def pretty_packages(self, fields=None, max_width=0):
     if fields == None:
         fields = self.default_package_fields
     return rst_table(fields,
                      [package.metadata for package in self.packages],
                      max_width=max_width)
Exemple #2
0
def rollback_menu(remote_repos=None, interactive=True,
    dry_run=False, term_width=0, show_all=False, num_entries=5,
    show_dates=False):
    """
    Show a menu with possible rollback options and perform the appropriate
    action based on the user's input.
    """
    # Create a list of metadata for the possible rollback dates so that we
    # can create an auto-generated user selection layout.  Based on the
    # command-line options, we can limit the list of rollback points that
    # are shown.  If the ensetuptools.cache doesn't exist, let the user know
    # why they can not do a rollback.
    cached_states = retrieve_states()
    if not cached_states:
        print ("A rollback can not be performed because there are "
            "no cached rollback points.")
        return
    if not show_all:
        cached_states = cached_states[:num_entries]
    metadata = []
    local_time = time.localtime()
    for i, state in enumerate(cached_states):
        # Create a date display from the difference between the timestamp of
        # the rollback point and the current time.  The difference we retrieve
        # is the time sine the epoch (i.e. January 1, 1970), so we make our
        # calculations from that.
        timestamp = state[0]
        time_tuple = time.strptime(timestamp, "%Y%m%d%H%M%S")
        date_display = date_display_diff(local_time, time_tuple)

        # If the user specified to display the full date/timestamp with the
        # rollback points, then tack it onto the simple display.
        if show_dates:
            date_display = "%s (%s)" % (date_display,
                                        time.strftime("%Y/%m/%d %H:%M:%S",
                                                      time_tuple))

        # Find the differences between two rollback points (i.e. packages
        # added, removed, or modified) and calculate a nice diff that can
        # be displayed in the table.
        # We need to stop calculating these diffs once we reach the last
        # item though because there are no entries after it.
        option_diff = ""
        if i < len(cached_states)-1:
            project_list_1 = cached_states[i][1]
            project_list_2 = cached_states[i+1][1]
            diff_list_1 = [project for project in project_list_1
                           if not project in project_list_2]
            diff_list_2 = [project for project in project_list_2
                           if not project in project_list_1]
            if len(diff_list_1) == 0 and len(diff_list_2) == 0:
                option_diff = "  There are no changes between these points."
            else:
                added = []
                modified = []
                deactivated = []
                for project in diff_list_1:
                    (project_name_1,
                     project_version_1) = parse_project_str(project)
                    found = False

                    for project2 in diff_list_2:
                        (project_name_2,
                         project_version_2) = parse_project_str(project2)
                        if project_name_1 == project_name_2:
                            found = True
                            modified.append("%s-%s to %s" % (
                                    project_name_1, project_version_2,
                                project_version_1))
                            break

                    if not found:
                        added.append("%s-%s" % (project_name_1,
                                                project_version_1))
                for project2 in diff_list_2:
                    (project_name_2,
                     project_version_2) = parse_project_str(project2)
                    found = False
                    for project in diff_list_1:
                        (project_name_1,
                         project_version_1) = parse_project_str(project)
                        if project_name_2 == project_name_1:
                            found = True
                            break

                    if not found:
                        deactivated.append("%s-%s" % (project_name_2,
                                                      project_version_2))
                if len(added) > 0:
                    option_diff += "  [A] %s" % added[0]
                    for add_str in added[1:]:
                        option_diff += "\n\t      %s" % add_str
                    if len(modified) > 0 or len(deactivated) > 0:
                        option_diff += "\n\t"
                if len(modified) > 0:
                    option_diff += "  [M] %s" % modified[0]
                    for mod_str in modified[1:]:
                        option_diff += "\n\t      %s" % mod_str
                    if len(deactivated) > 0:
                        option_diff += "\n\t"
                if len(deactivated) > 0:
                    option_diff += "  [D] %s" % deactivated[0]
                    for deac_str in deactivated[1:]:
                        option_diff += "\n\t      %s" % deac_str

        # Set the 'date' metadata according to the date display and
        # the differene between rollback points.
        metadata.append({"date": date_display + "\n\t" + option_diff})

    # If a user selects to view more information about a specific rollback
    # point, keep prompting the user to choose a rollback point after
    # displaying that information.
    while True:
        selection = user_select(["date"],
            metadata, ("Select a restore point to rollback your "
            "environment to.  For more information about a "
            "specific rollback point, type the option number "
            "followed by a question mark.  Use '0' to cancel "
            "rollback:  "), default="0", extra_char="?",
            max_width=term_width)
        if not selection.endswith("?"):
            break
        else:
            option = int(selection.split('?')[0])-1
            state = cached_states[option]
            timestamp = state[0]
            time_tuple = time.strptime(timestamp, "%Y%m%d%H%M%S")
            date_display = time.strftime("%Y/%m/%d %H:%M:%S", time_tuple)
            print "Active Project State on %s:" % date_display
            state_data=[]
            project_list = state[1]
            for project in project_list:
                (project_name, project_version) = parse_project_str(project)
                state_data.append({"project_name": project_name,
                    "version": project_version})
            msg = rst_table(["project_name", "version"],
                state_data, sorted=False, max_width=term_width)
            msg += "\n\n"
            print msg

    # If the user selected option '0', then there's nothing to do.
    if selection == '0':
        return

    # Now that the user has selected a rollback point, perform the action
    # to rollback to that state.  Once the rollback has been completed
    # successfully, let the user know.
    state_index = int(selection)-1
    project_list = cached_states[state_index][1]
    rollback_state(project_list, remote_repos, interactive, dry_run, term_width)
    timestamp = cached_states[state_index][0]
    time_tuple = time.strptime(timestamp, "%Y%m%d%H%M%S")
    date_display = time.strftime("%Y/%m/%d %H:%M:%S", time_tuple)
    print "\nSystem successfully rolled back to state on: %s" % date_display