Esempio n. 1
0
    def __init__(self, *args, **kwargs):
        self.name = kwargs.pop('name')

        isolated = kwargs.pop("isolated", False)
        self.config = Configuration(isolated)

        assert self.name
        optparse.OptionParser.__init__(self, *args, **kwargs)
Esempio n. 2
0
    def __init__(self, *args, **kwargs):
        self.name = kwargs.pop('name')

        isolated = kwargs.pop("isolated", False)
        self.config = Configuration(isolated)

        assert self.name
        optparse.OptionParser.__init__(self, *args, **kwargs)
Esempio n. 3
0
    def run(self, options, args):
        handlers = {
            "list": self.list_values,
            "edit": self.open_in_editor,
            "get": self.get_name,
            "set": self.set_name_value,
            "unset": self.unset_name
        }

        # Determine action
        if not args or args[0] not in handlers:
            logger.error("Need an action ({}) to perform.".format(", ".join(
                sorted(handlers))))
            return ERROR

        action = args[0]

        # Determine which configuration files are to be loaded
        #    Depends on whether the command is modifying.
        try:
            load_only = self._determine_file(
                options,
                need_value=(action in ["get", "set", "unset", "edit"]))
        except PipError as e:
            logger.error(e.args[0])
            return ERROR

        # Load a new configuration
        self.configuration = Configuration(isolated=options.isolated_mode,
                                           load_only=load_only)
        self.configuration.load()

        # Error handling happens here, not in the action-handlers.
        try:
            handlers[action](options, args[1:])
        except PipError as e:
            logger.error(e.args[0])
            return ERROR

        return SUCCESS
Esempio n. 4
0
    def run(self, options, args):
        handlers = {
            "list": self.list_values,
            "edit": self.open_in_editor,
            "get": self.get_name,
            "set": self.set_name_value,
            "unset": self.unset_name
        }

        # Determine action
        if not args or args[0] not in handlers:
            logger.error("Need an action ({}) to perform.".format(
                ", ".join(sorted(handlers)))
            )
            return ERROR

        action = args[0]

        # Determine which configuration files are to be loaded
        #    Depends on whether the command is modifying.
        try:
            load_only = self._determine_file(
                options, need_value=(action in ["get", "set", "unset", "edit"])
            )
        except PipError as e:
            logger.error(e.args[0])
            return ERROR

        # Load a new configuration
        self.configuration = Configuration(
            isolated=options.isolated_mode, load_only=load_only
        )
        self.configuration.load()

        # Error handling happens here, not in the action-handlers.
        try:
            handlers[action](options, args[1:])
        except PipError as e:
            logger.error(e.args[0])
            return ERROR

        return SUCCESS
Esempio n. 5
0
class ConfigOptionParser(CustomOptionParser):
    """Custom option parser which updates its defaults by checking the
    configuration files and environmental variables"""

    isolated = False

    def __init__(self, *args, **kwargs):
        self.name = kwargs.pop('name')
        self.isolated = kwargs.pop("isolated", False)
        self.config = Configuration()
        assert self.name
        optparse.OptionParser.__init__(self, *args, **kwargs)

    def check_default(self, option, key, val):
        try:
            return option.check_value(key, val)
        except optparse.OptionValueError as exc:
            print("An error occurred during configuration: %s" % exc)
            sys.exit(3)

    def _update_defaults(self, defaults):
        """Updates the given defaults with values from the config files and
        the environ. Does a little special handling for certain types of
        options (lists)."""
        self.config.load_config_files(self.name, self.isolated)
        # 2. environmental variables
        if not self.isolated:
            self.config.load_environment_vars()

        # Accumulate complex default state.
        self.values = optparse.Values(self.defaults)
        late_eval = set()
        # Then set the options with those values
        for key, val in self.config.items():
            # ignore empty values
            if not val:
                continue

            # '--' because configuration supports only long names
            option = self.get_option('--' + key)

            # Ignore options not present in this parser. E.g. non-globals put
            # in [global] by users that want them to apply to all applicable
            # commands.
            if option is None:
                continue

            if option.action in ('store_true', 'store_false', 'count'):
                val = strtobool(val)
            elif option.action == 'append':
                val = val.split()
                val = [self.check_default(option, key, v) for v in val]
            elif option.action == 'callback':
                late_eval.add(option.dest)
                opt_str = option.get_opt_string()
                val = option.convert_value(opt_str, val)
                # From take_action
                args = option.callback_args or ()
                kwargs = option.callback_kwargs or {}
                option.callback(option, opt_str, val, self, *args, **kwargs)
            else:
                val = self.check_default(option, key, val)

            defaults[option.dest] = val

        for key in late_eval:
            defaults[key] = getattr(self.values, key)
        self.values = None
        return defaults

    def get_default_values(self):
        """Overriding to make updating the defaults after instantiation of
        the option parser possible, _update_defaults() does the dirty work."""
        if not self.process_default_values:
            # Old, pre-Optik 1.5 behaviour.
            return optparse.Values(self.defaults)

        defaults = self._update_defaults(self.defaults.copy())  # ours
        for option in self._get_all_options():
            default = defaults.get(option.dest)
            if isinstance(default, string_types):
                opt_str = option.get_opt_string()
                defaults[option.dest] = option.check_value(opt_str, default)
        return optparse.Values(defaults)

    def error(self, msg):
        self.print_usage(sys.stderr)
        self.exit(2, "%s\n" % msg)
