コード例 #1
0
    def prepare_install(self,
                        backup_path=None,
                        arg_mode='abort',
                        robust=False):
        preparation_report = PreparationReport(self)
        present = self.detect_presence()
        if present or self.path_exists():
            # Directory exists see what we need to do
            error_message = None

            if not present:
                error_message = "Failed to detect %s presence at %s." % (
                    self.get_vcs_type_name(), self.path)
            else:
                cur_url = self._get_vcsc().get_url()
                if cur_url is not None:
                    # strip trailing slashes for #3269
                    cur_url = cur_url.rstrip('/')
                if not cur_url or cur_url != self.uri.rstrip('/'):
                    # local repositories get absolute pathnames
                    if not (os.path.isdir(self.uri) and os.path.isdir(cur_url)
                            and samefile(cur_url, self.uri)):
                        if not self._get_vcsc().url_matches(cur_url, self.uri):
                            error_message = "Url %s does not match %s requested." % (
                                cur_url, self.uri)
            if error_message is None:
                # update should be possible
                preparation_report.checkout = False
            else:
                # If robust ala continue-on-error, just error now and
                # it will be continued at a higher level
                if robust:
                    raise MultiProjectException("Update Failed of %s: %s" %
                                                (self.path, error_message))
                # prompt the user based on the error code
                if arg_mode == 'prompt':
                    print("Prepare updating %s (version %s) to %s" %
                          (self.uri, self.version, self.path))
                    mode = Ui.get_ui().prompt_del_abort_retry(error_message,
                                                              allow_skip=True)
                else:
                    mode = arg_mode
                if mode == 'backup':
                    preparation_report.backup = True
                    if backup_path is None:
                        print("Prepare updating %s (version %s) to %s" %
                              (self.uri, self.version, self.path))
                        preparation_report.backup_path = Ui.get_ui(
                        ).get_backup_path()
                    else:
                        preparation_report.backup_path = backup_path
                if mode == 'abort':
                    preparation_report.abort = True
                    preparation_report.error = error_message
                if mode == 'skip':
                    preparation_report.skip = True
                    preparation_report.error = error_message
                if mode == 'delete':
                    preparation_report.backup = False
        return preparation_report
コード例 #2
0
ファイル: cli_common.py プロジェクト: eacousineau/rosinstall
def get_workspace(argv, shell_path, config_filename=None, varname=None):
    """
    If target option -t is given return value of that one. Else, if varname
    is given and exists, considers that one, plus,
    if config_filename is given, searches for a file named in config_filename
    in 'shell_path' and ancestors.
    In that case, if two solutions are found, asks the user.

    :param shell_path: where to look for relevant config_filename
    :param config_filename: optional, filename for files defining workspaces
    :param varname: optional, env var to be used as workspace folder
    :returns: abspath if a .rosinstall was found, error and exist else.
    """
    parser = OptionParser()
    parser.add_option(
        "-t", "--target-workspace",
        dest="workspace", default=None,
        help="which workspace to use",
        action="store")
    # suppress errors based on any other options this parser is agnostic about
    argv2 = [x for x in argv if ((not x.startswith('-')) or
                                 x.startswith('--target-workspace=') or
                                 x.startswith('-t') or
                                 x == '--target-workspace')]
    (options, _) = parser.parse_args(argv2)
    if options.workspace is not None:
        if (config_filename is not None and
            not os.path.isfile(os.path.join(options.workspace, config_filename))):

            raise MultiProjectException("%s has no workspace configuration file '%s'" % (os.path.abspath(options.workspace), config_filename))
        return os.path.abspath(options.workspace)

    varname_path = None
    if varname is not None and varname in os.environ:
        # workspace could be relative, maybe confusing,
        # but that's the users fault
        varname_path = os.environ[varname]
        if varname_path.strip() == '' or not os.path.isdir(varname_path):
            varname_path = None

    # use current dir
    current_path = None
    if config_filename is not None:
        while shell_path is not None and not shell_path == os.path.dirname(shell_path):
            if os.path.exists(os.path.join(shell_path, config_filename)):
                current_path = shell_path
                break
            shell_path = os.path.dirname(shell_path)

    if current_path is not None and varname_path is not None and not samefile(current_path, varname_path):
        raise MultiProjectException("Ambiguous workspace: %s=%s, %s" % (varname, varname_path, os.path.abspath(config_filename)))

    if current_path is None and varname_path is None:
        raise MultiProjectException("Command requires a target workspace.")

    if current_path is not None:
        return current_path
    else:
        return varname_path
