Skip to content

Commit

Permalink
Merge pull request #83 from jedwards4b/jedwards/components_arg
Browse files Browse the repository at this point in the history
add a components arg to checkout only select components

Add optional argument to only process components listed on the command line
checkout_externals cam clm
will only process externals associated with the listed components cam and clm.
Also added a test of the new functionality.

User interface changes?: Yes
An additional command line option was added, previous functionality continues to be supported

Fixes: #80

Testing:
test removed:
unit tests: all pass
system tests:
manual testing: Tested with lists of components in Externals.cfg and with ones that were not there.
  • Loading branch information
billsacks authored Apr 10, 2018
2 parents 6923119 + 3f4c88f commit b2f3ae8
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 12 deletions.
18 changes: 15 additions & 3 deletions manic/checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from manic.externals_description import read_externals_description_file
from manic.externals_status import check_safe_to_update_repos
from manic.sourcetree import SourceTree
from manic.utils import printlog
from manic.utils import printlog, fatal_error
from manic.global_constants import VERSION_SEPERATOR, LOG_FILE_NAME

if sys.hexversion < 0x02070000:
Expand Down Expand Up @@ -243,6 +243,10 @@ def commandline_arguments(args=None):
#
# user options
#
parser.add_argument("components", nargs="*",
help="Specific component(s) to checkout. By default"
"all required externals are checked out.")

parser.add_argument('-e', '--externals', nargs='?',
default='Externals.cfg',
help='The externals description filename. '
Expand Down Expand Up @@ -316,7 +320,12 @@ def main(args):

root_dir = os.path.abspath(os.getcwd())
external_data = read_externals_description_file(root_dir, args.externals)
external = create_externals_description(external_data)
external = create_externals_description(external_data, components=args.components)

for comp in args.components:
if comp not in external.keys():
fatal_error("No component {} found in {}".format(comp, args.externals))


source_tree = SourceTree(root_dir, external)
printlog('Checking status of externals: ', end='')
Expand Down Expand Up @@ -354,7 +363,10 @@ def main(args):
printlog(msg)
printlog('-' * 70)
else:
source_tree.checkout(args.verbose, load_all)
if not args.components:
source_tree.checkout(args.verbose, load_all)
for comp in args.components:
source_tree.checkout(args.verbose, load_all, load_comp=comp)
printlog('')

logging.info('%s completed without exceptions.', program_name)
Expand Down
23 changes: 15 additions & 8 deletions manic/externals_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,16 @@ def read_externals_description_file(root_dir, file_name):
return externals_description


def create_externals_description(model_data, model_format='cfg'):
def create_externals_description(model_data, model_format='cfg', components=None):
"""Create the a externals description object from the provided data
"""
externals_description = None
if model_format == 'dict':
externals_description = ExternalsDescriptionDict(model_data, )
externals_description = ExternalsDescriptionDict(model_data, components=components)
elif model_format == 'cfg':
major, _, _ = get_cfg_schema_version(model_data)
if major == 1:
externals_description = ExternalsDescriptionConfigV1(model_data)
externals_description = ExternalsDescriptionConfigV1(model_data, components=components)
else:
msg = ('Externals description file has unsupported schema '
'version "{0}".'.format(major))
Expand Down Expand Up @@ -419,7 +419,7 @@ class ExternalsDescriptionDict(ExternalsDescription):
"""

def __init__(self, model_data):
def __init__(self, model_data, components=None):
"""Parse a native dictionary into a externals description.
"""
ExternalsDescription.__init__(self)
Expand All @@ -430,6 +430,11 @@ def __init__(self, model_data):
self._input_minor = 0
self._input_patch = 0
self._verify_schema_version()
if components:
for k in model_data.items():
if k not in components:
del model_data[k]

self.update(model_data)
self._check_user_input()

Expand All @@ -440,8 +445,8 @@ class ExternalsDescriptionConfigV1(ExternalsDescription):
"""

def __init__(self, model_data):
"""Convert the xml into a standardized dict that can be used to
def __init__(self, model_data, components=None):
"""Convert the config data into a standardized dict that can be used to
construct the source objects
"""
Expand All @@ -453,7 +458,7 @@ def __init__(self, model_data):
get_cfg_schema_version(model_data)
self._verify_schema_version()
self._remove_metadata(model_data)
self._parse_cfg(model_data)
self._parse_cfg(model_data, components=components)
self._check_user_input()

@staticmethod
Expand All @@ -465,7 +470,7 @@ def _remove_metadata(model_data):
"""
model_data.remove_section(DESCRIPTION_SECTION)

def _parse_cfg(self, cfg_data):
def _parse_cfg(self, cfg_data, components=None):
"""Parse a config_parser object into a externals description.
"""
def list_to_dict(input_list, convert_to_lower_case=True):
Expand All @@ -482,6 +487,8 @@ def list_to_dict(input_list, convert_to_lower_case=True):

for section in cfg_data.sections():
name = config_string_cleaner(section.lower().strip())
if components and name not in components:
continue
self[name] = {}
self[name].update(list_to_dict(cfg_data.items(section)))
self[name][self.REPO] = {}
Expand Down
2 changes: 1 addition & 1 deletion manic/sourcetree.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

class _External(object):
"""
_External represents an external object in side a SourceTree
_External represents an external object inside a SourceTree
"""

# pylint: disable=R0902
Expand Down
44 changes: 44 additions & 0 deletions test/test_sys_checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,18 @@ def _check_container_full_pre_checkout(self, overall, tree):
self._check_simple_opt_empty(tree)
self._check_mixed_ext_branch_required_pre_checkout(overall, tree)

def _check_container_component_post_checkout(self, overall, tree):
self.assertEqual(overall, 0)
self._check_simple_opt_ok(tree)
self._check_simple_tag_empty(tree)
self._check_simple_branch_empty(tree)

def _check_container_component_post_checkout2(self, overall, tree):
self.assertEqual(overall, 0)
self._check_simple_opt_ok(tree)
self._check_simple_tag_empty(tree)
self._check_simple_branch_ok(tree)

def _check_container_full_post_checkout(self, overall, tree):
self.assertEqual(overall, 0)
self._check_simple_tag_ok(tree)
Expand Down Expand Up @@ -1219,6 +1231,38 @@ def test_container_full(self):
self.status_args)
self._check_container_full_post_checkout(overall, tree)

def test_container_component(self):
"""Verify that optional component checkout works
"""
# create the test repository
under_test_dir = self.setup_test_repo(CONTAINER_REPO_NAME)

# create the top level externals file
self._generator.container_full(under_test_dir)

# inital checkout, first try a nonexistant component argument noref
checkout_args = ['simp_opt', 'noref']
checkout_args.extend(self.checkout_args)

with self.assertRaises(RuntimeError):
self.execute_cmd_in_dir(under_test_dir, checkout_args)

checkout_args = ['simp_opt']
checkout_args.extend(self.checkout_args)

overall, tree = self.execute_cmd_in_dir(under_test_dir,
checkout_args)

overall, tree = self.execute_cmd_in_dir(under_test_dir,
self.status_args)
self._check_container_component_post_checkout(overall, tree)
checkout_args.append('simp_branch')
overall, tree = self.execute_cmd_in_dir(under_test_dir,
checkout_args)
overall, tree = self.execute_cmd_in_dir(under_test_dir,
self.status_args)
self._check_container_component_post_checkout2(overall, tree)

def test_mixed_simple(self):
"""Verify that a mixed use repo can serve as a 'full' container,
pulling in a set of externals and a seperate set of sub-externals.
Expand Down

0 comments on commit b2f3ae8

Please sign in to comment.