Exemplo n.º 1
0
    def cmd_status(self, target_path, argv, config=None):
        parser = OptionParser(
            usage="usage: %s status [localname]* " % self.progname,
            description=__MULTIPRO_CMD_DICT__["status"]
            + ". The status columns meanings are as the respective SCM defines them.",
            epilog="""See: http://www.ros.org/wiki/rosinstall for details""",
        )
        parser.add_option(
            "--untracked", dest="untracked", default=False, help="Also shows untracked files", 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 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))

        if len(args) > 0:
            statuslist = multiproject_cmd.cmd_status(config, localnames=args, untracked=options.untracked)
        else:
            statuslist = multiproject_cmd.cmd_status(config, untracked=options.untracked)
        allstatus = []
        for entrystatus in statuslist:
            if entrystatus["status"] is not None:
                allstatus.append(entrystatus["status"])
        print("".join(allstatus), end="")
        return 0
Exemplo n.º 2
0
    def cmd_diff(self, target_path, argv, config=None):
        parser = OptionParser(usage="usage: rosws diff [localname]* ",
                              description=__MULTIPRO_CMD_DICT__["diff"],
                              epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        # required here but used one layer above
        parser.add_option("-t", "--target-workspace", dest="workspace",
                          default=None,
                          help="which workspace to use",
                          action="store")
        (_, args) = parser.parse_args(argv)

        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))

        if len(args) > 0:
            difflist = multiproject_cmd.cmd_diff(config, localnames=args)
        else:
            difflist = multiproject_cmd.cmd_diff(config)
        alldiff = []
        for entrydiff in difflist:
            if entrydiff['diff'] is not None and entrydiff['diff'] != '':
                alldiff.append(entrydiff['diff'])
        print('\n'.join(alldiff))

        return False
Exemplo n.º 3
0
    def cmd_delete_stack(self, target_path, argv):
        parser = OptionParser(usage="usage: rosws delete-stack [PATH] localname",
                        epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("-N", "--non-recursive", dest="norecurse",
                          default=False,
                          help="don't change configuration for dependent stacks",
                          action="store_true")
        parser.add_option("-d", "--delete-working-copies", dest="delete",
                          default=False,
                          help="when deleting a stack from the configuration, also delete the working copy (DANGEROUS!)",
                          action="store_true")
        (options, args) = parser.parse_args(argv)

        if len(args) < 1:
            print("Error: Too few arguments.")
            print(parser.usage)
            return -1
        if len(args) > 1:
            print("Error: Too many arguments.")
            print(parser.usage)
            return -1
        uri = args[0]
        config = get_config(target_path, [], config_filename=self.config_filename)
        if cmd_delete_stack(config,
                            uri,
                            delete=options.delete,
                            recurse=(not options.norecurse)):
            cmd_persist_config(config, self.config_filename)
            return 0
        return 1
Exemplo n.º 4
0
    def cmd_diff(self, target_path, argv, config=None):
        parser = OptionParser(usage="usage: %s diff [localname]* " % self.progname,
                              description=__MULTIPRO_CMD_DICT__["diff"],
                              epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        # required here but used one layer above
        parser.add_option("-t", "--target-workspace", dest="workspace",
                          default=None,
                          help="which workspace to use",
                          action="store")
        (_, args) = parser.parse_args(argv)

        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))

        if len(args) > 0:
            difflist = multiproject_cmd.cmd_diff(config, localnames=args)
        else:
            difflist = multiproject_cmd.cmd_diff(config)
        alldiff = []
        for entrydiff in difflist:
            if entrydiff['diff'] is not None and entrydiff['diff'] != '':
                alldiff.append(entrydiff['diff'])
        print('\n'.join(alldiff))

        return False
Exemplo n.º 5
0
    def cmd_regenerate(self, target_path, argv, config=None):
        parser = OptionParser(
            usage="usage: %s regenerate" % self.progname,
            formatter=IndentedHelpFormatterWithNL(),
            description=__MULTIPRO_CMD_DICT__["remove"] + """

this command without options generates files setup.sh, setup.bash and
setup.zsh. Note that doing this is unnecessary in general, as these
files do not change anymore, unless you change from one ROS distro to
another (which you should never do like this, create a separate new
workspace instead), or you deleted or modified any of those files
accidentally.
""",
            epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("-c",
                          "--catkin",
                          dest="catkin",
                          default=False,
                          help="Declare this is a catkin build.",
                          action="store_true")
        parser.add_option("--cmake-prefix-path",
                          dest="catkinpp",
                          default=None,
                          help="Where to set the CMAKE_PREFIX_PATH",
                          action="store")
        # -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 len(args) > 0:
            print("Error: Too many arguments.")
            print(parser.usage)
            return -1

        if config is None:
            config = 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))
        rosinstall_cmd.cmd_generate_ros_files(config,
                                              target_path,
                                              nobuild=True,
                                              rosdep_yes=False,
                                              catkin=options.catkin,
                                              catkinpp=options.catkinpp,
                                              no_ros_allowed=True)
        return 0
Exemplo n.º 6
0
    def cmd_regenerate(self, target_path, argv, config=None):
        parser = OptionParser(usage="usage: %s regenerate" % self.progname,
                              formatter=IndentedHelpFormatterWithNL(),
                              description=__MULTIPRO_CMD_DICT__["remove"] + """

this command without options generates files setup.sh, setup.bash and
setup.zsh. Note that doing this is unnecessary in general, as these
files do not change anymore, unless you change from one ROS distro to
another (which you should never do like this, create a separate new
workspace instead), or you deleted or modified any of those files
accidentally.
""",
                              epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("-c", "--catkin", dest="catkin", default=False,
                          help="Declare this is a catkin build.",
                          action="store_true")
        parser.add_option("--cmake-prefix-path", dest="catkinpp", default=None,
                          help="Where to set the CMAKE_PREFIX_PATH",
                          action="store")
        # -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 len(args) > 0:
            print("Error: Too many arguments.")
            print(parser.usage)
            return -1

        if config is None:
            config = 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))
        rosinstall_cmd.cmd_generate_ros_files(config,
                                              target_path,
                                              nobuild=True,
                                              rosdep_yes=False,
                                              catkin=options.catkin,
                                              catkinpp=options.catkinpp,
                                              no_ros_allowed=True)
        return 0
Exemplo n.º 7
0
 def test_source(self):
     """checkout into temp dir and test setup files"""
     cmd = copy.copy(self.rosinstall_fn)
     url = "http://packages.ros.org/cgi-bin/gen_rosinstall.py?rosdistro=fuerte&variant=robot&overlay=no"
     self.simple_rosinstall = os.path.join(self.directory, "simple.rosinstall")
     response = urlopen(url)
     contents = response.read()
     with open(self.simple_rosinstall, 'wb') as fhand:
         fhand.write(contents)
     config = get_config(self.directory, [self.simple_rosinstall])
     cmd.extend(['-j8', '--catkin', self.directory, self.simple_rosinstall])
     self.assertTrue(rosinstall_main(cmd))
     generated_rosinstall_filename = os.path.join(self.directory, ".rosinstall")
     self.assertTrue(os.path.exists(generated_rosinstall_filename))
     # fuerte core ros stacks are catkinized, installed via catkin workspace
     self.assertTrue(os.path.exists(os.path.join(self.directory, "common")))
     self.assertTrue(os.path.exists(os.path.join(self.directory, "dynamic_reconfigure")))
     self.assertTrue(os.path.exists(os.path.join(self.directory, "CMakeLists.txt")))
