示例#1
0
def __set(args):
    env_var = create_environment_variable(args.VARIABLE)
    if env_var is None:
        raise ValueError("This environment variable cannot or should not "
                         "be managed.")
    env_var.value = args.VALUE
    get_current_shell().set_env_var(env_var)
示例#2
0
def __remove(args):
    env_var = create_environment_variable(args.VARIABLE)
    if env_var is None:
        raise ValueError("This environment variable cannot or should not "
                         "be managed.")
    if not isinstance(env_var, ArrayEnvVar):
        raise NotImplementedError("'add' and 'remove' operations are only "
                                  "applicable to array-like environmental "
                                  "variables.")

    for val in args.VALUE:
        env_var.remove_value(val)
    get_current_shell().set_env_var(env_var)
示例#3
0
def __create_track_subcommand(main_parser):
    parser = main_parser.add_parser(
        name='track',
        description="Change a variable's tracking status. A tracked "
                    "variable's value changes is reflected in Envprobe "
                    "saves.",
        help="Change a variable's tracking status."
    )

    parser.add_argument(
        'VARIABLE',
        type=str,
        help="The variable which is to be tracked, e.g. PATH."
    )

    if get_current_shell():
        # Only allow the changing the non-global configuration if there
        # is a shell that is loaded.
        parser.add_argument('-g', '--global',
                            dest='global_scope',
                            action='store_true',
                            help="Save the tracking status into your user "
                                 "configuration, not to the settings of the "
                                 "current Shell.")

    mgroup = parser.add_argument_group('additional tracking settings')
    mgroup = mgroup.add_mutually_exclusive_group()

    mgroup.add_argument('-i', '--ignore',
                        action='store_true',
                        help="Set the variable to be ignored instead of "
                             "tracked. An ignored variable's value changes "
                             "are not reflected in Envprove saves.")

    mgroup.add_argument('-d', '--default',
                        action='store_true',
                        help="Remove both the track and ignore status of "
                             "VARIABLE. After this, the user's or shell's "
                             "(depending on whether '-g' was specified) "
                             "default tracking behaviour will be "
                             "applicable.")

    parser.set_defaults(func=__track)
    if not get_current_shell():
        # If a shell could not be loaded, default to changing the global
        # state.
        parser.set_defaults(global_scope=True)
    global_config.REGISTERED_COMMANDS.append('track')
示例#4
0
def get_common_epilogue_or_die():
    epilogue = None
    shell = get_current_shell()

    if len(sys.argv) == 1 or \
            (len(sys.argv) == 2 and sys.argv[1] in ['-h', '--help']):
        if shell is None:
            epilogue = "You are currently using `envprobe` in a shell that " \
                       "does not have it enabled. Please refer to the "      \
                       "README on how to enable Envprobe."

            if len(sys.argv) == 1:
                print(
                    "To see what commands `envprobe` can do, specify "
                    "'--help'.",
                    file=sys.stderr)
        elif shell is False:
            epilogue = "You are currently using an unknown shell, but " \
                       "your environment claims Envprobe is enabled. "  \
                       "Stop hacking your variables! :)"
        else:
            epilogue = "You are currently using a '{0}' shell, and Envprobe " \
                       "is enabled!".format(shell.shell_type)

            if int(os.environ.get('_ENVPROBE', 0)) != 1:
                # If the user is not running the command through an alias,
                # present an error. We don't want users to randomly run
                # envprobe if it is enabled and set up.
                print("You are in an environment where `envprobe` is "
                      "enabled, but you used the command '{0}' to run "
                      "Envprobe, instead of `envprobe`.".format(sys.argv[0]),
                      file=sys.stderr)
                sys.exit(2)

    return epilogue
示例#5
0
def __track(args):
    tracking = TrackingOverlay(get_current_shell())
    if args.ignore:
        tracking.ignore(args.VARIABLE, args.global_scope)
    elif args.default:
        tracking.make_default(args.VARIABLE, args.global_scope)
    else:
        tracking.track(args.VARIABLE, args.global_scope)
    tracking.flush(args.global_scope)