コード例 #3
0
ファイル: config_elements.py プロジェクト: bteeter/rosinstall
    def prepare_install(self, backup_path=None, arg_mode='abort', robust=False):
        preparation_report = PreparationReport(self)
        present = self.detect_presence()
        if present or self.path_exists():
            # Directory exists see what we need to do
            error_message = None

            if not present:
                error_message = "Failed to detect %s presence at %s." % (
                    self.get_vcs_type_name(), self.path)
            else:
                cur_url = self._get_vcsc().get_url()
                if cur_url is not None:
                    # strip trailing slashes for #3269
                    cur_url = cur_url.rstrip('/')
                if not cur_url or cur_url != self.uri.rstrip('/'):
                    # local repositories get absolute pathnames
                    if not (os.path.isdir(self.uri) and
                            os.path.isdir(cur_url) and
                            samefile(cur_url, self.uri)):
                        if not self._get_vcsc().url_matches(cur_url, self.uri):
                            error_message = "Url %s does not match %s requested." % (
                                cur_url, self.uri)
            if error_message is None:
                # update should be possible
                preparation_report.checkout = False
            else:
                # If robust ala continue-on-error, just error now and
                # it will be continued at a higher level
                if robust:
                    raise MultiProjectException("Update Failed of %s: %s" % (
                            self.path, error_message))
                # prompt the user based on the error code
                if arg_mode == 'prompt':
                    print("Prepare updating %s (version %s) to %s" % (
                            self.uri, self.version, self.path))
                    mode = Ui.get_ui().prompt_del_abort_retry(error_message,
                                                              allow_skip=True)
                else:
                    mode = arg_mode
                if mode == 'backup':
                    preparation_report.backup = True
                    if backup_path is None:
                        print("Prepare updating %s (version %s) to %s" % (
                                self.uri, self.version, self.path))
                        preparation_report.backup_path = Ui.get_ui().get_backup_path()
                    else:
                        preparation_report.backup_path = backup_path
                if mode == 'abort':
                    preparation_report.abort = True
                    preparation_report.error = error_message
                if mode == 'skip':
                    preparation_report.skip = True
                    preparation_report.error = error_message
                if mode == 'delete':
                    preparation_report.backup = False
        return preparation_report
コード例 #4
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
コード例 #5
0
ファイル: cli_common.py プロジェクト: jamuraa/rosinstall
def get_workspace(argv, shell_path, config_filename=None, varname=None):
    """
    If target option -t is given return value of that one. Else, if varname
    is given and exists, considers that one, plus,
    if config_filename is given, searches for a file named in config_filename
    in 'shell_path' and ancestors.
    In that case, if two solutions are found, asks the user.

    :param shell_path: where to look for relevant config_filename
    :param config_filename: optional, filename for files defining workspaces
    :param varname: optional,
    :returns: abspath if a .rosinstall was found, error and exist else.
    """
    parser = OptionParser()
    parser.add_option("-t",
                      "--target-workspace",
                      dest="workspace",
                      default=None,
                      help="which workspace to use",
                      action="store")
    # suppress errors based on any other options this parser is agnostic about
    argv2 = [
        x for x in argv
        if ((not x.startswith('-')) or x.startswith('--target-workspace=')
            or x.startswith('-t') or x == '--target-workspace')
    ]
    (options, args) = parser.parse_args(argv2)
    if options.workspace is not None:
        if (config_filename is not None and not os.path.isfile(
                os.path.join(options.workspace, config_filename))):

            raise MultiProjectException(
                "%s has no workspace configuration file '%s'" %
                (os.path.abspath(options.workspace), config_filename))
        return os.path.abspath(options.workspace)

    varname_path = None
    if varname is not None and varname in os.environ:
        # workspace could be relative, maybe confusing, but that's the users fault
        varname_path = os.environ[varname]
        if varname_path.strip() == '' or not os.path.isdir(varname_path):
            varname_path = None

    # use current dir
    current_path = None
    if config_filename is not None:
        while shell_path is not None and not shell_path == os.path.dirname(
                shell_path):
            if os.path.exists(os.path.join(shell_path, config_filename)):
                current_path = shell_path
                break
            shell_path = os.path.dirname(shell_path)

    if current_path is not None and varname_path is not None and not samefile(
            current_path, varname_path):
        raise MultiProjectException(
            "Ambiguous workspace: %s=%s, %s" %
            (varname, varname_path, os.path.abspath(config_filename)))

    if current_path is None and varname_path is None:
        raise MultiProjectException("Command requires a target workspace.")

    if current_path is not None:
        return current_path
    else:
        return varname_path
コード例 #6
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