Esempio n. 6
0
class ConfigOptionParser(CustomOptionParser):
    """Custom option parser which updates its defaults by checking the
    configuration files and environmental variables"""
    def __init__(self, *args, **kwargs):
        self.name = kwargs.pop('name')

        isolated = kwargs.pop("isolated", False)
        self.config = Configuration(isolated)

        assert self.name
        optparse.OptionParser.__init__(self, *args, **kwargs)

    def check_default(self, option, key, val):
        try:
            return option.check_value(key, val)
        except optparse.OptionValueError as exc:
            print("An error occurred during configuration: %s" % exc)
            sys.exit(3)

    def _update_defaults(self, defaults):
        """Updates the given defaults with values from the config files and
        the environ. Does a little special handling for certain types of
        options (lists)."""

        # Load the configuration
        self.config.load(self.name)

        # Accumulate complex default state.
        self.values = optparse.Values(self.defaults)
        late_eval = set()
        # Then set the options with those values
        for key, val in self.config.items():
            # ignore empty values
            if not val:
                continue

            # '--' because configuration supports only long names
            option = self.get_option('--' + key)

            # Ignore options not present in this parser. E.g. non-globals put
            # in [global] by users that want them to apply to all applicable
            # commands.
            if option is None:
                continue

            if option.action in ('store_true', 'store_false', 'count'):
                val = strtobool(val)
            elif option.action == 'append':
                val = val.split()
                val = [self.check_default(option, key, v) for v in val]
            elif option.action == 'callback':
                late_eval.add(option.dest)
                opt_str = option.get_opt_string()
                val = option.convert_value(opt_str, val)
                # From take_action
                args = option.callback_args or ()
                kwargs = option.callback_kwargs or {}
                option.callback(option, opt_str, val, self, *args, **kwargs)
            else:
                val = self.check_default(option, key, val)

            defaults[option.dest] = val

        for key in late_eval:
            defaults[key] = getattr(self.values, key)
        self.values = None
        return defaults

    def get_default_values(self):
        """Overriding to make updating the defaults after instantiation of
        the option parser possible, _update_defaults() does the dirty work."""
        if not self.process_default_values:
            # Old, pre-Optik 1.5 behaviour.
            return optparse.Values(self.defaults)

        defaults = self._update_defaults(self.defaults.copy())  # ours
        for option in self._get_all_options():
            default = defaults.get(option.dest)
            if isinstance(default, string_types):
                opt_str = option.get_opt_string()
                defaults[option.dest] = option.check_value(opt_str, default)
        return optparse.Values(defaults)

    def error(self, msg):
        self.print_usage(sys.stderr)
        self.exit(2, "%s\n" % msg)