示例#6
0
def __add(args):
    env_var = create_environment_variable(args.VARIABLE)
    if env_var is None:
        raise ValueError("This environment variable cannot or should not "
                         "be managed.")
    if not isinstance(env_var, ArrayEnvVar):
        raise NotImplementedError("'add' and 'remove' operations are only "
                                  "applicable to array-like environmental "
                                  "variables.")

    for val in args.VALUE:
        env_var.insert_at(args.position, val)
        if args.position >= 0:
            # If the arguments are appended with a positive index, we insert
            # the values in order. If the arguments are inserted at a negative
            # index, the position must not be modified, because the arguments
            # get shifted with the insert.
            args.position += 1
    get_current_shell().set_env_var(env_var)
示例#7
0
def create_subcommand_parser(main_parser):
    if not get_current_shell():
        return

    # Only expose these commands of this module if the user is running
    # envprobe in a known valid shell.
    __create_get_subcommand(main_parser)
    __create_set_subcommand(main_parser)
    __create_add_subcommand(main_parser)
    __create_remove_subcommand(main_parser)
    __create_undefine_subcommand(main_parser)
示例#8
0
def create_subcommand_parser(main_parser):
    __create_list_subcommand(main_parser)

    if get_current_shell():
        # Only expose these commands of this module if the user is running
        # envprobe in a known valid shell.
        __create_load_subcommand(main_parser)
        __create_diff_subcommand(main_parser)
        __create_save_subcommand(main_parser)

    __create_delete_subcommand(main_parser)
示例#9
0
def __create_default_tracking_subcommand(main_parser):
    parser = main_parser.add_parser(
        name='default-tracking',
        description="Change the default tracking behaviour of variables.",
        help="Change the default tracking behaviour of variables."
    )

    ngroup = parser.add_mutually_exclusive_group(required=True)

    ngroup.add_argument('-t', '--track', '-e', '--enable',
                        dest='track',
                        action='store_true',
                        help="Set the default behaviour to track all "
                             "(not explicitly ignored) variables.")

    ngroup.add_argument('-i', '--ignore', '-d', '--disable',
                        dest='ignore',
                        action='store_true',
                        help="Set the default behaviour to ignore all "
                             "(not explicitly tracked) variables.")

    if get_current_shell():
        # Only allow the changing the non-global configuration if there
        # is a shell that is loaded.
        parser.add_argument('-g', '--global',
                            dest='global_scope',
                            action='store_true',
                            help="Save the tracking status into your user "
                                 "configuration, not to the settings of the "
                                 "current Shell.")

    parser.set_defaults(func=__change_default)
    if not get_current_shell():
        # If a shell could not be loaded, default to changing the global
        # state.
        parser.set_defaults(global_scope=True)
    global_config.REGISTERED_COMMANDS.append('default-tracking')
示例#10
0
def __undefine(args):
    env_var = create_environment_variable(args.VARIABLE)
    if env_var is None:
        raise ValueError("This environment variable cannot or should not "
                         "be managed.")
    get_current_shell().undefine_env_var(env_var)
