Skip to content

Commit 34fbf55

Browse files
author
goldy
authored
Add support for git sparse checkout
Added a new, optional external property, sparse. sparse points to a file (relative to external repository local directory) with git sparse checkout patterns (e.g., directory names to include). If the sparse keyword is included, enable sparse checkout for that repository and use git read-tree to perform the sparse checkout. Added a new test for sparse checkout. The test is a repo with two externals which are both tag2 of the simple_ext repo with one of them configured for a sparse checkout. The test makes sure that both externals have the correct files. Updated the documentation for the externals configuration file. User interface changes?: Yes New sparse keyword is optional with a blank default value which preserves current functionality. Fixes: #120 Testing: test removed: None unit tests: All passed system tests: All passed, including new test for sparse feature manual testing: Several manual tests of NASA test cases.
2 parents a48558d + 6c6ef9f commit 34fbf55

16 files changed

+181
-11
lines changed

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ The root of the source tree will be referred to as `${SRC_ROOT}` below.
8585
description file:
8686

8787
$ cd ${SRC_ROOT}
88-
$ ./manage_externals/checkout_externals --excernals my-externals.cfg
88+
$ ./manage_externals/checkout_externals --externals my-externals.cfg
8989

9090
* Status summary of the repositories managed by checkout_externals:
9191

@@ -202,6 +202,21 @@ The root of the source tree will be referred to as `${SRC_ROOT}` below.
202202
Then the main 'externals' field in the top level repo should point to
203203
'sub-externals.cfg'.
204204

205+
* from_submodule (True / False) : used to pull the repo_url, local_path,
206+
and hash properties for this external from the .gitmodules file in
207+
this repository. Note that the section name (the entry in square
208+
brackets) must match the name in the .gitmodules file.
209+
If from_submodule is True, the protocol must be git and no repo_url,
210+
local_path, hash, branch, or tag entries are allowed.
211+
Default: False
212+
213+
* sparse (string) : used to control a sparse checkout. This optional
214+
entry should point to a filename (path relative to local_path) that
215+
contains instructions on which repository paths to include (or
216+
exclude) from the working tree.
217+
See the "SPARSE CHECKOUT" section of https://git-scm.com/docs/git-read-tree
218+
Default: sparse checkout is disabled
219+
205220
* Lines begining with '#' or ';' are comments and will be ignored.
206221

207222
# Obtaining this tool, reporting issues, etc.

manic/checkout.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,21 @@ def commandline_arguments(args=None):
227227
Now, %(prog)s will process Externals.cfg and also process
228228
Externals_LIBX.cfg as if it was a sub-external.
229229
230+
* from_submodule (True / False) : used to pull the repo_url, local_path,
231+
and hash properties for this external from the .gitmodules file in
232+
this repository. Note that the section name (the entry in square
233+
brackets) must match the name in the .gitmodules file.
234+
If from_submodule is True, the protocol must be git and no repo_url,
235+
local_path, hash, branch, or tag entries are allowed.
236+
Default: False
237+
238+
* sparse (string) : used to control a sparse checkout. This optional
239+
entry should point to a filename (path relative to local_path) that
240+
contains instructions on which repository paths to include (or
241+
exclude) from the working tree.
242+
See the "SPARSE CHECKOUT" section of https://git-scm.com/docs/git-read-tree
243+
Default: sparse checkout is disabled
244+
230245
* Lines beginning with '#' or ';' are comments and will be ignored.
231246
232247
# Obtaining this tool, reporting issues, etc.

manic/externals_description.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ class ExternalsDescription(dict):
351351
REPO_URL = 'repo_url'
352352
REQUIRED = 'required'
353353
TAG = 'tag'
354+
SPARSE = 'sparse'
354355

355356
PROTOCOL_EXTERNALS_ONLY = 'externals_only'
356357
PROTOCOL_GIT = 'git'
@@ -374,6 +375,7 @@ class ExternalsDescription(dict):
374375
TAG: 'string',
375376
BRANCH: 'string',
376377
HASH: 'string',
378+
SPARSE: 'string',
377379
}
378380
}
379381