Esempio n. 7
0
class ConfigurationCommand(Command):
    """Manage local and global configuration."""
    name = 'config'
    usage = """
        %prog [<file-option>] list
        %prog [<file-option>] [--editor <editor-path>] edit

        %prog [<file-option>] get name
        %prog [<file-option>] set name value
        %prog [<file-option>] unset name
    """

    summary = """
        Manage local and global configuration.

        Subcommands:

        list: List the active configuration (or from the file specified)
        edit: Edit the configuration file in an editor
        get: Get the value associated with name
        set: Set the name=value
        unset: Unset the value associated with name

        If none of --user, --global and --venv are passed, a virtual
        environment configuration file is used if one is active and the file
        exists. Otherwise, all modifications happen on the to the user file by
        default.
    """

    def __init__(self, *args, **kwargs):
        super(ConfigurationCommand, self).__init__(*args, **kwargs)

        self.configuration = None

        self.cmd_opts.add_option('--editor',
                                 dest='editor',
                                 action='store',
                                 default=None,
                                 help=('Editor to use to edit the file. Uses '
                                       '$EDITOR if not passed.'))

        self.cmd_opts.add_option(
            '--global',
            dest='global_file',
            action='store_true',
            default=False,
            help='Use the system-wide configuration file only')

        self.cmd_opts.add_option('--user',
                                 dest='user_file',
                                 action='store_true',
                                 default=False,
                                 help='Use the user configuration file only')

        self.cmd_opts.add_option(
            '--venv',
            dest='venv_file',
            action='store_true',
            default=False,
            help='Use the virtualenv configuration file only')

        self.parser.insert_option_group(0, self.cmd_opts)

    def run(self, options, args):
        handlers = {
            "list": self.list_values,
            "edit": self.open_in_editor,
            "get": self.get_name,
            "set": self.set_name_value,
            "unset": self.unset_name
        }

        # Determine action
        if not args or args[0] not in handlers:
            logger.error("Need an action ({}) to perform.".format(", ".join(
                sorted(handlers))))
            return ERROR

        action = args[0]

        # Determine which configuration files are to be loaded
        #    Depends on whether the command is modifying.
        try:
            load_only = self._determine_file(
                options,
                need_value=(action in ["get", "set", "unset", "edit"]))
        except PipError as e:
            logger.error(e.args[0])
            return ERROR

        # Load a new configuration
        self.configuration = Configuration(isolated=options.isolated_mode,
                                           load_only=load_only)
        self.configuration.load()

        # Error handling happens here, not in the action-handlers.
        try:
            handlers[action](options, args[1:])
        except PipError as e:
            logger.error(e.args[0])
            return ERROR

        return SUCCESS

    def _determine_file(self, options, need_value):
        file_options = {
            kinds.USER: options.user_file,
            kinds.GLOBAL: options.global_file,
            kinds.VENV: options.venv_file
        }

        if sum(file_options.values()) == 0:
            if not need_value:
                return None
            # Default to user, unless there's a virtualenv file.
            elif os.path.exists(venv_config_file):
                return kinds.VENV
            else:
                return kinds.USER
        elif sum(file_options.values()) == 1:
            # There's probably a better expression for this.
            return [key for key in file_options if file_options[key]][0]

        raise PipError("Need exactly one file to operate upon "
                       "(--user, --venv, --global) to perform.")

    def list_values(self, options, args):
        self._get_n_args(args, "list", n=0)

        for key, value in sorted(self.configuration.items()):
            logger.info("%s=%r", key, value)

    def get_name(self, options, args):
        key = self._get_n_args(args, "get [name]", n=1)
        value = self.configuration.get_value(key)

        logger.info("%s", value)

    def set_name_value(self, options, args):
        key, value = self._get_n_args(args, "set [name] [value]", n=2)
        self.configuration.set_value(key, value)

        self._save_configuration()

    def unset_name(self, options, args):
        key = self._get_n_args(args, "unset [name]", n=1)
        self.configuration.unset_value(key)

        self._save_configuration()

    def open_in_editor(self, options, args):
        editor = self._determine_editor(options)

        fname = self.configuration.get_file_to_edit()
        if fname is None:
            raise PipError("Could not determine appropriate file.")

        try:
            subprocess.check_call([editor, fname])
        except subprocess.CalledProcessError as e:
            raise PipError("Editor Subprocess exited with exit code {}".format(
                e.returncode))

    def _get_n_args(self, args, example, n):
        """Helper to make sure the command got the right number of arguments
        """
        if len(args) != n:
            msg = ('Got unexpected number of arguments, expected {}. '
                   '(example: "{} config {}")').format(n, get_prog(), example)
            raise PipError(msg)

        if n == 1:
            return args[0]
        else:
            return args

    def _save_configuration(self):
        # We successfully ran a modifying command. Need to save the
        # configuration.
        try:
            self.configuration.save()
        except Exception:
            logger.error(
                "Unable to save configuration. Please report this as a bug.",
                exc_info=1)
            raise PipError("Internal Error.")

    def _determine_editor(self, options):
        if options.editor is not None:
            return options.editor
        elif "VISUAL" in os.environ:
            return os.environ["VISUAL"]
        elif "EDITOR" in os.environ:
            return os.environ["EDITOR"]
        else:
            raise PipError("Could not determine editor to use.")