示例#11
0
def __load(args):
    def bool_prompt():
        response = False
        user_input = input("Apply this change? (y/N) ").lower()
        if user_input == 'y' or user_input == 'yes':
            response = True
        return response

    shell = get_current_shell()
    tracking = TrackingOverlay(shell)
    env = environment.Environment(shell)
    var_names = __clean_variable_list(args.variable)

    with Save(args.name, read_only=True) as save:
        if save is None:
            print("Error! The save '%s' cannot be opened, perhaps it is "
                  "being modified by another process!" % args.name,
                  file=sys.stderr)
            return
        if len(save) == 0:
            print("The save '%s' does not exist!" % args.name)

        for variable_name in save:
            if var_names and variable_name not in var_names:
                continue
            if not var_names and not tracking.is_tracked(variable_name):
                continue

            # The 'saved' variable is used to update the environment's
            # "saved" state so the loaded change won't be a difference.
            variable_saved = create_environment_variable(variable_name,
                                                         env.saved_env)
            # The 'shell' variable is used to update the actual value the
            # user experiences in the shell. (This distinction is used
            # because there might be changes in the current shell which were
            # never "saved" into the state file or a save.)
            variable_shell = create_environment_variable(variable_name,
                                                         env.current_env)

            if save[variable_name] == Save.UNSET:
                if args.patch or args.dry_run:
                    print("Variable \"%s\" will be unset (from value: '%s')"
                          % (variable_name, variable_shell.value))

                if not args.dry_run and (not args.patch or bool_prompt()):
                    env.apply_change(variable_saved, remove=True)
                    shell.undefine_env_var(variable_shell)

                continue

            # Read the change from the save and apply it to the variable.
            value = save[variable_name]
            current_value = variable_shell.value
            if not isinstance(value, dict):
                # Single variable changes contain the NEW value in the save.
                # For the sake of user communication here, regard a list
                # containing a single string as a single string.
                if isinstance(value, list) and len(value) == 1:
                    value = value[0]
                if isinstance(current_value, list) and \
                        len(current_value) == 1:
                    current_value = current_value[0]

                if args.patch or args.dry_run:
                    if variable_name not in env.current_env:
                        print("New variable \"%s\" will be set to value: "
                              "'%s'." % (variable_name, value))
                    elif value == current_value:
                        # Don't change something that already has the new
                        # value.
                        continue
                    else:
                        print("Variable \"%s\" will be changed to value: "
                              "'%s' (previous value was: '%s')"
                              % (variable_name, value, current_value))

                if not args.dry_run and (not args.patch or bool_prompt()):
                    variable_saved.value = value
                    variable_shell.value = value
                    env.apply_change(variable_saved)
                    shell.set_env_var(variable_shell)
            else:
                # Complex changes are represented in a dict.
                if not isinstance(variable_saved, ArrayEnvVar) or \
                        not isinstance(variable_saved, ArrayEnvVar):
                    raise TypeError("Cannot apply a complex add/remove "
                                    "change to a variable which is not an "
                                    "array!")

                insert_idx = 0
                for add in value['add']:
                    if add in current_value:
                        # Ignore adding something that is already there.
                        continue

                    if args.patch or args.dry_run:
                        print("In variable \"%s\", the value (component) "
                              "'%s' will be added."
                              % (variable_name, add))
                    if not args.dry_run and (not args.patch or bool_prompt()):
                        variable_saved.insert_at(insert_idx, add)
                        variable_shell.insert_at(insert_idx, add)
                        insert_idx += 1

                        env.apply_change(variable_saved)
                        shell.set_env_var(variable_shell)

                for remove in value['remove']:
                    if remove not in current_value:
                        # Ignore removing something that is not there.
                        continue

                    if args.patch or args.dry_run:
                        print("In variable \"%s\", the value (component) "
                              "'%s' will be removed."
                              % (variable_name, remove))
                    if not args.dry_run and (not args.patch or bool_prompt()):
                        variable_saved.remove_value(remove)
                        variable_shell.remove_value(remove)
                        env.apply_change(variable_saved)
                        shell.set_env_var(variable_shell)

    # After loading, the user's "known" environment has changed, so it has
    # to be flushed.
    env.flush()
示例#12
0
def __diff(args):
    TYPES = environment.VariableDifferenceType
    shell = get_current_shell()
    tracking = TrackingOverlay(shell)
    env = environment.Environment(shell)
    diffs = env.diff()
    var_names = __clean_variable_list(args.variable)

    for variable_name in sorted(list(diffs.keys())):
        if var_names and variable_name not in var_names:
            continue
        if not var_names and not tracking.is_tracked(variable_name):
            continue

        change = diffs[variable_name]
        diff = change.differences
        if args.type == 'normal':
            kind = diffs[variable_name].type
            if kind == TYPES.ADDED:
                kind = '+ Added:'
            elif kind == TYPES.REMOVED:
                kind = '- Removed:'
            elif kind == TYPES.CHANGED:
                kind = '! Modified:'

            print("%s %s" % (kind.ljust(11), variable_name))
            if change.is_new() or change.is_unset():
                # If only a remove or an addition took place, show the
                # new value.
                print("     value: %s" % diff[0][1])
            elif change.is_simple_change():
                # If the difference is exactly a single change from a
                # value to another, just show the change.
                print("      from: %s\n        to: %s"
                      % (diff[1][1], diff[0][1]))
            else:
                for action, value in diff:
                    if action == ' ':
                        # Do not show "keep" or "unchanged" lines.
                        continue
                    elif action == '+':
                        print("      added %s" % value)
                    elif action == '-':
                        print("    removed %s" % value)

            print()
        elif args.type == 'unified':
            old_name, new_name = variable_name, variable_name
            old_start, old_count, new_start, new_count = \
                1, len(diff), 1, len(diff)

            if diffs[variable_name].type == TYPES.ADDED:
                old_name = '(new variable)'
                old_start, old_count = 0, 0
            elif diffs[variable_name].type == TYPES.REMOVED:
                new_name = '(variable unset)'
                new_start, new_count = 0, 0

            print("--- %s" % old_name)
            print("+++ %s" % new_name)
            print("@@ -%d,%d +%d,%d @@"
                  % (old_start, old_count, new_start, new_count))
            for difference in diff:
                print("%s %s" % difference)
            print()