Exemplo n.º 8
0
    def cmd_remove(self, target_path, argv, config=None):
        parser = OptionParser(
            usage="usage: %s remove [localname]*" % self.progname,
            formatter=IndentedHelpFormatterWithNL(),
            description=__MULTIPRO_CMD_DICT__["remove"] + """
The command removes entries from your configuration file, it does not affect your filesystem.
""",
            epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        (_, args) = parser.parse_args(argv)
        if len(args) < 1:
            print("Error: Too few 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))
        success = True
        elements = select_elements(config, args)
        for element in elements:
            if not config.remove_element(element.get_local_name()):
                success = False
                print(
                    "Bug: No such element %s in config, aborting without changes"
                    % (element.get_local_name()))
                break
        if success:
            print("Overwriting %s" %
                  os.path.join(config.get_base_path(), self.config_filename))
            shutil.move(
                os.path.join(config.get_base_path(),
                             self.config_filename), "%s.bak" %
                os.path.join(config.get_base_path(), self.config_filename))
            self.config_generator(config, self.config_filename)
            print("Removed entries %s" % args)

        return 0
Exemplo n.º 9
0
    def cmd_status(self, target_path, argv, config=None):
        parser = OptionParser(
            usage="usage: %s status [localname]* " % self.progname,
            description=__MULTIPRO_CMD_DICT__["status"] +
            ". The status columns meanings are as the respective SCM defines them.",
            epilog="""See: http://www.ros.org/wiki/rosinstall for details""")
        parser.add_option("--untracked",
                          dest="untracked",
                          default=False,
                          help="Also shows untracked files",
                          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 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))

        if len(args) > 0:
            statuslist = multiproject_cmd.cmd_status(
                config, localnames=args, untracked=options.untracked)
        else:
            statuslist = multiproject_cmd.cmd_status(
                config, untracked=options.untracked)
        allstatus = []
        for entrystatus in statuslist:
            if entrystatus['status'] is not None:
                allstatus.append(entrystatus['status'])
        print(''.join(allstatus), end='')
        return 0
Exemplo n.º 10
0
    def cmd_remove(self, target_path, argv, config=None):
        parser = OptionParser(usage="usage: %s remove [localname]*" % self.progname,
                              formatter=IndentedHelpFormatterWithNL(),
                              description=__MULTIPRO_CMD_DICT__["remove"] + """
The command removes entries from your configuration file, it does not affect your filesystem.
""",
                              epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        (_, args) = parser.parse_args(argv)
        if len(args) < 1:
            print("Error: Too few 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))
        success = True
        elements = select_elements(config, args)
        for element in elements:
            if not config.remove_element(element.get_local_name()):
                success = False
                print("Bug: No such element %s in config, aborting without changes" %
                      (element.get_local_name()))
                break
        if success:
            print("Overwriting %s" % os.path.join(config.get_base_path(),
                                                  self.config_filename))
            shutil.move(os.path.join(config.get_base_path(),
                                     self.config_filename),
                        "%s.bak" % os.path.join(config.get_base_path(),
                                                self.config_filename))
            self.config_generator(config, self.config_filename)
            print("Removed entries %s" % args)

        return 0
Exemplo n.º 11
0
 def test_source(self):
     """checkout into temp dir and test setup files"""
     cmd = copy.copy(self.rosinstall_fn)
     url = "http://packages.ros.org/cgi-bin/gen_rosinstall.py?rosdistro=fuerte&variant=robot&overlay=no"
     self.simple_rosinstall = os.path.join(self.directory,
                                           "simple.rosinstall")
     response = urlopen(url)
     contents = response.read()
     with open(self.simple_rosinstall, 'wb') as fhand:
         fhand.write(contents)
     config = get_config(self.directory, [self.simple_rosinstall])
     cmd.extend(['-j8', '--catkin', self.directory, self.simple_rosinstall])
     self.assertTrue(rosinstall_main(cmd))
     generated_rosinstall_filename = os.path.join(self.directory,
                                                  ".rosinstall")
     self.assertTrue(os.path.exists(generated_rosinstall_filename))
     # fuerte core ros stacks are catkinized, installed via catkin workspace
     self.assertTrue(os.path.exists(os.path.join(self.directory, "common")))
     self.assertTrue(
         os.path.exists(os.path.join(self.directory,
                                     "dynamic_reconfigure")))
     self.assertTrue(
         os.path.exists(os.path.join(self.directory, "CMakeLists.txt")))
Exemplo n.º 12
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
Exemplo n.º 13
0
    def cmd_update(self, target_path, argv, config=None):
        parser = OptionParser(usage="usage: %s update [localname]*" % self.progname,
                              formatter=IndentedHelpFormatterWithNL(),
                              description=__MULTIPRO_CMD_DICT__["update"] + """

This command calls the SCM provider to pull changes from remote to
your local filesystem. In case the url has changed, the command will
ask whether to delete or backup the folder.

Examples:
$ %(progname)s update -t ~/fuerte
$ %(progname)s update robot_model geometry
""" % {'progname': self.progname},
                              epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("--delete-changed-uris", dest="delete_changed",
                          default=False,
                          help="Delete the local copy of a directory before changing uri.",
                          action="store_true")
        parser.add_option("--abort-changed-uris", dest="abort_changed",
                          default=False,
                          help="Abort if changed uri detected",
                          action="store_true")
        parser.add_option("--continue-on-error", dest="robust",
                          default=False,
                          help="Continue despite checkout errors",
                          action="store_true")
        parser.add_option("--backup-changed-uris", dest="backup_changed",
                          default='',
                          help="backup the local copy of a directory before changing uri to this directory.",
                          action="store")
        parser.add_option("-j", "--parallel", dest="jobs",
                          default=1,
                          help="How many parallel threads to use for installing",
                          action="store")
        parser.add_option("-v", "--verbose", dest="verbose",
                          default=False,
                          help="Whether to print out more information",
                          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 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))
        success = True
        mode = _get_mode_from_options(parser, options)
        if args == []:
            # None means no filter, [] means filter all
            args = None
        if success:
            install_success = multiproject_cmd.cmd_install_or_update(
                config,
                localnames=args,
                backup_path=options.backup_changed,
                mode=mode,
                robust=options.robust,
                num_threads=int(options.jobs),
                verbose=options.verbose)
            if install_success or options.robust:
                return 0
        return 1
Exemplo n.º 14
0
    def cmd_init(self, argv):
        if self.config_filename is None:
            print('Error: Bug: config filename required for init')
            return 1
        parser = OptionParser(
            usage="""usage: %s init [TARGET_PATH [SOURCE_PATH]]?""" % self.progname,
            formatter=IndentedHelpFormatterWithNL(),
            description=__MULTIPRO_CMD_DICT__["init"] + """

%(prog)s init does the following:
  1. Reads folder/file/web-uri SOURCE_PATH looking for a rosinstall yaml
  2. Creates new %(cfg_file)s file at TARGET-PATH
  3. Generates ROS setup files

SOURCE_PATH can e.g. be a folder like /opt/ros/electric
If PATH is not given, uses current dir.

Examples:
$ %(prog)s init ~/fuerte /opt/ros/fuerte
""" % {'cfg_file': self.config_filename, 'prog': self.progname},
            epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("--continue-on-error", dest="robust", default=False,
                          help="Continue despite checkout errors",
                          action="store_true")
        parser.add_option("-j", "--parallel", dest="jobs", default=1,
                          help="How many parallel threads to use for installing",
                          action="store")
        (options, args) = parser.parse_args(argv)
        if len(args) < 1:
            target_path = '.'
        else:
            target_path = args[0]

        if not os.path.isdir(target_path):
            if not os.path.exists(target_path):
                os.mkdir(target_path)
            else:
                print('Error: Cannot create in target path %s ' % target_path)

        if os.path.exists(os.path.join(target_path, self.config_filename)):
            print('Error: There already is a workspace config file %s at "%s". Use %s install/modify.' %
                  (self.config_filename, target_path, self.progname))
            return 1
        if len(args) > 2:
            parser.error('Too many arguments')
        if len(args) == 2:
            print('Using initial elements from: %s' % args[1])
            config_uris = [args[1]]
        else:
            config_uris = []

        config = multiproject_cmd.get_config(
            basepath=target_path,
            additional_uris=config_uris,
            config_filename=(self.config_filename
                             if self.allow_other_element
                             else None))

        # includes ROS specific files

        print("Writing %s" % os.path.join(config.get_base_path(), self.config_filename))
        self.config_generator(
            config, self.config_filename, get_header(self.progname))

        ## install or update each element
        install_success = multiproject_cmd.cmd_install_or_update(
            config,
            robust=False,
            num_threads=int(options.jobs))

        if not install_success:
            print("Warning: installation encountered errors, but --continue-on-error was requested.  Look above for warnings.")
        print("\nupdate complete.")
        return 0
Exemplo n.º 15
0
    def cmd_info(self, target_path, argv, reverse=True, config=None):
        only_option_valid_attrs = [
            'path', 'localname', 'version', 'revision', 'cur_revision', 'uri',
            'cur_uri', 'scmtype'
        ]
        parser = OptionParser(
            usage="usage: %s info [localname]* [OPTIONS]" % _PROGNAME,
            formatter=IndentedHelpFormatterWithNL(),
            description=__MULTIPRO_CMD_DICT__["info"] + """

The Status (S) column shows
 x  for missing
 L  for uncommited (local) changes
 V  for difference in version and/or remote URI

The 'Version-Spec' column shows what tag, branch or revision was given
in the .rosinstall file. The 'UID' column shows the unique ID of the
current (and specified) version. The 'URI' column shows the configured
URL of the repo.

If status is V, the difference between what was specified and what is
real is shown in the respective column. For SVN entries, the url is
split up according to standard layout (trunk/tags/branches).  The
ROS_PACKAGE_PATH follows the order of the table, earlier entries
overlay later entries.

When given one localname, just show the data of one element in list form.
This also has the generic properties element which is usually empty.

The --only option accepts keywords: %(opts)s

Examples:
$ %(prog)s info -t ~/ros/fuerte
$ %(prog)s info robot_model
$ %(prog)s info --yaml
$ %(prog)s info --only=path,cur_uri,cur_revision robot_model geometry
""" % {
                'prog': _PROGNAME,
                'opts': only_option_valid_attrs
            },
            epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("--data-only",
                          dest="data_only",
                          default=False,
                          help="Does not provide explanations",
                          action="store_true")
        parser.add_option("--no-pkg-path",
                          dest="no_pkg_path",
                          default=False,
                          help="Suppress ROS_PACKAGE_PATH.",
                          action="store_true")
        parser.add_option(
            "--pkg-path-only",
            dest="pkg_path_only",
            default=False,
            help=
            "Shows only ROS_PACKAGE_PATH separated by ':'. Supercedes all other options.",
            action="store_true")
        parser.add_option(
            "--only",
            dest="only",
            default=False,
            help=
            "Shows comma-separated lists of only given comma-separated attribute(s).",
            action="store")
        parser.add_option(
            "--yaml",
            dest="yaml",
            default=False,
            help="Shows only version of single entry. Intended for scripting.",
            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 config is None:
            config = 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))
        if args == []:
            args = None
        # relevant for code completion, so these should yield quick response:
        if options.pkg_path_only:
            print(":".join(get_ros_package_path(config)))
            return 0
        elif options.only:
            only_options = options.only.split(",")
            if only_options == '':
                parser.error('No valid options given')

            lookup_required = False
            for attr in only_options:
                if not attr in only_option_valid_attrs:
                    parser.error("Invalid --only option '%s', valids are %s" %
                                 (attr, only_option_valid_attrs))
                if attr in ['cur_revision', 'cur_uri', 'revision']:
                    lookup_required = True
            elements = select_elements(config, args)
            for element in elements:
                if lookup_required and element.is_vcs_element():
                    spec = element.get_versioned_path_spec()
                else:
                    spec = element.get_path_spec()
                output = []
                for attr in only_options:
                    if 'localname' == attr:
                        output.append(spec.get_local_name() or '')
                    if 'path' == attr:
                        output.append(spec.get_path() or '')
                    if 'scmtype' == attr:
                        output.append(spec.get_scmtype() or '')
                    if 'uri' == attr:
                        output.append(spec.get_uri() or '')
                    if 'version' == attr:
                        output.append(spec.get_version() or '')
                    if 'revision' == attr:
                        output.append(spec.get_revision() or '')
                    if 'cur_uri' == attr:
                        output.append(spec.get_curr_uri() or '')
                    if 'cur_revision' == attr:
                        output.append(spec.get_current_revision() or '')
                print(','.join(output))
            return 0
        if options.yaml:
            source_aggregate = cmd_snapshot(config, localnames=args)
            print(yaml.safe_dump(source_aggregate))
            return 0

        # this call takes long, as it invokes scms.
        outputs = cmd_info(config, localnames=args)
        if args is not None and len(outputs) == 1:
            print(
                get_info_list(config.get_base_path(), outputs[0],
                              options.data_only))
            return 0

        header = 'workspace: %s\nROS_ROOT: %s' % (target_path,
                                                  get_ros_stack_path(config))
        print(header)
        if not options.no_pkg_path:
            table = get_info_table(config.get_base_path(),
                                   outputs,
                                   options.data_only,
                                   reverse=reverse)
            if table is not None and table != '':
                print("\n%s" % table)

        return 0
Exemplo n.º 16
0
def rosinstall_main(argv):
    if len(argv) < 2:
        usage()
    args = argv[1:]
    parser = OptionParser(
        usage=
        "usage: rosinstall [OPTIONS] INSTALL_PATH [ROSINSTALL FILES OR DIRECTORIES]\n\n\
rosinstall does the following:\n\
  1. Merges all URIs into new or existing .rosinstall file at PATH\n\
  2. Checks out or updates all version controlled URIs\n\
  3. If ros stack is installed from source, calls rosmake after checkout or updates.\n\
  4. Generates/overwrites updated setup files\n\n\
If running with --catkin mode:\
  1. Merges all URIs into new or existing .rosinstall file at PATH\n\
  2. Checks out or updates all version controlled URIs\n\
  4. Generates/overwrites updated setup files and creates CMakeLists.txt at the root.\n\n\
URIs can be web urls to remote .rosinstall files, local .rosinstall files,\n\
git, svn, bzr, hg URIs, or other (local directories)\n\
Later URIs will shadow packages of earlier URIs.\n",
        epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
    parser.add_option("-c",
                      "--catkin",
                      dest="catkin",
                      default=False,
                      help="Declare this is a catkin build.",
                      action="store_true")
    parser.add_option(
        "--cmake-prefix-path",
        dest="catkinpp",
        default=None,
        help="Where to set the CMAKE_PREFIX_PATH, implies --catkin",
        action="store")
    parser.add_option("--version",
                      dest="version",
                      default=False,
                      help="display version information",
                      action="store_true")
    parser.add_option("--verbose",
                      dest="verbose",
                      default=False,
                      help="display more information",
                      action="store_true")
    parser.add_option("-n",
                      "--nobuild",
                      dest="nobuild",
                      default=False,
                      help="skip the build step for the ROS stack",
                      action="store_true")
    parser.add_option("--rosdep-yes",
                      dest="rosdep_yes",
                      default=False,
                      help="Pass through --rosdep-yes to rosmake",
                      action="store_true")
    parser.add_option("--continue-on-error",
                      dest="robust",
                      default=False,
                      help="Continue despite checkout errors",
                      action="store_true")
    parser.add_option(
        "--delete-changed-uris",
        dest="delete_changed",
        default=False,
        help="Delete the local copy of a directory before changing uri.",
        action="store_true")
    parser.add_option("--abort-changed-uris",
                      dest="abort_changed",
                      default=False,
                      help="Abort if changed uri detected",
                      action="store_true")
    parser.add_option(
        "--backup-changed-uris",
        dest="backup_changed",
        default='',
        help=
        "backup the local copy of a directory before changing uri to this directory.",
        action="store")
    parser.add_option("--diff",
                      dest="vcs_diff",
                      default=False,
                      help="shows a combined diff over all SCM entries",
                      action="store_true")
    parser.add_option(
        "--status",
        dest="vcs_status",
        default=False,
        help="shows a combined status command over all SCM entries",
        action="store_true")
    parser.add_option(
        "--status-untracked",
        dest="vcs_status_untracked",
        default=False,
        help=
        "shows a combined status command over all SCM entries, also showing untracked files",
        action="store_true")
    parser.add_option("-j",
                      "--parallel",
                      dest="jobs",
                      default=1,
                      help="How many parallel threads to use for installing",
                      action="store")
    parser.add_option("--generate-versioned-rosinstall",
                      dest="generate_versioned",
                      default=None,
                      help="generate a versioned rosinstall file",
                      action="store")
    (options, args) = parser.parse_args(args)

    #if options.rosdep_yes:
    #  parser.error("rosinstall no longer bootstraps the build, it will not call rosmake or pass it rosdep options")

    if options.version:
        print("rosinstall %s\n%s" %
              (rosinstall.__version__.version, multiproject_cmd.cmd_version()))
        sys.exit(0)

    if len(args) < 1:
        parser.error("rosinstall requires at least 1 argument")

    mode = 'prompt'
    if options.delete_changed:
        mode = 'delete'
    if options.abort_changed:
        if mode == 'delete':
            parser.error(
                "delete-changed-uris is mutually exclusive with abort-changed-uris"
            )
        mode = 'abort'
    if options.backup_changed != '':
        if mode == 'delete':
            parser.error(
                "delete-changed-uris is mutually exclusive with backup-changed-uris"
            )
        if mode == 'abort':
            parser.error(
                "abort-changed-uris is mutually exclusive with backup-changed-uris"
            )
        mode = 'backup'

    # Catkin must be enabled if catkinpp is set
    if options.catkinpp:
        options.catkin = True

    # Get the path to the rosinstall
    options.path = os.path.abspath(args[0])

    config_uris = args[1:]

    config = multiproject_cmd.get_config(basepath=options.path,
                                         additional_uris=config_uris,
                                         config_filename=ROSINSTALL_FILENAME)

    if options.generate_versioned:
        filename = os.path.abspath(options.generate_versioned)
        source_aggregate = multiproject_cmd.cmd_snapshot(config)
        with open(filename, 'w') as fhand:
            fhand.write(yaml.safe_dump(source_aggregate))
        print("Saved versioned rosinstall of current directory %s to %s" %
              (options.path, filename))
        return True

    if options.vcs_diff:
        difflist = multiproject_cmd.cmd_diff(config)
        alldiff = []
        for entrydiff in difflist:
            if entrydiff['diff'] is not None and entrydiff['diff'] != '':
                alldiff.append(entrydiff['diff'])
        print('\n'.join(alldiff))
        return True

    if options.vcs_status or options.vcs_status_untracked:
        statuslist = multiproject_cmd.cmd_status(
            config, untracked=options.vcs_status_untracked)
        allstatus = ""
        for entrystatus in statuslist:
            if entrystatus['status'] is not None:
                allstatus += entrystatus['status']
        print(allstatus, end='')
        return True

    print("rosinstall operating on", options.path,
          "from specifications in rosinstall files ", ", ".join(config_uris))

    # includes ROS specific files
    print("(Over-)Writing %s" %
          os.path.join(options.path, ROSINSTALL_FILENAME))
    if (os.path.isfile(os.path.join(options.path, ROSINSTALL_FILENAME))):
        shutil.move(os.path.join(options.path, ROSINSTALL_FILENAME),
                    "%s.bak" % os.path.join(options.path, ROSINSTALL_FILENAME))
    rosinstall_cmd.cmd_persist_config(config)

    ## install or update each element
    install_success = multiproject_cmd.cmd_install_or_update(
        config,
        backup_path=options.backup_changed,
        mode=mode,
        robust=options.robust,
        num_threads=int(options.jobs),
        verbose=options.verbose)

    rosinstall_cmd.cmd_generate_ros_files(config, options.path,
                                          options.nobuild, options.rosdep_yes,
                                          options.catkin, options.catkinpp)

    if not install_success:
        print(
            "Warning: installation encountered errors, but --continue-on-error was requested.    Look above for warnings."
        )

    print("\nrosinstall update complete.")
    if (options.catkin is False and options.catkinpp is None):

        print(
            "\n\nNow, type 'source %s/setup.bash' to set up your environment.\nAdd that to the bottom of your ~/.bashrc to set it up every time.\n\nIf you are not using bash please see http://www.ros.org/wiki/rosinstall/NonBashShells "
            % os.path.abspath(options.path))
    return True
Exemplo n.º 17
0
def prompt_merge(target_path,
                 additional_uris,
                 additional_specs,
                 path_change_message=None,
                 merge_strategy='KillAppend',
                 confirmed=False,
                 confirm=False,
                 show_advanced=True,
                 show_verbosity=True,
                 config_filename=None,
                 config=None,
                 allow_other_element=True):
    """
    Prompts the user for the resolution of a merge. Without
    further options, will prompt only if elements change. New
    elements are just added without prompt.

    :param target_path: Location of the config workspace
    :param additional_uris: uris from which to load more elements
    :param additional_specs: path specs for additional elements
    :param path_change_message: Something to tell the user about elements order
    :param merge_strategy: See Config.insert_element
    :param confirmed: Never ask
    :param confirm: Always ask, supercedes confirmed
    :param config: None or a Config object for target path if available
    :param show_advanced: if true allow to change merge strategy
    :param show_verbosity: if true allows to change verbosity
    :param allow_other_element: if False merge fails hwen it could cause other elements
    :returns: tupel (Config or None if no change, bool path_changed)
    """
    if config is None:
        config = multiproject_cmd.get_config(
            target_path,
            additional_uris=[],
            config_filename=config_filename)
    elif config.get_base_path() != target_path:
        msg = "Config path does not match %s %s " % (config.get_base_path(),
                                                     target_path)
        raise MultiProjectException(msg)
    local_names_old = [x.get_local_name() for x in config.get_config_elements()]

    extra_verbose = confirmed or confirm
    abort = False
    last_merge_strategy = None
    while not abort:

        if (last_merge_strategy is None
            or last_merge_strategy != merge_strategy):
            if not config_filename:
                # should never happen right now with rosinstall/rosws/wstool
                # TODO Need a better way to work with clones of original config
                raise ValueError('Cannot merge when no config filename is set')
            newconfig = multiproject_cmd.get_config(
                target_path,
                additional_uris=[],
                config_filename=config_filename)
            config_actions = multiproject_cmd.add_uris(
                newconfig,
                additional_uris=additional_uris,
                merge_strategy=merge_strategy,
                allow_other_element=allow_other_element)
            for path_spec in additional_specs:
                action = newconfig.add_path_spec(path_spec, merge_strategy)
                config_actions[path_spec.get_local_name()] = (action, path_spec)
            last_merge_strategy = merge_strategy

        local_names_new = [x.get_local_name() for x in newconfig.get_config_elements()]

        path_changed = False
        ask_user = False
        output = ""
        new_elements = []
        changed_elements = []
        discard_elements = []
        for localname, (action, new_path_spec) in list(config_actions.items()):
            index = -1
            if localname in local_names_old:
                index = local_names_old.index(localname)
            if action == 'KillAppend':
                ask_user = True
                if (index > -1 and local_names_old[:index + 1] == local_names_new[:index + 1]):
                    action = 'MergeReplace'
                else:
                    changed_elements.append(_get_element_diff(new_path_spec, config, extra_verbose))
                    path_changed = True

            if action == 'Append':
                path_changed = True
                new_elements.append(_get_element_diff(new_path_spec,
                                                      config,
                                                      extra_verbose))
            elif action == 'MergeReplace':
                changed_elements.append(_get_element_diff(new_path_spec,
                                                          config,
                                                          extra_verbose))
                ask_user = True
            elif action == 'MergeKeep':
                discard_elements.append(_get_element_diff(new_path_spec,
                                                          config,
                                                          extra_verbose))
                ask_user = True
        if len(changed_elements) > 0:
            output += "\n     Change details of element (Use --merge-keep or --merge-replace to change):\n"
            if extra_verbose:
                output += " %s\n" % ("\n".join(sorted(changed_elements)))
            else:
                output += " %s\n" % (", ".join(sorted(changed_elements)))
        if len(new_elements) > 0:
            output += "\n     Add new elements:\n"
            if extra_verbose:
                output += " %s\n" % ("\n".join(sorted(new_elements)))
            else:
                output += " %s\n" % (", ".join(sorted(new_elements)))

        if local_names_old != local_names_new[:len(local_names_old)]:
            old_order = ' '.join(reversed(local_names_old))
            new_order = ' '.join(reversed(local_names_new))
            output += "\n     %s " % path_change_message or "Element order change"
            output += "(Use --merge-keep or --merge-replace to prevent) "
            output += "from\n %s\n     to\n %s\n\n" % (old_order, new_order)
            ask_user = True

        if output == "":
            return (None, False)
        if not confirm and (confirmed or not ask_user):
            print("     Performing actions: ")
            print(output)
            return (newconfig, path_changed)
        else:
            print(output)
            showhelp = True
            while(showhelp):
                showhelp = False
                prompt = "Continue: (y)es, (n)o"
                if show_verbosity:
                    prompt += ", (v)erbosity"
                if show_advanced:
                    prompt += ", (a)dvanced options"
                prompt += ": "
                mode_input = Ui.get_ui().get_input(prompt)
                if mode_input == 'y':
                    return (newconfig, path_changed)
                elif mode_input == 'n':
                    abort = True
                elif show_advanced and mode_input == 'a':
                    strategies = {'MergeKeep': "(k)eep",
                                  'MergeReplace': "(s)witch in",
                                  'KillAppend': "(a)ppending"}
                    unselected = [v for k, v in
                                  list(strategies.items())
                                  if k != merge_strategy]
                    print("""New entries will just be appended to the config and
appear at the beginning of your ROS_PACKAGE_PATH. The merge strategy
decides how to deal with entries having a duplicate localname or path.

"(k)eep" means the existing entry will stay as it is, the new one will
be discarded. Useful for getting additional elements from other
workspaces without affecting your setup.

"(s)witch in" means that the new entry will replace the old in the
same position. Useful for upgrading/downgrading.

"switch (a)ppend" means that the existing entry will be removed, and
the new entry appended to the end of the list. This maintains order
of elements in the order they were given.

Switch append is the default.
""")
                    prompt = "Change Strategy %s: " % (", ".join(unselected))
                    mode_input = Ui.get_ui().get_input(prompt)
                    if mode_input == 's':
                        merge_strategy = 'MergeReplace'
                    elif mode_input == 'k':
                        merge_strategy = 'MergeKeep'
                    elif mode_input == 'a':
                        merge_strategy = 'KillAppend'

                elif show_verbosity and mode_input == 'v':
                    extra_verbose = not extra_verbose
        if abort:
            print("No changes made.")
        print('==========================================')
    return (None, False)
Exemplo n.º 18
0
 def cmd_add_stack(self, target_path, argv):
     parser = OptionParser(usage="usage: rosws add-stack [PATH] localname",
                     epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
     parser.add_option("-N", "--non-recursive", dest="norecurse",
                       default=False,
                       help="don't change configuration for dependent stacks",
                       action="store_true")
     parser.add_option("--released", dest="released",
                       default=False,
                       help="Pull stack from release tag instead of development branch",
                       action="store_true")
     parser.add_option("--continue-on-error", dest="robust",
                       default=False,
                       help="Continue despite checkout errors",
                       action="store_true")
     parser.add_option("--delete-changed-uris", dest="delete_changed",
                       default=False,
                       help="Delete the local copy of a directory before changing uri.",
                       action="store_true")
     parser.add_option("--abort-changed-uris", dest="abort_changed",
                       default=False,
                       help="Abort if changed uri detected",
                       action="store_true")
     parser.add_option("--backup-changed-uris", dest="backup_changed",
                       default='',
                       help="backup the local copy of a directory before changing uri to this directory.",
                       action="store")
     (options, args) = parser.parse_args(argv)
     mode = 'prompt'
     if options.delete_changed:
         mode = 'delete'
     if options.abort_changed:
         if mode == 'delete':
             parser.error("delete-changed-uris is mutually exclusive with abort-changed-uris")
         mode = 'abort'
     if options.backup_changed != '':
         if mode == 'delete':
             parser.error("delete-changed-uris is mutually exclusive with backup-changed-uris")
         if mode == 'abort':
             parser.error("abort-changed-uris is mutually exclusive with backup-changed-uris")
         mode = 'backup'
     if len(args) < 1:
         print("Error: Too few arguments.")
         print(parser.usage)
         return -1
     if len(args) > 1:
         print("Error: Too many arguments.")
         print(parser.usage)
         return -1
     stack = args[0]
     config = get_config(target_path, [], config_filename=self.config_filename)
     if cmd_add_stack(config,
                      stack,
                      released=options.released,
                      recurse=(not options.norecurse)) is True:
         cmd_persist_config(config, self.config_filename)
         # install or update each element
         install_success = cmd_install_or_update(
             config,
             backup_path=options.backup_changed,
             mode=mode,
             robust=options.robust)
         if install_success:
             return 0
     return 1
Exemplo n.º 19
0
    def cmd_init(self, argv):
        if self.config_filename is None:
            print('Error: Bug: config filename required for init')
            return 1
        parser = OptionParser(
            usage="""usage: %s init [TARGET_PATH [SOURCE_PATH]]?""" %
            _PROGNAME,
            formatter=IndentedHelpFormatterWithNL(),
            description=__MULTIPRO_CMD_DICT__["init"] + """

%(prog)s init does the following:
  1. Reads folder/file/web-uri SOURCE_PATH looking for a rosinstall yaml
  2. Creates new %(cfg_file)s file at TARGET-PATH
  3. Generates ROS setup files

SOURCE_PATH can e.g. be a folder like /opt/ros/electric
If PATH is not given, uses current dir.

Examples:
$ %(prog)s init ~/fuerte /opt/ros/fuerte
""" % {
                'cfg_file': self.config_filename,
                'prog': _PROGNAME
            },
            epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("-c",
                          "--catkin",
                          dest="catkin",
                          default=False,
                          help="Declare this is a catkin build.",
                          action="store_true")
        parser.add_option("--cmake-prefix-path",
                          dest="catkinpp",
                          default=None,
                          help="Where to set the CMAKE_PREFIX_PATH",
                          action="store")
        parser.add_option("--continue-on-error",
                          dest="robust",
                          default=False,
                          help="Continue despite checkout errors",
                          action="store_true")
        parser.add_option(
            "-j",
            "--parallel",
            dest="jobs",
            default=1,
            help="How many parallel threads to use for installing",
            action="store")
        (options, args) = parser.parse_args(argv)
        if len(args) < 1:
            target_path = '.'
        else:
            target_path = args[0]

        if not os.path.isdir(target_path):
            if not os.path.exists(target_path):
                os.mkdir(target_path)
            else:
                print('Error: Cannot create in target path %s ' % target_path)

        if os.path.exists(os.path.join(target_path, self.config_filename)):
            print(
                'Error: There already is a workspace config file %s at "%s". Use %s install/modify.'
                % (self.config_filename, target_path, _PROGNAME))
            return 1
        if len(args) > 2:
            parser.error('Too many arguments')
        config_uris = []
        if len(args) == 2:
            config_uris.append(args[1])
        if len(config_uris) > 0:
            print('Using ROS_ROOT: %s' % config_uris[0])

        config = get_config(basepath=target_path,
                            additional_uris=config_uris,
                            config_filename=self.config_filename)

        # includes ROS specific files

        print("Writing %s" %
              os.path.join(config.get_base_path(), self.config_filename))
        rosinstall_cmd.cmd_persist_config(config)

        ## install or update each element
        install_success = cmd_install_or_update(config,
                                                robust=False,
                                                num_threads=int(options.jobs))

        rosinstall_cmd.cmd_generate_ros_files(config,
                                              target_path,
                                              nobuild=True,
                                              rosdep_yes=False,
                                              catkin=options.catkin,
                                              catkinpp=options.catkinpp,
                                              no_ros_allowed=True)

        if not install_success:
            print(
                "Warning: installation encountered errors, but --continue-on-error was requested.  Look above for warnings."
            )
        print("\nrosinstall update complete.")
        if (options.catkin is False and options.catkinpp is None):
            print(
                "\nType 'source %s/setup.bash' to change into this environment. Add that source command to the bottom of your ~/.bashrc to set it up every time you log in.\n\nIf you are not using bash please see http://www.ros.org/wiki/rosinstall/NonBashShells "
                % os.path.abspath(target_path))
        return 0
Exemplo n.º 20
0
    def cmd_update(self, target_path, argv, config=None):
        parser = OptionParser(
            usage="usage: %s update [localname]*" % self.progname,
            formatter=IndentedHelpFormatterWithNL(),
            description=__MULTIPRO_CMD_DICT__["update"] + """

This command calls the SCM provider to pull changes from remote to
your local filesystem. In case the url has changed, the command will
ask whether to delete or backup the folder.

Examples:
$ %(progname)s update -t ~/fuerte
$ %(progname)s update robot_model geometry
""" % {'progname': self.progname},
            epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option(
            "--delete-changed-uris",
            dest="delete_changed",
            default=False,
            help="Delete the local copy of a directory before changing uri.",
            action="store_true")
        parser.add_option("--abort-changed-uris",
                          dest="abort_changed",
                          default=False,
                          help="Abort if changed uri detected",
                          action="store_true")
        parser.add_option("--continue-on-error",
                          dest="robust",
                          default=False,
                          help="Continue despite checkout errors",
                          action="store_true")
        parser.add_option(
            "--backup-changed-uris",
            dest="backup_changed",
            default='',
            help=
            "backup the local copy of a directory before changing uri to this directory.",
            action="store")
        parser.add_option(
            "-j",
            "--parallel",
            dest="jobs",
            default=1,
            help="How many parallel threads to use for installing",
            action="store")
        parser.add_option("-v",
                          "--verbose",
                          dest="verbose",
                          default=False,
                          help="Whether to print out more information",
                          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 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))
        success = True
        mode = _get_mode_from_options(parser, options)
        if args == []:
            # None means no filter, [] means filter all
            args = None
        if success:
            install_success = multiproject_cmd.cmd_install_or_update(
                config,
                localnames=args,
                backup_path=options.backup_changed,
                mode=mode,
                robust=options.robust,
                num_threads=int(options.jobs),
                verbose=options.verbose)
            if install_success or options.robust:
                return 0
        return 1
Exemplo n.º 21
0
    def cmd_init(self, argv):
        if self.config_filename is None:
            print('Error: Bug: config filename required for init')
            return 1
        parser = OptionParser(
            usage="""usage: %s init [TARGET_PATH [SOURCE_PATH]]?""" % self.progname,
            formatter=IndentedHelpFormatterWithNL(),
            description=__MULTIPRO_CMD_DICT__["init"] + """

%(prog)s init does the following:
  1. Reads folder/file/web-uri SOURCE_PATH looking for a rosinstall yaml
  2. Creates new %(cfg_file)s file at TARGET-PATH
  3. Generates ROS setup files

SOURCE_PATH can e.g. be a folder like /opt/ros/electric
If PATH is not given, uses current dir.

Examples:
$ %(prog)s init ~/fuerte /opt/ros/fuerte
""" % {'cfg_file': self.config_filename, 'prog': self.progname},
            epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("-c", "--catkin", dest="catkin", default=False,
                          help="Declare this is a catkin build.",
                          action="store_true")
        parser.add_option("--cmake-prefix-path", dest="catkinpp", default=None,
                          help="Where to set the CMAKE_PREFIX_PATH",
                          action="store")
        parser.add_option("--continue-on-error", dest="robust", default=False,
                          help="Continue despite checkout errors",
                          action="store_true")
        parser.add_option("-j", "--parallel", dest="jobs", default=1,
                          help="How many parallel threads to use for installing",
                          action="store")
        (options, args) = parser.parse_args(argv)
        if len(args) < 1:
            target_path = '.'
        else:
            target_path = args[0]

        if not os.path.isdir(target_path):
            if not os.path.exists(target_path):
                os.mkdir(target_path)
            else:
                print('Error: Cannot create in target path %s ' % target_path)

        if os.path.exists(os.path.join(target_path, self.config_filename)):
            print('Error: There already is a workspace config file %s at "%s". Use %s install/modify.' %
                  (self.config_filename, target_path, self.progname))
            return 1
        if len(args) > 2:
            parser.error('Too many arguments')
        config_uris = []
        if len(args) == 2:
            config_uris.append(args[1])
        if len(config_uris) > 0:
            print('Using ROS_ROOT: %s' % config_uris[0])

        config = get_config(basepath=target_path,
                            additional_uris=config_uris,
                            config_filename=self.config_filename)

        # includes ROS specific files

        print("Writing %s" % os.path.join(config.get_base_path(),
              self.config_filename))
        rosinstall_cmd.cmd_persist_config(config)

        ## install or update each element
        install_success = cmd_install_or_update(
            config,
            robust=False,
            num_threads=int(options.jobs))

        rosinstall_cmd.cmd_generate_ros_files(config,
                                              target_path,
                                              nobuild=True,
                                              rosdep_yes=False,
                                              catkin=options.catkin,
                                              catkinpp=options.catkinpp,
                                              no_ros_allowed=True)

        if not install_success:
            print("Warning: installation encountered errors, but --continue-on-error was requested.  Look above for warnings.")
        print("\nrosinstall update complete.")
        if (options.catkin is False
            and options.catkinpp is None):
            print("\nType 'source %s/setup.bash' to change into this environment. Add that source command to the bottom of your ~/.bashrc to set it up every time you log in.\n\nIf you are not using bash please see http://www.ros.org/wiki/rosinstall/NonBashShells " % os.path.abspath(target_path))
        return 0
Exemplo n.º 22
0
def rosinstall_main(argv):
    if len(argv) < 2:
        usage()
    args = argv[1:]
    parser = OptionParser(
        usage="usage: rosinstall [OPTIONS] INSTALL_PATH [ROSINSTALL FILES OR DIRECTORIES]\n\n\
rosinstall does the following:\n\
  1. Merges all URIs into new or existing .rosinstall file at PATH\n\
  2. Checks out or updates all version controlled URIs\n\
  3. If ros stack is installed from source, calls rosmake after checkout or updates.\n\
  4. Generates/overwrites updated setup files\n\n\
If running with --catkin mode:\
  1. Merges all URIs into new or existing .rosinstall file at PATH\n\
  2. Checks out or updates all version controlled URIs\n\
  4. Generates/overwrites updated setup files and creates CMakeLists.txt at the root.\n\n\
URIs can be web urls to remote .rosinstall files, local .rosinstall files,\n\
git, svn, bzr, hg URIs, or other (local directories)\n\
Later URIs will shadow packages of earlier URIs.\n",
        epilog="See: http://www.ros.org/wiki/rosinstall for details\n",
    )
    parser.add_option(
        "-c", "--catkin", dest="catkin", default=False, help="Declare this is a catkin build.", action="store_true"
    )
    parser.add_option(
        "--cmake-prefix-path",
        dest="catkinpp",
        default=None,
        help="Where to set the CMAKE_PREFIX_PATH, implies --catkin",
        action="store",
    )
    parser.add_option(
        "--version", dest="version", default=False, help="display version information", action="store_true"
    )
    parser.add_option("--verbose", dest="verbose", default=False, help="display more information", action="store_true")
    parser.add_option(
        "-n",
        "--nobuild",
        dest="nobuild",
        default=False,
        help="skip the build step for the ROS stack",
        action="store_true",
    )
    parser.add_option(
        "--rosdep-yes",
        dest="rosdep_yes",
        default=False,
        help="Pass through --rosdep-yes to rosmake",
        action="store_true",
    )
    parser.add_option(
        "--continue-on-error",
        dest="robust",
        default=False,
        help="Continue despite checkout errors",
        action="store_true",
    )
    parser.add_option(
        "--delete-changed-uris",
        dest="delete_changed",
        default=False,
        help="Delete the local copy of a directory before changing uri.",
        action="store_true",
    )
    parser.add_option(
        "--abort-changed-uris",
        dest="abort_changed",
        default=False,
        help="Abort if changed uri detected",
        action="store_true",
    )
    parser.add_option(
        "--backup-changed-uris",
        dest="backup_changed",
        default="",
        help="backup the local copy of a directory before changing uri to this directory.",
        action="store",
    )
    parser.add_option(
        "--diff", dest="vcs_diff", default=False, help="shows a combined diff over all SCM entries", action="store_true"
    )
    parser.add_option(
        "--status",
        dest="vcs_status",
        default=False,
        help="shows a combined status command over all SCM entries",
        action="store_true",
    )
    parser.add_option(
        "--status-untracked",
        dest="vcs_status_untracked",
        default=False,
        help="shows a combined status command over all SCM entries, also showing untracked files",
        action="store_true",
    )
    parser.add_option(
        "-j",
        "--parallel",
        dest="jobs",
        default=1,
        help="How many parallel threads to use for installing",
        action="store",
    )
    parser.add_option(
        "--generate-versioned-rosinstall",
        dest="generate_versioned",
        default=None,
        help="generate a versioned rosinstall file",
        action="store",
    )
    (options, args) = parser.parse_args(args)

    if options.version:
        print("rosinstall %s\n%s" % (rosinstall.__version__.version, multiproject_cmd.cmd_version()))
        sys.exit(0)

    if len(args) < 1:
        parser.error("rosinstall requires at least 1 argument")

    mode = "prompt"
    if options.delete_changed:
        mode = "delete"
    if options.abort_changed:
        if mode == "delete":
            parser.error("delete-changed-uris is mutually exclusive with abort-changed-uris")
        mode = "abort"
    if options.backup_changed != "":
        if mode == "delete":
            parser.error("delete-changed-uris is mutually exclusive with backup-changed-uris")
        if mode == "abort":
            parser.error("abort-changed-uris is mutually exclusive with backup-changed-uris")
        mode = "backup"

    # Catkin must be enabled if catkinpp is set
    if options.catkinpp:
        options.catkin = True

    # Get the path to the rosinstall
    options.path = os.path.abspath(args[0])

    config_uris = args[1:]

    config = multiproject_cmd.get_config(
        basepath=options.path, additional_uris=config_uris, config_filename=ROSINSTALL_FILENAME
    )

    if options.generate_versioned:
        filename = os.path.abspath(options.generate_versioned)
        source_aggregate = multiproject_cmd.cmd_snapshot(config)
        with open(filename, "w") as fhand:
            fhand.write(yaml.safe_dump(source_aggregate))
        print("Saved versioned rosinstall of current directory %s to %s" % (options.path, filename))
        return True

    if options.vcs_diff:
        difflist = multiproject_cmd.cmd_diff(config)
        alldiff = []
        for entrydiff in difflist:
            if entrydiff["diff"] is not None and entrydiff["diff"] != "":
                alldiff.append(entrydiff["diff"])
        print("\n".join(alldiff))
        return True

    if options.vcs_status or options.vcs_status_untracked:
        statuslist = multiproject_cmd.cmd_status(config, untracked=options.vcs_status_untracked)
        allstatus = ""
        for entrystatus in statuslist:
            if entrystatus["status"] is not None:
                allstatus += entrystatus["status"]
        print(allstatus, end="")
        return True

    print("rosinstall operating on", options.path, "from specifications in rosinstall files ", ", ".join(config_uris))

    # includes ROS specific files
    print("(Over-)Writing %s" % os.path.join(options.path, ROSINSTALL_FILENAME))
    if os.path.isfile(os.path.join(options.path, ROSINSTALL_FILENAME)):
        shutil.move(
            os.path.join(options.path, ROSINSTALL_FILENAME), "%s.bak" % os.path.join(options.path, ROSINSTALL_FILENAME)
        )
    rosinstall_cmd.cmd_persist_config(config)

    ## install or update each element
    install_success = multiproject_cmd.cmd_install_or_update(
        config,
        backup_path=options.backup_changed,
        mode=mode,
        robust=options.robust,
        num_threads=int(options.jobs),
        verbose=options.verbose,
    )

    rosinstall_cmd.cmd_generate_ros_files(
        config, options.path, options.nobuild, options.rosdep_yes, options.catkin, options.catkinpp
    )

    if not install_success:
        print(
            "Warning: installation encountered errors, but --continue-on-error was requested.    Look above for warnings."
        )

    print("\nrosinstall update complete.")
    if options.catkin is False and options.catkinpp is None:

        print(
            "\n\nNow, type 'source %s/setup.bash' to set up your environment.\nAdd that to the bottom of your ~/.bashrc to set it up every time.\n\nIf you are not using bash please see http://www.ros.org/wiki/rosinstall/NonBashShells "
            % os.path.abspath(options.path)
        )
    return True
Exemplo n.º 23
0
    def cmd_info(self, target_path, argv, reverse=True, config=None):
        parser = OptionParser(
            usage="usage: %s info [localname]* [OPTIONS]" % self.progname,
            formatter=IndentedHelpFormatterWithNL(),
            description=__MULTIPRO_CMD_DICT__["info"] + """

The Status (S) column shows
 x  for missing
 L  for uncommited (local) changes
 V  for difference in version and/or remote URI

The 'Version-Spec' column shows what tag, branch or revision was given
in the .rosinstall file. The 'UID' column shows the unique ID of the
current (and specified) version. The 'URI' column shows the configured
URL of the repo.

If status is V, the difference between what was specified and what is
real is shown in the respective column. For SVN entries, the url is
split up according to standard layout (trunk/tags/branches).

When given one localname, just show the data of one element in list form.
This also has the generic properties element which is usually empty.

The --only option accepts keywords: %(opts)s

Examples:
$ %(prog)s info -t ~/ros/fuerte
$ %(prog)s info robot_model
$ %(prog)s info --yaml
$ %(prog)s info --only=path,cur_uri,cur_revision robot_model geometry
""" % {'prog': self.progname, 'opts': ONLY_OPTION_VALID_ATTRS},
            epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option(
            "--data-only", dest="data_only", default=False,
            help="Does not provide explanations",
            action="store_true")
        parser.add_option(
            "--only", dest="only", default=False,
            help="Shows comma-separated lists of only given comma-separated attribute(s).",
            action="store")
        parser.add_option(
            "--yaml", dest="yaml", default=False,
            help="Shows only version of single entry. Intended for scripting.",
            action="store_true")
        parser.add_option(
            "-u", "--untracked", dest="untracked",
            default=False,
            help="Also show untracked files as modifications",
            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 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))

        if args == []:
            args = None

        if options.only:
            only_options = options.only.split(",")
            if only_options == '':
                parser.error('No valid options given')
            lines = get_info_table_raw_csv(config,
                                           properties=only_options,
                                           localnames=args)
            print('\n'.join(lines))
            return 0
        elif options.yaml:
            source_aggregate = multiproject_cmd.cmd_snapshot(config,
                                                             localnames=args)
            print(yaml.safe_dump(source_aggregate), end='')
            return 0

        # this call takes long, as it invokes scms.
        outputs = multiproject_cmd.cmd_info(config,
                                            localnames=args,
                                            untracked=options.untracked)
        if args and len(args) == 1:
            # if only one element selected, print just one line
            print(get_info_list(config.get_base_path(),
                                outputs[0],
                                options.data_only))
            return 0

        header = 'workspace: %s' % (target_path)
        print(header)
        table = get_info_table(config.get_base_path(),
                               outputs,
                               options.data_only,
                               reverse=reverse)
        if table is not None and table != '':
           print("\n%s" % table)

        return 0
Exemplo n.º 24
0
    def cmd_init(self, argv):
        if self.config_filename is None:
            print('Error: Bug: config filename required for init')
            return 1
        parser = OptionParser(
            usage="""usage: %s init [TARGET_PATH [SOURCE_PATH]]?""" %
            self.progname,
            formatter=IndentedHelpFormatterWithNL(),
            description=__MULTIPRO_CMD_DICT__["init"] + """

%(prog)s init does the following:
  1. Reads folder/file/web-uri SOURCE_PATH looking for a rosinstall yaml
  2. Creates new %(cfg_file)s file at TARGET-PATH
  3. Generates ROS setup files

SOURCE_PATH can e.g. be a folder like /opt/ros/electric
If PATH is not given, uses current dir.

Examples:
$ %(prog)s init ~/fuerte /opt/ros/fuerte
""" % {
                'cfg_file': self.config_filename,
                'prog': self.progname
            },
            epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("--continue-on-error",
                          dest="robust",
                          default=False,
                          help="Continue despite checkout errors",
                          action="store_true")
        parser.add_option(
            "-j",
            "--parallel",
            dest="jobs",
            default=1,
            help="How many parallel threads to use for installing",
            action="store")
        (options, args) = parser.parse_args(argv)
        if len(args) < 1:
            target_path = '.'
        else:
            target_path = args[0]

        if not os.path.isdir(target_path):
            if not os.path.exists(target_path):
                os.mkdir(target_path)
            else:
                print('Error: Cannot create in target path %s ' % target_path)

        if os.path.exists(os.path.join(target_path, self.config_filename)):
            print(
                'Error: There already is a workspace config file %s at "%s". Use %s install/modify.'
                % (self.config_filename, target_path, self.progname))
            return 1
        if len(args) > 2:
            parser.error('Too many arguments')
        if len(args) == 2:
            print('Using initial elements from: %s' % args[1])
            config_uris = [args[1]]
        else:
            config_uris = []

        config = multiproject_cmd.get_config(
            basepath=target_path,
            additional_uris=config_uris,
            config_filename=(self.config_filename
                             if self.allow_other_element else None))

        # includes ROS specific files

        print("Writing %s" %
              os.path.join(config.get_base_path(), self.config_filename))
        self.config_generator(config, self.config_filename,
                              get_header(self.progname))

        ## install or update each element
        install_success = multiproject_cmd.cmd_install_or_update(
            config, robust=False, num_threads=int(options.jobs))

        if not install_success:
            print(
                "Warning: installation encountered errors, but --continue-on-error was requested.  Look above for warnings."
            )
        print("\nupdate complete.")
        return 0
Exemplo n.º 25
0
def prompt_merge(target_path,
                 additional_uris,
                 additional_specs,
                 path_change_message=None,
                 merge_strategy='KillAppend',
                 confirmed=False,
                 confirm=False,
                 show_advanced=True,
                 show_verbosity=True,
                 config_filename=None,
                 config=None,
                 allow_other_element=True):
    """
    Prompts the user for the resolution of a merge. Without
    further options, will prompt only if elements change. New
    elements are just added without prompt.

    :param target_path: Location of the config workspace
    :param additional_uris: uris from which to load more elements
    :param additional_specs: path specs for additional elements
    :param path_change_message: Something to tell the user about elements order
    :param merge_strategy: See Config.insert_element
    :param confirmed: Never ask
    :param confirm: Always ask, supercedes confirmed
    :param config: None or a Config object for target path if available
    :param show_advanced: if true allow to change merge strategy
    :param show_verbosity: if true allows to change verbosity
    :param allow_other_element: if False merge fails hwen it could cause other elements
    :returns: tupel (Config or None if no change, bool path_changed)
    """
    if config is None:
        config = multiproject_cmd.get_config(target_path,
                                             additional_uris=[],
                                             config_filename=config_filename)
    elif config.get_base_path() != target_path:
        msg = "Config path does not match %s %s " % (config.get_base_path(),
                                                     target_path)
        raise MultiProjectException(msg)
    local_names_old = [
        x.get_local_name() for x in config.get_config_elements()
    ]

    extra_verbose = confirmed or confirm
    abort = False
    last_merge_strategy = None
    while not abort:

        if (last_merge_strategy is None
                or last_merge_strategy != merge_strategy):
            if not config_filename:
                # should never happen right now with rosinstall/rosws/wstool
                # TODO Need a better way to work with clones of original config
                raise ValueError('Cannot merge when no config filename is set')
            newconfig = multiproject_cmd.get_config(
                target_path,
                additional_uris=[],
                config_filename=config_filename)
            config_actions = multiproject_cmd.add_uris(
                newconfig,
                additional_uris=additional_uris,
                merge_strategy=merge_strategy,
                allow_other_element=allow_other_element)
            for path_spec in additional_specs:
                action = newconfig.add_path_spec(path_spec, merge_strategy)
                config_actions[path_spec.get_local_name()] = (action,
                                                              path_spec)
            last_merge_strategy = merge_strategy

        local_names_new = [
            x.get_local_name() for x in newconfig.get_config_elements()
        ]

        path_changed = False
        ask_user = False
        output = ""
        new_elements = []
        changed_elements = []
        discard_elements = []
        for localname, (action, new_path_spec) in list(config_actions.items()):
            index = -1
            if localname in local_names_old:
                index = local_names_old.index(localname)
            if action == 'KillAppend':
                ask_user = True
                if (index > -1 and local_names_old[:index + 1]
                        == local_names_new[:index + 1]):
                    action = 'MergeReplace'
                else:
                    changed_elements.append(
                        _get_element_diff(new_path_spec, config,
                                          extra_verbose))
                    path_changed = True

            if action == 'Append':
                path_changed = True
                new_elements.append(
                    _get_element_diff(new_path_spec, config, extra_verbose))
            elif action == 'MergeReplace':
                changed_elements.append(
                    _get_element_diff(new_path_spec, config, extra_verbose))
                ask_user = True
            elif action == 'MergeKeep':
                discard_elements.append(
                    _get_element_diff(new_path_spec, config, extra_verbose))
                ask_user = True
        if len(changed_elements) > 0:
            output += "\n     Change details of element (Use --merge-keep or --merge-replace to change):\n"
            if extra_verbose:
                output += " %s\n" % ("\n".join(sorted(changed_elements)))
            else:
                output += " %s\n" % (", ".join(sorted(changed_elements)))
        if len(new_elements) > 0:
            output += "\n     Add new elements:\n"
            if extra_verbose:
                output += " %s\n" % ("\n".join(sorted(new_elements)))
            else:
                output += " %s\n" % (", ".join(sorted(new_elements)))

        if local_names_old != local_names_new[:len(local_names_old)]:
            old_order = ' '.join(reversed(local_names_old))
            new_order = ' '.join(reversed(local_names_new))
            output += "\n     %s " % path_change_message or "Element order change"
            output += "(Use --merge-keep or --merge-replace to prevent) "
            output += "from\n %s\n     to\n %s\n\n" % (old_order, new_order)
            ask_user = True

        if output == "":
            return (None, False)
        if not confirm and (confirmed or not ask_user):
            print("     Performing actions: ")
            print(output)
            return (newconfig, path_changed)
        else:
            print(output)
            showhelp = True
            while (showhelp):
                showhelp = False
                prompt = "Continue: (y)es, (n)o"
                if show_verbosity:
                    prompt += ", (v)erbosity"
                if show_advanced:
                    prompt += ", (a)dvanced options"
                prompt += ": "
                mode_input = Ui.get_ui().get_input(prompt)
                if mode_input == 'y':
                    return (newconfig, path_changed)
                elif mode_input == 'n':
                    abort = True
                elif show_advanced and mode_input == 'a':
                    strategies = {
                        'MergeKeep': "(k)eep",
                        'MergeReplace': "(s)witch in",
                        'KillAppend': "(a)ppending"
                    }
                    unselected = [
                        v for k, v in list(strategies.items())
                        if k != merge_strategy
                    ]
                    print(
                        """New entries will just be appended to the config and
appear at the beginning of your ROS_PACKAGE_PATH. The merge strategy
decides how to deal with entries having a duplicate localname or path.

"(k)eep" means the existing entry will stay as it is, the new one will
be discarded. Useful for getting additional elements from other
workspaces without affecting your setup.

"(s)witch in" means that the new entry will replace the old in the
same position. Useful for upgrading/downgrading.

"switch (a)ppend" means that the existing entry will be removed, and
the new entry appended to the end of the list. This maintains order
of elements in the order they were given.

Switch append is the default.
""")
                    prompt = "Change Strategy %s: " % (", ".join(unselected))
                    mode_input = Ui.get_ui().get_input(prompt)
                    if mode_input == 's':
                        merge_strategy = 'MergeReplace'
                    elif mode_input == 'k':
                        merge_strategy = 'MergeKeep'
                    elif mode_input == 'a':
                        merge_strategy = 'KillAppend'

                elif show_verbosity and mode_input == 'v':
                    extra_verbose = not extra_verbose
        if abort:
            print("No changes made.")
        print('==========================================')
    return (None, False)
Exemplo n.º 26
0
    def cmd_info(self, target_path, argv, reverse=True, config=None):
        parser = OptionParser(
            usage="usage: %s info [localname]* [OPTIONS]" % self.progname,
            formatter=IndentedHelpFormatterWithNL(),
            description=__MULTIPRO_CMD_DICT__["info"] + """

The Status (S) column shows
 x  for missing
 L  for uncommited (local) changes
 V  for difference in version and/or remote URI

The 'Version-Spec' column shows what tag, branch or revision was given
in the .rosinstall file. The 'UID' column shows the unique ID of the
current (and specified) version. The 'URI' column shows the configured
URL of the repo.

If status is V, the difference between what was specified and what is
real is shown in the respective column. For SVN entries, the url is
split up according to standard layout (trunk/tags/branches).

When given one localname, just show the data of one element in list form.
This also has the generic properties element which is usually empty.

The --only option accepts keywords: %(opts)s

Examples:
$ %(prog)s info -t ~/ros/fuerte
$ %(prog)s info robot_model
$ %(prog)s info --yaml
$ %(prog)s info --only=path,cur_uri,cur_revision robot_model geometry
""" % {
                'prog': self.progname,
                'opts': ONLY_OPTION_VALID_ATTRS
            },
            epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("--data-only",
                          dest="data_only",
                          default=False,
                          help="Does not provide explanations",
                          action="store_true")
        parser.add_option(
            "--only",
            dest="only",
            default=False,
            help=
            "Shows comma-separated lists of only given comma-separated attribute(s).",
            action="store")
        parser.add_option(
            "--yaml",
            dest="yaml",
            default=False,
            help="Shows only version of single entry. Intended for scripting.",
            action="store_true")
        parser.add_option("-u",
                          "--untracked",
                          dest="untracked",
                          default=False,
                          help="Also show untracked files as modifications",
                          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 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))

        if args == []:
            args = None

        if options.only:
            only_options = options.only.split(",")
            if only_options == '':
                parser.error('No valid options given')
            lines = get_info_table_raw_csv(config,
                                           properties=only_options,
                                           localnames=args)
            print('\n'.join(lines))
            return 0
        elif options.yaml:
            source_aggregate = multiproject_cmd.cmd_snapshot(config,
                                                             localnames=args)
            print(yaml.safe_dump(source_aggregate), end='')
            return 0

        # this call takes long, as it invokes scms.
        outputs = multiproject_cmd.cmd_info(config,
                                            localnames=args,
                                            untracked=options.untracked)
        if args and len(args) == 1:
            # if only one element selected, print just one line
            print(
                get_info_list(config.get_base_path(), outputs[0],
                              options.data_only))
            return 0

        header = 'workspace: %s' % (target_path)
        print(header)
        table = get_info_table(config.get_base_path(),
                               outputs,
                               options.data_only,
                               reverse=reverse)
        if table is not None and table != '':
            print("\n%s" % table)

        return 0
Exemplo n.º 27
0
    def cmd_info(self, target_path, argv, reverse=True, config=None):
        only_option_valid_attrs = ['path', 'localname', 'version', 'revision', 'cur_revision', 'uri', 'cur_uri', 'scmtype']
        parser = OptionParser(usage="usage: %s info [localname]* [OPTIONS]" % self.progname,
                              formatter=IndentedHelpFormatterWithNL(),
                              description=__MULTIPRO_CMD_DICT__["info"] + """

The Status (S) column shows
 x  for missing
 L  for uncommited (local) changes
 V  for difference in version and/or remote URI

The 'Version-Spec' column shows what tag, branch or revision was given
in the .rosinstall file. The 'UID' column shows the unique ID of the
current (and specified) version. The 'URI' column shows the configured
URL of the repo.

If status is V, the difference between what was specified and what is
real is shown in the respective column. For SVN entries, the url is
split up according to standard layout (trunk/tags/branches).  The
ROS_PACKAGE_PATH follows the order of the table, earlier entries
overlay later entries.

When given one localname, just show the data of one element in list form.
This also has the generic properties element which is usually empty.

The --only option accepts keywords: %(opts)s

Examples:
$ %(prog)s info -t ~/ros/fuerte
$ %(prog)s info robot_model
$ %(prog)s info --yaml
$ %(prog)s info --only=path,cur_uri,cur_revision robot_model geometry
""" % {'prog': _PROGNAME, 'opts': only_option_valid_attrs},
                              epilog="See: http://www.ros.org/wiki/rosinstall for details\n")
        parser.add_option("--data-only", dest="data_only", default=False,
                          help="Does not provide explanations",
                          action="store_true")
        parser.add_option("--no-pkg-path", dest="no_pkg_path", default=False,
                          help="Suppress ROS_PACKAGE_PATH.",
                          action="store_true")
        parser.add_option("--pkg-path-only", dest="pkg_path_only", default=False,
                          help="Shows only ROS_PACKAGE_PATH separated by ':'. Supercedes all other options.",
                          action="store_true")
        parser.add_option("--only", dest="only", default=False,
                          help="Shows comma-separated lists of only given comma-separated attribute(s).",
                          action="store")
        parser.add_option("--yaml", dest="yaml", default=False,
                          help="Shows only version of single entry. Intended for scripting.",
                          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 config is None:
            config = 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))
        if args == []:
            args = None
        # relevant for code completion, so these should yield quick response:
        if options.pkg_path_only:
            print(":".join(get_ros_package_path(config)))
            return 0
        elif options.only:
            only_options = options.only.split(",")
            if only_options == '':
                parser.error('No valid options given')

            lookup_required = False
            for attr in only_options:
                if not attr in only_option_valid_attrs:
                    parser.error("Invalid --only option '%s', valids are %s" % (attr, only_option_valid_attrs))
                if attr in ['cur_revision', 'cur_uri', 'revision']:
                    lookup_required = True
            elements = select_elements(config, args)
            for element in elements:
                if lookup_required and element.is_vcs_element():
                    spec = element.get_versioned_path_spec()
                else:
                    spec = element.get_path_spec()
                output = []
                for attr in only_options:
                    if 'localname' == attr:
                        output.append(spec.get_local_name() or '')
                    if 'path' == attr:
                        output.append(spec.get_path() or '')
                    if 'scmtype' == attr:
                        output.append(spec.get_scmtype() or '')
                    if 'uri' == attr:
                        output.append(spec.get_uri() or '')
                    if 'version' == attr:
                        output.append(spec.get_version() or '')
                    if 'revision' == attr:
                        output.append(spec.get_revision() or '')
                    if 'cur_uri' == attr:
                        output.append(spec.get_curr_uri() or '')
                    if 'cur_revision' == attr:
                        output.append(spec.get_current_revision() or '')
                print(','.join(output))
            return 0
        if options.yaml:
            source_aggregate = cmd_snapshot(config, localnames=args)
            print(yaml.safe_dump(source_aggregate))
            return 0

        # this call takes long, as it invokes scms.
        outputs = cmd_info(config, localnames=args)
        if args is not None and len(outputs) == 1:
            print(get_info_list(config.get_base_path(),
                                outputs[0],
                                options.data_only))
            return 0

        header = 'workspace: %s\nROS_ROOT: %s' % (target_path,
                                                  get_ros_stack_path(config))
        print(header)
        if not options.no_pkg_path:
            table = get_info_table(config.get_base_path(),
                                   outputs,
                                   options.data_only,
                                   reverse=reverse)
            if table is not None and table != '':
                print("\n%s" % table)

        return 0
Exemplo n.º 28
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