@@ -562,6 +564,8 @@ def _check_optional(self):
562564
self[field][self.REPO][self.HASH] = EMPTY_STR
563565
if self.REPO_URL not in self[field][self.REPO]:
564566
self[field][self.REPO][self.REPO_URL] = EMPTY_STR
567+
if self.SPARSE not in self[field][self.REPO]:
568+
self[field][self.REPO][self.SPARSE] = EMPTY_STR
565569

566570
# from_submodule has a complex relationship with other fields
567571
if self.SUBMODULE in self[field]:

manic/repository.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def __init__(self, component_name, repo):
2121
self._branch = repo[ExternalsDescription.BRANCH]
2222
self._hash = repo[ExternalsDescription.HASH]
2323
self._url = repo[ExternalsDescription.REPO_URL]
24+
self._sparse = repo[ExternalsDescription.SPARSE]
2425

2526
if self._url is EMPTY_STR:
2627
fatal_error('repo must have a URL')

manic/repository_git.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,11 @@ def _checkout_ref(self, repo_dir, verbosity, submodules):
316316
else:
317317
self._checkout_external_ref(verbosity, submodules)
318318

319+
if self._sparse:
320+
self._sparse_checkout(repo_dir, verbosity)
319321
os.chdir(cwd)
320322

323+
321324
def _checkout_local_ref(self, verbosity, submodules):
322325
"""Checkout the reference considering the local repo only. Do not
323326
fetch any additional remotes or specify the remote when
@@ -362,6 +365,20 @@ def _checkout_external_ref(self, verbosity, submodules):
362365
ref = '{0}/{1}'.format(remote_name, ref)
363366
self._git_checkout_ref(ref, verbosity, submodules)
364367

368+
def _sparse_checkout(self, repo_dir, verbosity):
369+
"""Use git read-tree to thin the working tree."""
370+
cwd = os.getcwd()
371+
372+
cmd = ['cp', self._sparse, os.path.join(repo_dir,
373+
'.git/info/sparse-checkout')]
374+
if verbosity >= VERBOSITY_VERBOSE:
375+
printlog(' {0}'.format(' '.join(cmd)))
376+
execute_subprocess(cmd)
377+
os.chdir(repo_dir)
378+
self._git_sparse_checkout(verbosity)
379+
380+
os.chdir(cwd)
381+
365382
def _check_for_valid_ref(self, ref, remote_name=None):
366383
"""Try some basic sanity checks on the user supplied reference so we
367384
can provide a more useful error message than calledprocess
@@ -776,6 +793,18 @@ def _git_checkout_ref(ref, verbosity, submodules):
776793
if submodules:
777794
GitRepository._git_update_submodules(verbosity)
778795

796+
@staticmethod
797+
def _git_sparse_checkout(verbosity):
798+
"""Configure repo via read-tree."""
799+
cmd = ['git', 'config', 'core.sparsecheckout', 'true']
800+
if verbosity >= VERBOSITY_VERBOSE:
801+
printlog(' {0}'.format(' '.join(cmd)))
802+
execute_subprocess(cmd)
803+
cmd = ['git', 'read-tree', '-mu', 'HEAD']
804+
if verbosity >= VERBOSITY_VERBOSE:
805+
printlog(' {0}'.format(' '.join(cmd)))
806+
execute_subprocess(cmd)
807+
779808
@staticmethod
780809
def _git_update_submodules(verbosity):
781810
"""Run git submodule update for the side effect of updating this

manic/sourcetree.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def __init__(self, root_dir, name, ext_description, svn_ignore_ancestry):
4545
self._externals = EMPTY_STR
4646
self._externals_sourcetree = None
4747
self._stat = ExternalStatus()
48+
self._sparse = None
4849
# Parse the sub-elements
4950

5051
# _path : local path relative to the containing source tree
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)