def _insert_vcs_path_spec(self, path_spec, local_path, merge_strategy='KillAppend'): # Get the version and source_uri elements source_uri = normalize_uri(path_spec.get_uri(), self.get_base_path()) version = path_spec.get_version() try: local_name = os.path.normpath(path_spec.get_local_name()) elem = self._create_vcs_config_element(path_spec.get_scmtype(), local_path, local_name, source_uri, version, properties=path_spec.get_tags()) return self.insert_element(elem, merge_strategy) except LookupError as ex: raise MultiProjectException("Abstracted VCS Config failed. Exception: %s" % ex)
def test_normalize_uri(self): self.assertEqual('/foo', normalize_uri('/foo', None)) self.assertEqual(None, normalize_uri(None, None)) self.assertEqual('/bar/foo', normalize_uri('foo', '/bar')) self.assertEqual('http://foo.com', normalize_uri('http://foo.com', None))
def cmd_set(self, target_path, argv, config=None): """ command for modifying/adding a single entry :param target_path: where to look for config :param config: config to use instead of parsing file anew """ usage = ("usage: %s set [localname] [SCM-URI]? [--(%ssvn|hg|git|bzr)] [--version=VERSION]]" % (self.progname, 'detached|' if self.allow_other_element else '')) parser = OptionParser( usage=usage, formatter=IndentedHelpFormatterWithNL(), description=__MULTIPRO_CMD_DICT__["set"] + """ The command will infer whether you want to add or modify an entry. If you modify, it will only change the details you provide, keeping those you did not provide. if you only provide a uri, will use the basename of it as localname unless such an element already exists. The command only changes the configuration, to checkout or update the element, run %(progname)s update afterwards. Examples: $ %(progname)s set robot_model --hg https://kforge.ros.org/robotmodel/robot_model $ %(progname)s set robot_model --version-new robot_model-1.7.1 %(detached)s """ % { 'progname': self.progname, 'detached': '$ %s set robot_model --detached' % self.progname if self.allow_other_element else ''}, epilog="See: http://www.ros.org/wiki/rosinstall for details\n") if self.allow_other_element: parser.add_option("--detached", dest="detach", default=False, help="make an entry unmanaged (default for new element)", action="store_true") parser.add_option("-v", "--version-new", dest="version", default=None, help="point SCM to this version", action="store") parser.add_option("--git", dest="git", default=False, help="make an entry a git entry", action="store_true") parser.add_option("--svn", dest="svn", default=False, help="make an entry a subversion entry", action="store_true") parser.add_option("--hg", dest="hg", default=False, help="make an entry a mercurial entry", action="store_true") parser.add_option("--bzr", dest="bzr", default=False, help="make an entry a bazaar entry", action="store_true") parser.add_option("-y", "--confirm", dest="confirm", default='', help="Do not ask for confirmation", action="store_true") # -t option required here for help but used one layer above, see cli_common parser.add_option( "-t", "--target-workspace", dest="workspace", default=None, help="which workspace to use", action="store") (options, args) = parser.parse_args(argv) if not self.allow_other_element: options.detach = False if len(args) > 2: print("Error: Too many arguments.") print(parser.usage) return -1 if config is None: config = multiproject_cmd.get_config( target_path, additional_uris=[], config_filename=self.config_filename) elif config.get_base_path() != target_path: raise MultiProjectException( "Config path does not match %s %s " % (config.get_base_path(), target_path)) scmtype = None count_scms = 0 if options.git: scmtype = 'git' count_scms += 1 if options.svn: scmtype = 'svn' count_scms += 1 if options.hg: scmtype = 'hg' count_scms += 1 if options.bzr: scmtype = 'bzr' count_scms += 1 if options.detach: count_scms += 1 if count_scms > 1: parser.error( "You cannot provide more than one scm provider option") if len(args) == 0: parser.error("Must provide a localname") element = select_element(config.get_config_elements(), args[0]) uri = None if len(args) == 2: uri = args[1] version = None if options.version is not None: version = options.version.strip("'\"") # create spec object if element is None: if scmtype is None and not self.allow_other_element: # for modification, not re-stating the scm type is # okay, for new elements not parser.error("You have to provide one scm provider option") # asssume is insert, choose localname localname = os.path.normpath(args[0]) rel_path = os.path.relpath(os.path.realpath(localname), os.path.realpath(config.get_base_path())) if os.path.isabs(localname): # use shorter localname for folders inside workspace if not rel_path.startswith('..'): localname = rel_path else: # got a relative path as localname, could point to a dir or be # meant relative to workspace if not samefile(os.getcwd(), config.get_base_path()): if os.path.isdir(localname): parser.error( "Cannot decide which one you want to add:\n%s\n%s" % ( os.path.abspath(localname), os.path.join(config.get_base_path(), localname))) if not rel_path.startswith('..'): localname = rel_path spec = PathSpec(local_name=localname, uri=normalize_uri(uri, config.get_base_path()), version=version, scmtype=scmtype) else: # modify old_spec = element.get_path_spec() if options.detach: spec = PathSpec(local_name=element.get_local_name()) else: # '' evals to False, we do not want that if version is None: version = old_spec.get_version() spec = PathSpec(local_name=element.get_local_name(), uri=normalize_uri(uri or old_spec.get_uri(), config.get_base_path()), version=version, scmtype=scmtype or old_spec.get_scmtype(), path=old_spec.get_path()) if spec.get_legacy_yaml() == old_spec.get_legacy_yaml(): if not options.detach and spec.get_scmtype() is not None: parser.error( "Element %s already exists, did you mean --detached ?" % spec) parser.error("Element %s already exists" % spec) (newconfig, path_changed) = prompt_merge( target_path, additional_uris=[], additional_specs=[spec], merge_strategy='MergeReplace', confirmed=options.confirm, confirm=not options.confirm, show_verbosity=False, show_advanced=False, config_filename=self.config_filename, config=config, allow_other_element=self.allow_other_element) if newconfig is not None: print("Overwriting %s" % os.path.join( newconfig.get_base_path(), self.config_filename)) shutil.move( os.path.join(newconfig.get_base_path(), self.config_filename), "%s.bak" % os.path.join(newconfig.get_base_path(), self.config_filename)) self.config_generator(newconfig, self.config_filename) if path_changed: print("\nDo not forget to do ...\n$ source %s/setup.sh\n... in every open terminal." % target_path) if (spec.get_scmtype() is not None): print("Config changed, remember to run '%s update %s' to update the folder from %s" % (self.progname, spec.get_local_name(), spec.get_scmtype())) else: print("New element %s could not be added, " % spec) return 1 # auto-install not a good feature, maybe make an option # for element in config.get_config_elements(): # if element.get_local_name() == spec.get_local_name(): # if element.is_vcs_element(): # element.install(checkout=not os.path.exists(os.path.join(config.get_base_path(), spec.get_local_name()))) # break return 0
def cmd_set(self, target_path, argv, config=None): """ command for modifying/adding a single entry :param target_path: where to look for config :param config: config to use instead of parsing file anew """ usage = ( "usage: %s set [localname] [SCM-URI]? [--(%ssvn|hg|git|bzr)] [--version=VERSION]]" % (self.progname, 'detached|' if self.allow_other_element else '')) parser = OptionParser( usage=usage, formatter=IndentedHelpFormatterWithNL(), description=__MULTIPRO_CMD_DICT__["set"] + """ The command will infer whether you want to add or modify an entry. If you modify, it will only change the details you provide, keeping those you did not provide. if you only provide a uri, will use the basename of it as localname unless such an element already exists. The command only changes the configuration, to checkout or update the element, run %(progname)s update afterwards. Examples: $ %(progname)s set robot_model --hg https://kforge.ros.org/robotmodel/robot_model $ %(progname)s set robot_model --version-new robot_model-1.7.1 %(detached)s """ % { 'progname': self.progname, 'detached': '$ %s set robot_model --detached' % self.progname if self.allow_other_element else '' }, epilog="See: http://www.ros.org/wiki/rosinstall for details\n") if self.allow_other_element: parser.add_option( "--detached", dest="detach", default=False, help="make an entry unmanaged (default for new element)", action="store_true") parser.add_option("-v", "--version-new", dest="version", default=None, help="point SCM to this version", action="store") parser.add_option("--git", dest="git", default=False, help="make an entry a git entry", action="store_true") parser.add_option("--svn", dest="svn", default=False, help="make an entry a subversion entry", action="store_true") parser.add_option("--hg", dest="hg", default=False, help="make an entry a mercurial entry", action="store_true") parser.add_option("--bzr", dest="bzr", default=False, help="make an entry a bazaar entry", action="store_true") parser.add_option("-y", "--confirm", dest="confirm", default='', help="Do not ask for confirmation", action="store_true") # -t option required here for help but used one layer above, see cli_common parser.add_option("-t", "--target-workspace", dest="workspace", default=None, help="which workspace to use", action="store") (options, args) = parser.parse_args(argv) if not self.allow_other_element: options.detach = False if len(args) > 2: print("Error: Too many arguments.") print(parser.usage) return -1 if config is None: config = multiproject_cmd.get_config( target_path, additional_uris=[], config_filename=self.config_filename) elif config.get_base_path() != target_path: raise MultiProjectException("Config path does not match %s %s " % (config.get_base_path(), target_path)) scmtype = None count_scms = 0 if options.git: scmtype = 'git' count_scms += 1 if options.svn: scmtype = 'svn' count_scms += 1 if options.hg: scmtype = 'hg' count_scms += 1 if options.bzr: scmtype = 'bzr' count_scms += 1 if options.detach: count_scms += 1 if count_scms > 1: parser.error( "You cannot provide more than one scm provider option") if len(args) == 0: parser.error("Must provide a localname") element = select_element(config.get_config_elements(), args[0]) uri = None if len(args) == 2: uri = args[1] version = None if options.version is not None: version = options.version.strip("'\"") # create spec object if element is None: if scmtype is None and not self.allow_other_element: # for modification, not re-stating the scm type is # okay, for new elements not parser.error("You have to provide one scm provider option") # asssume is insert, choose localname localname = os.path.normpath(args[0]) rel_path = os.path.relpath( os.path.realpath(localname), os.path.realpath(config.get_base_path())) if os.path.isabs(localname): # use shorter localname for folders inside workspace if not rel_path.startswith('..'): localname = rel_path else: # got a relative path as localname, could point to a dir or be # meant relative to workspace if not samefile(os.getcwd(), config.get_base_path()): if os.path.isdir(localname): parser.error( "Cannot decide which one you want to add:\n%s\n%s" % (os.path.abspath(localname), os.path.join(config.get_base_path(), localname))) if not rel_path.startswith('..'): localname = rel_path spec = PathSpec(local_name=localname, uri=normalize_uri(uri, config.get_base_path()), version=version, scmtype=scmtype) else: # modify old_spec = element.get_path_spec() if options.detach: spec = PathSpec(local_name=element.get_local_name()) else: # '' evals to False, we do not want that if version is None: version = old_spec.get_version() spec = PathSpec(local_name=element.get_local_name(), uri=normalize_uri(uri or old_spec.get_uri(), config.get_base_path()), version=version, scmtype=scmtype or old_spec.get_scmtype(), path=old_spec.get_path()) if spec.get_legacy_yaml() == old_spec.get_legacy_yaml(): if not options.detach and spec.get_scmtype() is not None: parser.error( "Element %s already exists, did you mean --detached ?" % spec) parser.error("Element %s already exists" % spec) (newconfig, path_changed) = prompt_merge( target_path, additional_uris=[], additional_specs=[spec], merge_strategy='MergeReplace', confirmed=options.confirm, confirm=not options.confirm, show_verbosity=False, show_advanced=False, config_filename=self.config_filename, config=config, allow_other_element=self.allow_other_element) if newconfig is not None: print( "Overwriting %s" % os.path.join(newconfig.get_base_path(), self.config_filename)) shutil.move( os.path.join(newconfig.get_base_path(), self.config_filename), "%s.bak" % os.path.join(newconfig.get_base_path(), self.config_filename)) self.config_generator(newconfig, self.config_filename) if path_changed: print( "\nDo not forget to do ...\n$ source %s/setup.sh\n... in every open terminal." % target_path) if (spec.get_scmtype() is not None): print( "Config changed, remember to run '%s update %s' to update the folder from %s" % (self.progname, spec.get_local_name(), spec.get_scmtype())) else: print("New element %s could not be added, " % spec) return 1 # auto-install not a good feature, maybe make an option # for element in config.get_config_elements(): # if element.get_local_name() == spec.get_local_name(): # if element.is_vcs_element(): # element.install(checkout=not os.path.exists(os.path.join(config.get_base_path(), spec.get_local_name()))) # break return 0