示例#13
0
def __save(args):
    def bool_prompt():
        response = False
        user_input = input("Save this change? (y/N) ").lower()
        if user_input == 'y' or user_input == 'yes':
            response = True
        return response

    shell = get_current_shell()
    tracking = TrackingOverlay(shell)
    env = environment.Environment(shell)
    diffs = env.diff()
    var_names = __clean_variable_list(args.variable)

    with Save(args.name, read_only=False) as save:
        if save is None:
            print("Error! The save '%s' cannot be opened, perhaps it is "
                  "being modified by another process!" % args.name,
                  file=sys.stderr)
            return

        for variable_name in sorted(list(diffs.keys())):
            if var_names and variable_name not in var_names:
                continue
            if not var_names and not tracking.is_tracked(variable_name):
                continue

            change = diffs[variable_name]
            diff = change.differences

            variable_saved = create_environment_variable(variable_name,
                                                         env.saved_env)

            # First, transform the change to something that can later be
            # applied.
            if change.is_new():
                # In case a new variable was introduced, we only care
                # about the new, set value.
                if args.patch:
                    print("Variable \"%s\" set to value: '%s'."
                          % (variable_name, change.new_value))

                if not args.patch or bool_prompt():
                    save[variable_name] = change.new_value
                    variable_saved.value = change.new_value
                    env.apply_change(variable_saved)
            elif change.is_unset():
                # If a variable was removed from the environment, it
                # usually doesn't matter what its value was, only the fact
                # that it was removed.
                if args.patch:
                    print("Variable \"%s\" unset (from value: '%s')"
                          % (variable_name, change.old_value))

                if not args.patch or bool_prompt():
                    del save[variable_name]
                    env.apply_change(variable_saved, remove=True)
            elif change.is_simple_change():
                # If the change was a simple change that changed a
                # variable from something to something we are still only
                # interested in the new value. (This is environment
                # variables, not Git!)
                if args.patch:
                    print("Variable \"%s\" changed to value: '%s' "
                          "(previous value was: '%s')"
                          % (variable_name,
                             change.new_value, change.old_value))

                if not args.patch or bool_prompt():
                    save[variable_name] = change.new_value
                    variable_saved.value = change.new_value
                    env.apply_change(variable_saved)
            else:
                if not isinstance(variable_saved, ArrayEnvVar) or \
                        not isinstance(variable_saved, ArrayEnvVar):
                    raise TypeError("Cannot apply a complex add/remove "
                                    "change to a variable which is not an "
                                    "array!")

                # For complex changes, such as removal and addition of
                # multiple PATHs, both differences must be saved. This
                # ensures that if a user's particular save depends on
                # something that's usually seen is to not be seen, we can
                # handle it.
                # (In most cases, people only append new values to their
                # various PATHs...)
                save[variable_name] = {'add': [],
                                       'remove': []}

                for mode, value in diff:
                    key = None
                    passive = None
                    if mode == ' ':
                        # Ignore unchanged values.
                        continue
                    elif mode == '+':
                        key = 'add'
                        passive = "added"
                    elif mode == '-':
                        key = 'remove'
                        passive = "removed"

                    if args.patch:
                        print("In variable \"%s\", the value (component) "
                              "'%s' was %s."
                              % (variable_name, value, passive))
                    if not args.patch or bool_prompt():
                        save[variable_name][key].append(value)

                        if key == 'add':
                            variable_saved.insert_at(0, value)
                        elif key == 'remove':
                            variable_saved.remove_value(value)
                        env.apply_change(variable_saved)

        # Write the named state save file to the disk.
        save.flush()

        # Write the changed current environment's now saved changes to the
        # shell's known state, so changes saved here are no longer shown as
        # diffs.
        env.flush()
示例#14
0
def __change_default(args):
    tracking = TrackingOverlay(get_current_shell())
    tracking.set_default(args.track, args.global_scope)
    tracking.flush(args.global_scope)