Esempio n. 8
0
class ConfigurationCommand(Command):
    """Manage local and global configuration."""
    name = 'config'
    usage = """
        %prog [<file-option>] list
        %prog [<file-option>] [--editor <editor-path>] edit

        %prog [<file-option>] get name
        %prog [<file-option>] set name value
        %prog [<file-option>] unset name
    """

    summary = """
        Manage local and global configuration.

        Subcommands:

        list: List the active configuration (or from the file specified)
        edit: Edit the configuration file in an editor
        get: Get the value associated with name
        set: Set the name=value
        unset: Unset the value associated with name

        If none of --user, --global and --venv are passed, a virtual
        environment configuration file is used if one is active and the file
        exists. Otherwise, all modifications happen on the to the user file by
        default.
    """

    def __init__(self, *args, **kwargs):
        super(ConfigurationCommand, self).__init__(*args, **kwargs)

        self.configuration = None

        self.cmd_opts.add_option(
            '--editor',
            dest='editor',
            action='store',
            default=None,
            help=(
                'Editor to use to edit the file. Uses VISUAL or EDITOR '
                'environment variables if not provided.'
            )
        )

        self.cmd_opts.add_option(
            '--global',
            dest='global_file',
            action='store_true',
            default=False,
            help='Use the system-wide configuration file only'
        )

        self.cmd_opts.add_option(
            '--user',
            dest='user_file',
            action='store_true',
            default=False,
            help='Use the user configuration file only'
        )

        self.cmd_opts.add_option(
            '--venv',
            dest='venv_file',
            action='store_true',
            default=False,
            help='Use the virtualenv configuration file only'
        )

        self.parser.insert_option_group(0, self.cmd_opts)

    def run(self, options, args):
        handlers = {
            "list": self.list_values,
            "edit": self.open_in_editor,
            "get": self.get_name,
            "set": self.set_name_value,
            "unset": self.unset_name
        }

        # Determine action
        if not args or args[0] not in handlers:
            logger.error("Need an action ({}) to perform.".format(
                ", ".join(sorted(handlers)))
            )
            return ERROR

        action = args[0]

        # Determine which configuration files are to be loaded
        #    Depends on whether the command is modifying.
        try:
            load_only = self._determine_file(
                options, need_value=(action in ["get", "set", "unset", "edit"])
            )
        except PipError as e:
            logger.error(e.args[0])
            return ERROR

        # Load a new configuration
        self.configuration = Configuration(
            isolated=options.isolated_mode, load_only=load_only
        )
        self.configuration.load()

        # Error handling happens here, not in the action-handlers.
        try:
            handlers[action](options, args[1:])
        except PipError as e:
            logger.error(e.args[0])
            return ERROR

        return SUCCESS

    def _determine_file(self, options, need_value):
        file_options = {
            kinds.USER: options.user_file,
            kinds.GLOBAL: options.global_file,
            kinds.VENV: options.venv_file
        }

        if sum(file_options.values()) == 0:
            if not need_value:
                return None
            # Default to user, unless there's a virtualenv file.
            elif os.path.exists(venv_config_file):
                return kinds.VENV
            else:
                return kinds.USER
        elif sum(file_options.values()) == 1:
            # There's probably a better expression for this.
            return [key for key in file_options if file_options[key]][0]

        raise PipError(
            "Need exactly one file to operate upon "
            "(--user, --venv, --global) to perform."
        )

    def list_values(self, options, args):
        self._get_n_args(args, "list", n=0)

        for key, value in sorted(self.configuration.items()):
            logger.info("%s=%r", key, value)

    def get_name(self, options, args):
        key = self._get_n_args(args, "get [name]", n=1)
        value = self.configuration.get_value(key)

        logger.info("%s", value)

    def set_name_value(self, options, args):
        key, value = self._get_n_args(args, "set [name] [value]", n=2)
        self.configuration.set_value(key, value)

        self._save_configuration()

    def unset_name(self, options, args):
        key = self._get_n_args(args, "unset [name]", n=1)
        self.configuration.unset_value(key)

        self._save_configuration()

    def open_in_editor(self, options, args):
        editor = self._determine_editor(options)

        fname = self.configuration.get_file_to_edit()
        if fname is None:
            raise PipError("Could not determine appropriate file.")

        try:
            subprocess.check_call([editor, fname])
        except subprocess.CalledProcessError as e:
            raise PipError(
                "Editor Subprocess exited with exit code {}"
                .format(e.returncode)
            )

    def _get_n_args(self, args, example, n):
        """Helper to make sure the command got the right number of arguments
        """
        if len(args) != n:
            msg = (
                'Got unexpected number of arguments, expected {}. '
                '(example: "{} config {}")'
            ).format(n, get_prog(), example)
            raise PipError(msg)

        if n == 1:
            return args[0]
        else:
            return args

    def _save_configuration(self):
        # We successfully ran a modifying command. Need to save the
        # configuration.
        try:
            self.configuration.save()
        except Exception:
            logger.error(
                "Unable to save configuration. Please report this as a bug.",
                exc_info=1
            )
            raise PipError("Internal Error.")

    def _determine_editor(self, options):
        if options.editor is not None:
            return options.editor
        elif "VISUAL" in os.environ:
            return os.environ["VISUAL"]
        elif "EDITOR" in os.environ:
            return os.environ["EDITOR"]
        else:
            raise PipError("Could not determine editor to use.")