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

            if not present:
                error_message = "Failed to detect %s presence at %s." % (
                    self.get_vcs_type_name(), self.path)
            else:
                cur_url = self._get_vcsc().get_url()
                if cur_url is not None:
                    # strip trailing slashes for #3269
                    cur_url = cur_url.rstrip('/')
                if not cur_url or cur_url != self.uri.rstrip('/'):
                    # local repositories get absolute pathnames
                    if not (os.path.isdir(self.uri) and os.path.isdir(cur_url)
                            and samefile(cur_url, self.uri)):
                        if not self._get_vcsc().url_matches(cur_url, self.uri):
                            error_message = "Url %s does not match %s requested." % (
                                cur_url, self.uri)
            if error_message is None:
                # update should be possible
                preparation_report.checkout = False
            else:
                # If robust ala continue-on-error, just error now and
                # it will be continued at a higher level
                if robust:
                    raise MultiProjectException("Update Failed of %s: %s" %
                                                (self.path, error_message))
                # prompt the user based on the error code
                if arg_mode == 'prompt':
                    print("Prepare updating %s (version %s) to %s" %
                          (self.uri, self.version, self.path))
                    mode = Ui.get_ui().prompt_del_abort_retry(error_message,
                                                              allow_skip=True)
                else:
                    mode = arg_mode
                if mode == 'backup':
                    preparation_report.backup = True
                    if backup_path is None:
                        print("Prepare updating %s (version %s) to %s" %
                              (self.uri, self.version, self.path))
                        preparation_report.backup_path = Ui.get_ui(
                        ).get_backup_path()
                    else:
                        preparation_report.backup_path = backup_path
                if mode == 'abort':
                    preparation_report.abort = True
                    preparation_report.error = error_message
                if mode == 'skip':
                    preparation_report.skip = True
                    preparation_report.error = error_message
                if mode == 'delete':
                    preparation_report.backup = False
        return preparation_report
Ejemplo n.º 2
0
    def prepare_install(self, backup_path=None, arg_mode='abort', robust=False):
        preparation_report = PreparationReport(self)
        present = self.detect_presence()
        if present or self.path_exists():
            # Directory exists see what we need to do
            error_message = None

            if not present:
                error_message = "Failed to detect %s presence at %s." % (
                    self.get_vcs_type_name(), self.path)
            else:
                cur_url = self._get_vcsc().get_url()
                if cur_url is not None:
                    # strip trailing slashes for #3269
                    cur_url = cur_url.rstrip('/')
                if not cur_url or cur_url != self.uri.rstrip('/'):
                    # local repositories get absolute pathnames
                    if not (os.path.isdir(self.uri) and
                            os.path.isdir(cur_url) and
                            samefile(cur_url, self.uri)):
                        if not self._get_vcsc().url_matches(cur_url, self.uri):
                            error_message = "Url %s does not match %s requested." % (
                                cur_url, self.uri)
            if error_message is None:
                # update should be possible
                preparation_report.checkout = False
            else:
                # If robust ala continue-on-error, just error now and
                # it will be continued at a higher level
                if robust:
                    raise MultiProjectException("Update Failed of %s: %s" % (
                            self.path, error_message))
                # prompt the user based on the error code
                if arg_mode == 'prompt':
                    print("Prepare updating %s (version %s) to %s" % (
                            self.uri, self.version, self.path))
                    mode = Ui.get_ui().prompt_del_abort_retry(error_message,
                                                              allow_skip=True)
                else:
                    mode = arg_mode
                if mode == 'backup':
                    preparation_report.backup = True
                    if backup_path is None:
                        print("Prepare updating %s (version %s) to %s" % (
                                self.uri, self.version, self.path))
                        preparation_report.backup_path = Ui.get_ui().get_backup_path()
                    else:
                        preparation_report.backup_path = backup_path
                if mode == 'abort':
                    preparation_report.abort = True
                    preparation_report.error = error_message
                if mode == 'skip':
                    preparation_report.skip = True
                    preparation_report.error = error_message
                if mode == 'delete':
                    preparation_report.backup = False
        return preparation_report
Ejemplo n.º 3
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)
Ejemplo n.º 4
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)