def coerce_location(value, **options):
    """
    Coerce a string to a :class:`Location` object.

    :param value: The value to coerce (a string or :class:`Location` object).
    :param options: Any keyword arguments are passed on to
                    :func:`~executor.contexts.create_context()`.
    :returns: A :class:`Location` object.
    """
    # Location objects pass through untouched.
    if not isinstance(value, Location):
        # Other values are expected to be strings.
        if not isinstance(value, string_types):
            msg = "Expected Location object or string, got %s instead!"
            raise ValueError(msg % type(value))
        # Try to parse a remote location.
        ssh_alias, _, directory = value.partition(':')
        if ssh_alias and directory and '/' not in ssh_alias:
            options['ssh_alias'] = ssh_alias
        else:
            directory = value
        # Create the location object.
        value = Location(
            context=create_context(**options),
            directory=parse_path(directory),
        )
    return value
Exemplo n.º 2
0
def coerce_location(value, **options):
    """
    Coerce a string to a :class:`Location` object.

    :param value: The value to coerce (a string or :class:`Location` object).
    :param options: Any keyword arguments are passed on to
                    :func:`~executor.contexts.create_context()`.
    :returns: A :class:`Location` object.
    """
    # Location objects pass through untouched.
    if not isinstance(value, Location):
        # Other values are expected to be strings.
        if not isinstance(value, string_types):
            msg = "Expected Location object or string, got %s instead!"
            raise ValueError(msg % type(value))
        # Try to parse a remote location.
        ssh_alias, _, directory = value.partition(':')
        if ssh_alias and directory and '/' not in ssh_alias:
            options['ssh_alias'] = ssh_alias
        else:
            directory = value
        # Create the location object.
        value = Location(
            context=create_context(**options),
            directory=parse_path(directory),
        )
    return value
Exemplo n.º 3
0
    def store_host_keys(self, pre_server, post_server):
        """
        Store the SSH host keys in the configuration.

        :param pre_server: The :class:`ServerDetails` object from :func:`wait_for_pre_boot()`.
        :param post_server: The :class:`ServerDetails` object from :func:`wait_for_post_boot()`.
        """
        if self.config_section:
            items = (('pre-boot-host-keys', pre_server),
                     ('post-boot-host-keys', post_server))
            options = dict((name, '\n'.join(sorted(server.host_keys)))
                           for name, server in items)
            if not all(
                    self.config.get(name) == value
                    for name, value in options.items()):
                logger.info("Storing SSH host keys in %s ..", HOST_KEYS_FILE)
                filename = parse_path(HOST_KEYS_FILE)
                directory = os.path.dirname(filename)
                if not os.path.isdir(directory):
                    os.makedirs(directory)
                parser = configparser.RawConfigParser()
                parser.read(filename)
                if not parser.has_section(self.config_section):
                    parser.add_section(self.config_section)
                for name, value in options.items():
                    parser.set(self.config_section, name, value)
                with open(filename, 'w') as handle:
                    parser.write(handle)
        else:
            logger.verbose(
                "Not storing SSH host keys (no configuration available).")
Exemplo n.º 4
0
def prepare_config(config):
    """Prepare the ``~/.vcs-repo-mgr.ini`` configuration file."""
    with open(parse_path(USER_CONFIG_FILE), 'w') as handle:
        for name, options in config.items():
            handle.write('[%s]\n' % name)
            for key, value in options.items():
                handle.write('%s = %s\n' % (key, value))
Exemplo n.º 5
0
 def directory(self, value):
     """Normalize the value of :attr:`directory` when it's set."""
     # Normalize the value of `directory'.
     set_property(self, "directory", parse_path(value))
     # Clear the computed values of `context' and `entries'.
     clear_property(self, "context")
     clear_property(self, "entries")
Exemplo n.º 6
0
 def pre_boot(self):
     """A connection profile for the pre-boot environment (a :class:`ConnectionProfile` object)."""
     if self.config_section or 'pre-boot' in self.config:
         return ConnectionProfile(
             expression=self.config.get('pre-boot', self.config_section),
             identity_file=(parse_path(self.config['identity-file'])
                            if 'identity-file' in self.config else None),
             username='******',
         )
Exemplo n.º 7
0
    def data_directory(self):
        """
        The pathname of the directory where data files are stored (a string).

        The environment variable ``$CHAT_ARCHIVE_DIRECTORY`` can be used to set
        the value of this property. When the environment variable isn't set the
        default value ``~/.local/share/chat-archive`` is used (where ``~`` is
        expanded to the profile directory of the current user).
        """
        return parse_path(os.environ.get("CHAT_ARCHIVE_DIRECTORY", "~/.local/share/chat-archive"))
Exemplo n.º 8
0
def initialize_gnupg():
    """
    Make sure the ``~/.gnupg`` directory exists.

    Older versions of GPG can/will fail when the ``~/.gnupg`` directory doesn't
    exist (e.g. in a newly created chroot). GPG itself creates the directory
    after noticing that it's missing, but then still fails! Later runs work
    fine however. To avoid this problem we make sure ``~/.gnupg`` exists before
    we run GPG.
    """
    makedirs(parse_path('~/.gnupg'))
def load_config_file(configuration_file=None):
    """
    Load a configuration file with backup directories and rotation schemes.

    :param configuration_file: Override the pathname of the configuration file
                               to load (a string or :data:`None`).
    :returns: A generator of tuples with four values each:

              1. An execution context created using :mod:`executor.contexts`.
              2. The pathname of a directory with backups (a string).
              3. A dictionary with the rotation scheme.
              4. A dictionary with additional options.
    :raises: :exc:`~exceptions.ValueError` when `configuration_file` is given
             but doesn't exist or can't be loaded.

    When `configuration_file` isn't given :data:`LOCAL_CONFIG_FILE` and
    :data:`GLOBAL_CONFIG_FILE` are checked and the first configuration file
    that exists is loaded. This function is used by :class:`RotateBackups` to
    discover user defined rotation schemes and by :mod:`rotate_backups.cli` to
    discover directories for which backup rotation is configured.
    """
    parser = configparser.RawConfigParser()
    if configuration_file:
        logger.verbose("Reading configuration file %s ..",
                       format_path(configuration_file))
        loaded_files = parser.read(configuration_file)
        if len(loaded_files) == 0:
            msg = "Failed to read configuration file! (%s)"
            raise ValueError(msg % configuration_file)
    else:
        for config_file in LOCAL_CONFIG_FILE, GLOBAL_CONFIG_FILE:
            pathname = parse_path(config_file)
            if parser.read(pathname):
                logger.verbose("Reading configuration file %s ..",
                               format_path(pathname))
                break
    for section in parser.sections():
        items = dict(parser.items(section))
        context_options = {}
        if coerce_boolean(items.get('use-sudo')):
            context_options['sudo'] = True
        if items.get('ssh-user'):
            context_options['ssh_user'] = items['ssh-user']
        location = coerce_location(section, **context_options)
        rotation_scheme = dict((name, coerce_retention_period(items[name]))
                               for name in SUPPORTED_FREQUENCIES
                               if name in items)
        options = dict(include_list=split(items.get('include-list', '')),
                       exclude_list=split(items.get('exclude-list', '')),
                       io_scheduling_class=items.get('ionice'),
                       strict=coerce_boolean(items.get('strict', 'yes')),
                       prefer_recent=coerce_boolean(
                           items.get('prefer-recent', 'no')))
        yield location, rotation_scheme, options
Exemplo n.º 10
0
def initialize_gnupg():
    """
    Make sure the ``~/.gnupg`` directory exists.

    Older versions of GPG can/will fail when the ``~/.gnupg`` directory doesn't
    exist (e.g. in a newly created chroot). GPG itself creates the directory
    after noticing that it's missing, but then still fails! Later runs work
    fine however. To avoid this problem we make sure ``~/.gnupg`` exists before
    we run GPG.
    """
    makedirs(parse_path('~/.gnupg'))
Exemplo n.º 11
0
    def download_cache(self):
        """
        The absolute pathname of pip's download cache directory (a string).

        - Environment variable: ``$PIP_DOWNLOAD_CACHE``
        - Configuration option: ``download-cache``
        - Default: ``~/.pip/download-cache``
        """
        return parse_path(self.get(property_name='download_cache',
                                   environment_variable='PIP_DOWNLOAD_CACHE',
                                   configuration_option='download-cache',
                                   default='~/.pip/download-cache'))
Exemplo n.º 12
0
def check_directory(argument):
    """
    Make sure a command line argument points to an existing directory.

    :param argument: The original command line argument.
    :returns: The absolute pathname of an existing directory.
    """
    directory = parse_path(argument)
    if not os.path.isdir(directory):
        msg = "Directory doesn't exist! (%s)"
        raise Exception(msg % directory)
    return directory
Exemplo n.º 13
0
def check_directory(argument):
    """
    Make sure a command line argument points to an existing directory.

    :param argument: The original command line argument.
    :returns: The absolute pathname of an existing directory.
    """
    directory = parse_path(argument)
    if not os.path.isdir(directory):
        msg = "Directory doesn't exist! (%s)"
        raise Exception(msg % directory)
    return directory
Exemplo n.º 14
0
    def data_directory(self):
        """
        The absolute pathname of the directory where pip-accel's data files are stored (a string).

        - Environment variable: ``$PIP_ACCEL_CACHE``
        - Configuration option: ``data-directory``
        - Default: ``/var/cache/pip-accel`` if running as ``root``, ``~/.pip-accel`` otherwise
        """
        return parse_path(self.get(property_name='data_directory',
                                   environment_variable='PIP_ACCEL_CACHE',
                                   configuration_option='data-directory',
                                   default='/var/cache/pip-accel' if os.getuid() == 0 else '~/.pip-accel'))
Exemplo n.º 15
0
 def available_configuration_files(self):
     """A list of strings with the absolute pathnames of the available configuration files."""
     known_files = [
         GLOBAL_CONFIG, LOCAL_CONFIG,
         self.environment.get('PIP_ACCEL_CONFIG')
     ]
     absolute_paths = [
         parse_path(pathname) for pathname in known_files if pathname
     ]
     return [
         pathname for pathname in absolute_paths if os.path.isfile(pathname)
     ]
Exemplo n.º 16
0
def get_password_from_store(name, store=None):
    """Get the disk encryption password from the 'pass' program."""
    options = dict(capture=True, shell=False, tty=True)
    options['environment'] = dict(GPG_TTY=execute('tty', **options))
    if store:
        options['environment']['PASSWORD_STORE_DIR'] = parse_path(store)
    output = execute('pass', 'show', name, **options)
    lines = output.splitlines()
    if lines and lines[0]:
        return lines[0]
    else:
        logger.warning(
            "Failed to get disk encryption password using 'pass' program!")
Exemplo n.º 17
0
    def download_cache(self):
        """
        The absolute pathname of pip's download cache directory (a string).

        - Environment variable: ``$PIP_DOWNLOAD_CACHE``
        - Configuration option: ``download-cache``
        - Default: ``~/.pip/download-cache``
        """
        return parse_path(
            self.get(property_name='download_cache',
                     environment_variable='PIP_DOWNLOAD_CACHE',
                     configuration_option='download-cache',
                     default='~/.pip/download-cache'))
Exemplo n.º 18
0
def load_config_file(configuration_file=None):
    """
    Load a configuration file with backup directories and rotation schemes.

    :param configuration_file: Override the pathname of the configuration file
                               to load (a string or :data:`None`).
    :returns: A generator of tuples with four values each:

              1. An execution context created using :mod:`executor.contexts`.
              2. The pathname of a directory with backups (a string).
              3. A dictionary with the rotation scheme.
              4. A dictionary with additional options.
    :raises: :exc:`~exceptions.ValueError` when `configuration_file` is given
             but doesn't exist or can't be loaded.

    When `configuration_file` isn't given :data:`LOCAL_CONFIG_FILE` and
    :data:`GLOBAL_CONFIG_FILE` are checked and the first configuration file
    that exists is loaded. This function is used by :class:`RotateBackups` to
    discover user defined rotation schemes and by :mod:`rotate_backups.cli` to
    discover directories for which backup rotation is configured.
    """
    parser = configparser.RawConfigParser()
    if configuration_file:
        logger.verbose("Reading configuration file %s ..", format_path(configuration_file))
        loaded_files = parser.read(configuration_file)
        if len(loaded_files) == 0:
            msg = "Failed to read configuration file! (%s)"
            raise ValueError(msg % configuration_file)
    else:
        for config_file in LOCAL_CONFIG_FILE, GLOBAL_CONFIG_FILE:
            pathname = parse_path(config_file)
            if parser.read(pathname):
                logger.verbose("Reading configuration file %s ..", format_path(pathname))
                break
    for section in parser.sections():
        items = dict(parser.items(section))
        context_options = {}
        if coerce_boolean(items.get('use-sudo')):
            context_options['sudo'] = True
        if items.get('ssh-user'):
            context_options['ssh_user'] = items['ssh-user']
        location = coerce_location(section, **context_options)
        rotation_scheme = dict((name, coerce_retention_period(items[name]))
                               for name in SUPPORTED_FREQUENCIES
                               if name in items)
        options = dict(include_list=split(items.get('include-list', '')),
                       exclude_list=split(items.get('exclude-list', '')),
                       io_scheduling_class=items.get('ionice'),
                       strict=coerce_boolean(items.get('strict', 'yes')),
                       prefer_recent=coerce_boolean(items.get('prefer-recent', 'no')))
        yield location, rotation_scheme, options
Exemplo n.º 19
0
    def data_directory(self):
        """
        The absolute pathname of the directory where pip-accel's data files are stored (a string).

        - Environment variable: ``$PIP_ACCEL_CACHE``
        - Configuration option: ``data-directory``
        - Default: ``/var/cache/pip-accel`` if running as ``root``, ``~/.pip-accel`` otherwise
        """
        return parse_path(
            self.get(property_name='data_directory',
                     environment_variable='PIP_ACCEL_CACHE',
                     configuration_option='data-directory',
                     default='/var/cache/pip-accel'
                     if os.getuid() == 0 else '~/.pip-accel'))
Exemplo n.º 20
0
    def directory(self):
        """
        The pathname of the password storage directory (a string).

        When the environment variable given by :data:`DIRECTORY_VARIABLE` is
        set the value of that environment variable is used, otherwise
        :data:`DEFAULT_DIRECTORY` is used. In either case the resulting
        directory pathname is normalized using
        :func:`~humanfriendly.parse_path()`.

        When you set the :attr:`directory` property, the value you set will be
        normalized using :func:`~humanfriendly.parse_path()` and the computed
        value of the :attr:`context` property is cleared.
        """
        return parse_path(os.environ.get(DIRECTORY_VARIABLE, DEFAULT_DIRECTORY))
Exemplo n.º 21
0
    def available_files(self):
        """
        The filenames of the available configuration files (a list of strings).

        The value of :attr:`available_files` is computed the first time its
        needed by searching for available configuration files that match
        :attr:`filename_patterns` using :func:`~glob.glob()`. If you set
        :attr:`available_files` this effectively disables searching for
        configuration files.
        """
        matches = []
        for pattern in self.filename_patterns:
            logger.debug("Matching filename pattern: %s", pattern)
            matches.extend(natsort(glob.glob(parse_path(pattern))))
        return matches
Exemplo n.º 22
0
def find_fixed_agent_socket():
    """
    Search for a GPG agent UNIX socket in one of the "fixed locations".

    :returns: The pathname of the found socket file (a string) or :data:`None`.

    Two locations are searched, in the given order (the first that is found is
    returned):

    - Starting from GnuPG 2.1.13 the location ``/run/user/$UID/gnupg/S.gpg-agent``
      is used (only when the directory ``/run/user/$UID`` exists).

    - GnuPG 2.1 removed the ``$GPG_AGENT_INFO`` related code and switched to
      the fixed location ``~/.gnupg/S.gpg-agent``.
    """
    socket_on_tmpfs = '/run/user/%i/gnupg/S.gpg-agent' % os.getuid()
    for socket in (socket_on_tmpfs, parse_path(NEW_STYLE_SOCKET)):
        if os.path.exists(socket):
            return socket
Exemplo n.º 23
0
    def load_configuration_file(self, configuration_file):
        """
        Load configuration defaults from a configuration file.

        :param configuration_file: The pathname of a configuration file (a
                                   string).
        :raises: :py:exc:`Exception` when the configuration file cannot be
                 loaded.
        """
        configuration_file = parse_path(configuration_file)
        logger.debug("Loading configuration file: %s", configuration_file)
        parser = configparser.RawConfigParser()
        files_loaded = parser.read(configuration_file)
        if len(files_loaded) != 1:
            msg = "Failed to load configuration file! (%s)"
            raise Exception(msg % configuration_file)
        elif not parser.has_section('pip-accel'):
            msg = "Missing 'pip-accel' section in configuration file! (%s)"
            raise Exception(msg % configuration_file)
        else:
            self.configuration.update(parser.items('pip-accel'))
Exemplo n.º 24
0
    def load_configuration_file(self, configuration_file):
        """
        Load configuration defaults from a configuration file.

        :param configuration_file: The pathname of a configuration file (a
                                   string).
        :raises: :py:exc:`Exception` when the configuration file cannot be
                 loaded.
        """
        configuration_file = parse_path(configuration_file)
        logger.debug("Loading configuration file: %s", configuration_file)
        parser = configparser.RawConfigParser()
        files_loaded = parser.read(configuration_file)
        if len(files_loaded) != 1:
            msg = "Failed to load configuration file! (%s)"
            raise Exception(msg % configuration_file)
        elif not parser.has_section('pip-accel'):
            msg = "Missing 'pip-accel' section in configuration file! (%s)"
            raise Exception(msg % configuration_file)
        else:
            self.configuration.update(parser.items('pip-accel'))
Exemplo n.º 25
0
def expand_path(pathname):
    """
    Expand the home directory in a pathname based on the effective user id.

    :param pathname: A pathname that may start with ``~/``, indicating the path
                     should be interpreted as being relative to the home
                     directory of the current (effective) user.
    :returns: The (modified) pathname.

    This function is a variant of :func:`os.path.expanduser()` that doesn't use
    ``$HOME`` but instead uses the home directory of the effective user id.
    This is basically a workaround for ``sudo -s`` not resetting ``$HOME``.
    """
    # The following logic previously used regular expressions but that approach
    # turned out to be very error prone, hence the current contraption based on
    # direct string manipulation :-).
    home_directory = find_home_directory()
    separators = set([os.sep])
    if os.altsep is not None:
        separators.add(os.altsep)
    if len(pathname) >= 2 and pathname[0] == '~' and pathname[1] in separators:
        pathname = os.path.join(home_directory, pathname[2:])
    # Also expand environment variables.
    return parse_path(pathname)
Exemplo n.º 26
0
def expand_path(pathname):
    """
    Expand the home directory in a pathname based on the effective user id.

    :param pathname: A pathname that may start with ``~/``, indicating the path
                     should be interpreted as being relative to the home
                     directory of the current (effective) user.
    :returns: The (modified) pathname.

    This function is a variant of :func:`os.path.expanduser()` that doesn't use
    ``$HOME`` but instead uses the home directory of the effective user id.
    This is basically a workaround for ``sudo -s`` not resetting ``$HOME``.
    """
    # The following logic previously used regular expressions but that approach
    # turned out to be very error prone, hence the current contraption based on
    # direct string manipulation :-).
    home_directory = find_home_directory()
    separators = set([os.sep])
    if os.altsep is not None:
        separators.add(os.altsep)
    if len(pathname) >= 2 and pathname[0] == '~' and pathname[1] in separators:
        pathname = os.path.join(home_directory, pathname[2:])
    # Also expand environment variables.
    return parse_path(pathname)
Exemplo n.º 27
0
    def __init__(self,
                 name=None,
                 description=None,
                 secret_key_file=None,
                 public_key_file=None,
                 key_id=None):
        """
        Initialize a GPG key object.

        :param name: The name of the GPG key pair (a string). Used only when
                     the key pair is generated because it doesn't exist yet.
        :param description: The description of the GPG key pair (a string).
                            Used only when the key pair is generated because it
                            doesn't exist yet.
        :param secret_key_file: The absolute pathname of the secret key file (a
                                string). Defaults to ``~/.gnupg/secring.gpg``.
        :param public_key_file: The absolute pathname of the public key file (a
                                string). Defaults to ``~/.gnupg/pubring.gpg``.
        :param key_id: The key ID of an existing key pair to use (a string). If
                       this argument is provided then the key pair's secret and
                       public key files must already exist.

        This method initializes a GPG key object in one of several ways:

        1. If `key_id` is specified then the GPG key must have been created
           previously. If `secret_key_file` and `public_key_file` are not
           specified they default to ``~/.gnupg/secring.gpg`` and
           ``~/.gnupg/pubring.gpg``. In this case `key_id` is the only
           required argument.

           The following example assumes that the provided GPG key ID is
           defined in the default keyring of the current user:

           >>> from deb_pkg_tools.gpg import GPGKey
           >>> key = GPGKey(key_id='58B6B02B')
           >>> key.gpg_command
           'gpg --no-default-keyring --secret-keyring /home/peter/.gnupg/secring.gpg --keyring /home/peter/.gnupg/pubring.gpg --recipient 58B6B02B'

        2. If `secret_key_file` and `public_key_file` are specified but the
           files don't exist yet, a GPG key will be generated for you. In this
           case `name` and `description` are required arguments and `key_id`
           must be :data:`None` (the default). An example:

           >>> name = 'deb-pkg-tools'
           >>> description = 'Automatic signing key for deb-pkg-tools'
           >>> secret_key_file = '/home/peter/.deb-pkg-tools/automatic-signing-key.sec'
           >>> public_key_file = '/home/peter/.deb-pkg-tools/automatic-signing-key.pub'
           >>> key = GPGKey(name, description, secret_key_file, public_key_file)
           >>> key.gpg_command
           'gpg --no-default-keyring --secret-keyring /home/peter/.deb-pkg-tools/automatic-signing-key.sec --keyring /home/peter/.deb-pkg-tools/automatic-signing-key.pub'
        """
        # If the secret or public key file is provided, the other key file must
        # be provided as well.
        if secret_key_file and not public_key_file:
            raise Exception(
                "You provided a GPG secret key file without a public key file; please provide both!"
            )
        elif public_key_file and not secret_key_file:
            raise Exception(
                "You provided a GPG public key file without a secret key file; please provide both!"
            )

        # If neither of the key files is provided we'll default to the
        # locations that GnuPG uses by default.
        if not secret_key_file and not public_key_file:
            gnupg_directory = parse_path('~/.gnupg')
            secret_key_file = os.path.join(gnupg_directory, 'secring.gpg')
            public_key_file = os.path.join(gnupg_directory, 'pubring.gpg')

        # If a key ID was specified then the two key files must already exist;
        # we won't generate them because that makes no sense :-)
        if key_id and not os.path.isfile(secret_key_file):
            text = "The provided GPG secret key file (%s) doesn't exist but a key ID was specified!"
            raise Exception(text % secret_key_file)
        if key_id and not os.path.isfile(public_key_file):
            text = "The provided GPG public key file (%s) doesn't exist but a key ID was specified!"
            raise Exception(text % public_key_file)

        # If we're going to generate a GPG key for the caller we don't want to
        # overwrite a secret or public key file without its counterpart. We'll
        # also need a name and description for the generated key.
        existing_files = list(
            filter(os.path.isfile, [secret_key_file, public_key_file]))
        if len(existing_files) not in (0, 2):
            text = "Refusing to overwrite existing key file! (%s)"
            raise Exception(text % existing_files[0])
        elif len(existing_files) == 0 and not (name and description):
            logger.error("GPG key pair doesn't exist! (%s and %s)",
                         format_path(secret_key_file),
                         format_path(public_key_file))
            raise Exception(
                "To generate a GPG key you must provide a name and description!"
            )

        # Store the arguments.
        self.name = name
        self.description = description
        self.secret_key_file = secret_key_file
        self.public_key_file = public_key_file
        self.key_id = key_id

        # Generate the GPG key pair if required.
        if not existing_files:

            # Make sure the directories of the secret/public key files exist.
            for filename in [secret_key_file, public_key_file]:
                makedirs(os.path.dirname(filename))

            # Generate a file with batch instructions
            # suitable for `gpg --batch --gen-key'.
            fd, gpg_script = tempfile.mkstemp()
            with open(gpg_script, 'w') as handle:
                handle.write(
                    textwrap.dedent('''
                    Key-Type: DSA
                    Key-Length: 1024
                    Subkey-Type: ELG-E
                    Subkey-Length: 1024
                    Name-Real: {name}
                    Name-Comment: {description}
                    Name-Email: none
                    Expire-Date: 0
                    %pubring {public_key_file}
                    %secring {secret_key_file}
                    %commit
                ''').format(name=self.name,
                            description=self.description,
                            secret_key_file=self.secret_key_file,
                            public_key_file=self.public_key_file))

            # Generate the GPG key pair.
            logger.info("Generating GPG key pair %s (%s) ..", self.name,
                        self.description)
            logger.debug("Private key: %s", format_path(self.secret_key_file))
            logger.debug("Public key: %s", format_path(self.public_key_file))
            logger.info(
                "Please note: Generating a GPG key pair can take a long time. "
                "If you are logged into a virtual machine or a remote server "
                "over SSH, now is a good time to familiarize yourself with "
                "the concept of entropy and how to make more of it :-)")
            start_time = time.time()
            initialize_gnupg()
            with EntropyGenerator():
                execute('gpg',
                        '--batch',
                        '--gen-key',
                        gpg_script,
                        logger=logger)
            logger.info("Finished generating GPG key pair in %s.",
                        format_timespan(time.time() - start_time))
            os.unlink(gpg_script)
Exemplo n.º 28
0
def main():
    """Command line interface for ``unlock-remote-system``."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line arguments.
    program_opts = {}
    identity_file = None
    do_shell = False
    do_watch = False
    watch_all = False
    try:
        options, arguments = getopt.gnu_getopt(sys.argv[1:], 'i:k:p:r:swavqh',
                                               [
                                                   'identity-file=',
                                                   'known-hosts=',
                                                   'password='******'remote-host=',
                                                   'shell',
                                                   'watch',
                                                   'all',
                                                   'verbose',
                                                   'quiet',
                                                   'help',
                                               ])
        for option, value in options:
            if option in ('-i', '--identity-file'):
                identity_file = parse_path(value)
            elif option in ('-k', '--known-hosts'):
                program_opts['known_hosts_file'] = parse_path(value)
            elif option in ('-p', '--password'):
                program_opts['password'] = get_password_from_store(value)
            elif option in ('-r', '--remote-host'):
                program_opts['ssh_proxy'] = value
            elif option in ('-s', '--shell'):
                do_shell = True
            elif option in ('-w', '--watch'):
                do_watch = True
            elif option in ('-a', '--all'):
                watch_all = True
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                sys.exit(0)
            else:
                raise Exception("Unhandled option!")
        if not arguments:
            usage(__doc__)
            sys.exit(0)
        elif len(arguments) > 2:
            raise Exception("only two positional arguments allowed")
        # Create a ConfigLoader object and prepare to pass it to the program to
        # avoid scanning for configuration files more than once (which isn't a
        # real problem but does generate somewhat confusing log output).
        loader = ConfigLoader(program_name='unlock-remote-system')
        program_opts['config_loader'] = loader
        # Check if a single positional argument was given that matches the name
        # of a user defined configuration section.
        if len(arguments) == 1 and arguments[0] in loader.section_names:
            logger.info("Loading configuration section '%s' ..", arguments[0])
            program_opts['config_section'] = arguments[0]
        else:
            # The SSH connection profile of the pre-boot environment
            # is given as the first positional argument.
            program_opts['pre_boot'] = ConnectionProfile(
                expression=arguments[0], identity_file=identity_file)
            # The SSH connection profile of the post-boot environment
            # can be given as the second positional argument, otherwise
            # it will be inferred from the connection profile of
            # the pre-boot environment.
            if len(arguments) == 2:
                program_opts['post_boot'] = ConnectionProfile(
                    expression=arguments[1])
            else:
                # By default we don't use root to login to the post-boot environment.
                program_opts['post_boot'] = ConnectionProfile(
                    expression=arguments[0])
                program_opts['post_boot'].username = find_local_username()
            # Prompt the operator to enter the disk encryption password for the remote host?
            if not program_opts.get('password'):
                program_opts['password'] = prompt_for_password(
                    program_opts['pre_boot'].hostname)
    except Exception as e:
        warning("Failed to parse command line arguments! (%s)", e)
        sys.exit(1)
    # Try to unlock the remote system.
    try:
        if do_watch and watch_all:
            watch_all_systems(loader)
        else:
            with EncryptedSystem(**program_opts) as program:
                if do_watch:
                    program.watch_system()
                else:
                    program.unlock_system()
                    if do_shell:
                        start_interactive_shell(program.post_context)
    except EncryptedSystemError as e:
        logger.error("Aborting due to error: %s", e)
        sys.exit(2)
    except Exception:
        logger.exception("Aborting due to unexpected exception!")
        sys.exit(3)
Exemplo n.º 29
0
def main():
    """Command line interface for the ``chat-archive`` program."""
    # Enable logging to the terminal.
    coloredlogs.install()
    # Parse the command line options.
    program_opts = dict()
    command_name = None
    try:
        options, arguments = getopt.gnu_getopt(
            sys.argv[1:],
            "C:fl:c:p:vqh",
            [
                "context=",
                "force",
                "log-file=",
                "color=",
                "colour=",
                "profile=",
                "verbose",
                "quiet",
                "help",
            ],
        )
        for option, value in options:
            if option in ("-C", "--context"):
                program_opts["context"] = int(value)
            elif option in ("-f", "--force"):
                program_opts["force"] = True
            elif option in ("-l", "--log-file"):
                handler = logging.FileHandler(parse_path(value))
                handler.setFormatter(
                    logging.Formatter(
                        fmt=
                        "%(asctime)s %(name)s[%(process)d] %(levelname)s %(message)s",
                        datefmt="%Y-%m-%d %H:%M:%S"))
                handler.setLevel(logging.DEBUG)
                logging.root.addHandler(handler)
                logging.root.setLevel(logging.NOTSET)
            elif option in ("-c", "--color", "--colour"):
                mapping = dict(always=True, never=False)
                program_opts["use_colors"] = mapping[
                    value] if value in mapping else coerce_boolean(value)
            elif option in ("-p", "--profile"):
                program_opts["profile_file"] = parse_path(value)
            elif option in ("-v", "--verbose"):
                coloredlogs.increase_verbosity()
            elif option in ("-q", "--quiet"):
                coloredlogs.decrease_verbosity()
            elif option in ("-h", "--help"):
                usage(__doc__)
                sys.exit(0)
            else:
                assert False, "Unhandled option!"
        # Make sure the operator provided a command.
        if not arguments:
            usage(__doc__)
            sys.exit(0)
    except Exception as e:
        warning("Failed to parse command line arguments: %s", e)
        sys.exit(1)
    try:
        # We extract any search keywords from the command line arguments before
        # initializing an instance of the UserInterface class, to enable
        # initialization of the KeywordHighlighter class.
        if arguments[0] == "search":
            program_opts["keywords"] = arguments[1:]
        # Initialize the chat archive.
        with UserInterface(**program_opts) as program:
            # Validate the requested command.
            command_name = arguments.pop(0)
            method_name = "%s_cmd" % command_name
            if not hasattr(program, method_name):
                warning("Error: Invalid command name '%s'!", command_name)
                sys.exit(1)
            # Execute the requested command.
            command_fn = getattr(program, method_name)
            command_fn(arguments)
    except KeyboardInterrupt:
        logger.notice("Interrupted by Control-C ..")
        sys.exit(1)
    except Exception:
        logger.exception("Aborting due to unexpected exception!")
        sys.exit(1)
Exemplo n.º 30
0
 def available_configuration_files(self):
     """A list of strings with the absolute pathnames of the available configuration files."""
     known_files = [GLOBAL_CONFIG, LOCAL_CONFIG, self.environment.get('PIP_ACCEL_CONFIG')]
     absolute_paths = [parse_path(pathname) for pathname in known_files if pathname]
     return [pathname for pathname in absolute_paths if os.path.isfile(pathname)]
Exemplo n.º 31
0
def main():
    """Command line interface for the ``rotate-backups`` program."""
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    config_file = None
    dry_run = False
    exclude_list = []
    include_list = []
    io_scheduling_class = None
    rotation_scheme = {}
    use_sudo = False
    strict = True
    # Internal state.
    selected_locations = []
    # Parse the command line arguments.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'H:d:w:m:y:I:x:ri:c:r:unvqh', [
            'hourly=', 'daily=', 'weekly=', 'monthly=', 'yearly=', 'include=',
            'exclude=', 'relaxed', 'ionice=', 'config=', 'use-sudo', 'dry-run',
            'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-H', '--hourly'):
                rotation_scheme['hourly'] = coerce_retention_period(value)
            elif option in ('-d', '--daily'):
                rotation_scheme['daily'] = coerce_retention_period(value)
            elif option in ('-w', '--weekly'):
                rotation_scheme['weekly'] = coerce_retention_period(value)
            elif option in ('-m', '--monthly'):
                rotation_scheme['monthly'] = coerce_retention_period(value)
            elif option in ('-y', '--yearly'):
                rotation_scheme['yearly'] = coerce_retention_period(value)
            elif option in ('-I', '--include'):
                include_list.append(value)
            elif option in ('-x', '--exclude'):
                exclude_list.append(value)
            elif option in ('-r', '--relaxed'):
                strict = False
            elif option in ('-i', '--ionice'):
                value = value.lower().strip()
                expected = ('idle', 'best-effort', 'realtime')
                if value not in expected:
                    msg = "Invalid I/O scheduling class! (got %r while valid options are %s)"
                    raise Exception(msg % (value, concatenate(expected)))
                io_scheduling_class = value
            elif option in ('-c', '--config'):
                config_file = parse_path(value)
            elif option in ('-u', '--use-sudo'):
                use_sudo = True
            elif option in ('-n', '--dry-run'):
                logger.info("Performing a dry run (because of %s option) ..", option)
                dry_run = True
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
            else:
                assert False, "Unhandled option! (programming error)"
        if rotation_scheme:
            logger.debug("Parsed rotation scheme: %s", rotation_scheme)
        if arguments:
            # Rotation of the locations given on the command line.
            selected_locations.extend(coerce_location(value, sudo=use_sudo) for value in arguments)
        else:
            # Rotation of all configured locations.
            selected_locations.extend(location for location, rotation_scheme, options in load_config_file(config_file))
        # Show the usage message when no directories are given nor configured.
        if not selected_locations:
            usage(__doc__)
            return
    except Exception as e:
        logger.error("%s", e)
        sys.exit(1)
    # Rotate the backups in the selected directories.
    for location in selected_locations:
        RotateBackups(
            rotation_scheme=rotation_scheme,
            include_list=include_list,
            exclude_list=exclude_list,
            io_scheduling_class=io_scheduling_class,
            dry_run=dry_run,
            config_file=config_file,
            strict=strict,
        ).rotate_backups(location)
Exemplo n.º 32
0
"""Configuration defaults for the `deb-pkg-tools` package."""

# Standard library modules.
import os

# External dependencies.
from humanfriendly import parse_path

system_config_directory = '/etc/deb-pkg-tools'
"""The pathname of the global (system wide) configuration directory used by `deb-pkg-tools` (a string)."""

system_cache_directory = '/var/cache/deb-pkg-tools'
"""The pathname of the global (system wide) package cache directory (a string)."""

user_config_directory = parse_path('~/.deb-pkg-tools')
"""
The pathname of the current user's configuration directory used by `deb-pkg-tools` (a string).

:default: The expanded value of ``~/.deb-pkg-tools``.
"""

user_cache_directory = parse_path('~/.cache/deb-pkg-tools')
"""
The pathname of the current user's package cache directory (a string).

:default: The expanded value of ``~/.cache/deb-pkg-tools``.
"""

# The location of the package cache. If we're running as root we have write
# access to the system wide package cache so we'll pick that; the more users
Exemplo n.º 33
0
def main():
    """Command line interface for the ``rotate-backups`` program."""
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    config_file = None
    dry_run = False
    exclude_list = []
    include_list = []
    io_scheduling_class = None
    rotation_scheme = {}
    use_sudo = False
    strict = True
    # Internal state.
    selected_locations = []
    # Parse the command line arguments.
    try:
        options, arguments = getopt.getopt(sys.argv[1:],
                                           'H:d:w:m:y:I:x:ri:c:r:unvqh', [
                                               'hourly=',
                                               'daily=',
                                               'weekly=',
                                               'monthly=',
                                               'yearly=',
                                               'include=',
                                               'exclude=',
                                               'relaxed',
                                               'ionice=',
                                               'config=',
                                               'use-sudo',
                                               'dry-run',
                                               'verbose',
                                               'quiet',
                                               'help',
                                           ])
        for option, value in options:
            if option in ('-H', '--hourly'):
                rotation_scheme['hourly'] = coerce_retention_period(value)
            elif option in ('-d', '--daily'):
                rotation_scheme['daily'] = coerce_retention_period(value)
            elif option in ('-w', '--weekly'):
                rotation_scheme['weekly'] = coerce_retention_period(value)
            elif option in ('-m', '--monthly'):
                rotation_scheme['monthly'] = coerce_retention_period(value)
            elif option in ('-y', '--yearly'):
                rotation_scheme['yearly'] = coerce_retention_period(value)
            elif option in ('-I', '--include'):
                include_list.append(value)
            elif option in ('-x', '--exclude'):
                exclude_list.append(value)
            elif option in ('-r', '--relaxed'):
                strict = False
            elif option in ('-i', '--ionice'):
                value = value.lower().strip()
                expected = ('idle', 'best-effort', 'realtime')
                if value not in expected:
                    msg = "Invalid I/O scheduling class! (got %r while valid options are %s)"
                    raise Exception(msg % (value, concatenate(expected)))
                io_scheduling_class = value
            elif option in ('-c', '--config'):
                config_file = parse_path(value)
            elif option in ('-u', '--use-sudo'):
                use_sudo = True
            elif option in ('-n', '--dry-run'):
                logger.info("Performing a dry run (because of %s option) ..",
                            option)
                dry_run = True
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
            else:
                assert False, "Unhandled option! (programming error)"
        if rotation_scheme:
            logger.debug("Parsed rotation scheme: %s", rotation_scheme)
        if arguments:
            # Rotation of the locations given on the command line.
            selected_locations.extend(
                coerce_location(value, sudo=use_sudo) for value in arguments)
        else:
            # Rotation of all configured locations.
            selected_locations.extend(location for location, rotation_scheme,
                                      options in load_config_file(config_file))
        # Show the usage message when no directories are given nor configured.
        if not selected_locations:
            usage(__doc__)
            return
    except Exception as e:
        logger.error("%s", e)
        sys.exit(1)
    # Rotate the backups in the selected directories.
    for location in selected_locations:
        RotateBackups(
            rotation_scheme=rotation_scheme,
            include_list=include_list,
            exclude_list=exclude_list,
            io_scheduling_class=io_scheduling_class,
            dry_run=dry_run,
            config_file=config_file,
            strict=strict,
        ).rotate_backups(location)
Exemplo n.º 34
0
    def __init__(self, name=None, description=None, secret_key_file=None, public_key_file=None, key_id=None):
        """
        Initialize a GPG key object.

        :param name: The name of the GPG key pair (a string). Used only when
                     the key pair is generated because it doesn't exist yet.
        :param description: The description of the GPG key pair (a string).
                            Used only when the key pair is generated because it
                            doesn't exist yet.
        :param secret_key_file: The absolute pathname of the secret key file (a
                                string). Defaults to ``~/.gnupg/secring.gpg``.
        :param public_key_file: The absolute pathname of the public key file (a
                                string). Defaults to ``~/.gnupg/pubring.gpg``.
        :param key_id: The key ID of an existing key pair to use (a string). If
                       this argument is provided then the key pair's secret and
                       public key files must already exist.

        This method initializes a GPG key object in one of several ways:

        1. If `key_id` is specified then the GPG key must have been created
           previously. If `secret_key_file` and `public_key_file` are not
           specified they default to ``~/.gnupg/secring.gpg`` and
           ``~/.gnupg/pubring.gpg``. In this case `key_id` is the only
           required argument.

           The following example assumes that the provided GPG key ID is
           defined in the default keyring of the current user:

           >>> from deb_pkg_tools.gpg import GPGKey
           >>> key = GPGKey(key_id='58B6B02B')
           >>> key.gpg_command
           'gpg --no-default-keyring --secret-keyring /home/peter/.gnupg/secring.gpg --keyring /home/peter/.gnupg/pubring.gpg --recipient 58B6B02B'

        2. If `secret_key_file` and `public_key_file` are specified but the
           files don't exist yet, a GPG key will be generated for you. In this
           case `name` and `description` are required arguments and `key_id`
           must be :data:`None` (the default). An example:

           >>> name = 'deb-pkg-tools'
           >>> description = 'Automatic signing key for deb-pkg-tools'
           >>> secret_key_file = '/home/peter/.deb-pkg-tools/automatic-signing-key.sec'
           >>> public_key_file = '/home/peter/.deb-pkg-tools/automatic-signing-key.pub'
           >>> key = GPGKey(name, description, secret_key_file, public_key_file)
           >>> key.gpg_command
           'gpg --no-default-keyring --secret-keyring /home/peter/.deb-pkg-tools/automatic-signing-key.sec --keyring /home/peter/.deb-pkg-tools/automatic-signing-key.pub'
        """
        # If the secret or public key file is provided, the other key file must
        # be provided as well.
        if secret_key_file and not public_key_file:
            raise Exception("You provided a GPG secret key file without a public key file; please provide both!")
        elif public_key_file and not secret_key_file:
            raise Exception("You provided a GPG public key file without a secret key file; please provide both!")

        # If neither of the key files is provided we'll default to the
        # locations that GnuPG uses by default.
        if not secret_key_file and not public_key_file:
            gnupg_directory = parse_path('~/.gnupg')
            secret_key_file = os.path.join(gnupg_directory, 'secring.gpg')
            public_key_file = os.path.join(gnupg_directory, 'pubring.gpg')

        # If a key ID was specified then the two key files must already exist;
        # we won't generate them because that makes no sense :-)
        if key_id and not os.path.isfile(secret_key_file):
            text = "The provided GPG secret key file (%s) doesn't exist but a key ID was specified!"
            raise Exception(text % secret_key_file)
        if key_id and not os.path.isfile(public_key_file):
            text = "The provided GPG public key file (%s) doesn't exist but a key ID was specified!"
            raise Exception(text % public_key_file)

        # If we're going to generate a GPG key for the caller we don't want to
        # overwrite a secret or public key file without its counterpart. We'll
        # also need a name and description for the generated key.
        existing_files = list(filter(os.path.isfile, [secret_key_file, public_key_file]))
        if len(existing_files) not in (0, 2):
            text = "Refusing to overwrite existing key file! (%s)"
            raise Exception(text % existing_files[0])
        elif len(existing_files) == 0 and not (name and description):
            logger.error("GPG key pair doesn't exist! (%s and %s)",
                         format_path(secret_key_file),
                         format_path(public_key_file))
            raise Exception("To generate a GPG key you must provide a name and description!")

        # Store the arguments.
        self.name = name
        self.description = description
        self.secret_key_file = secret_key_file
        self.public_key_file = public_key_file
        self.key_id = key_id

        # Generate the GPG key pair if required.
        if not existing_files:

            # Make sure the directories of the secret/public key files exist.
            for filename in [secret_key_file, public_key_file]:
                makedirs(os.path.dirname(filename))

            # Generate a file with batch instructions
            # suitable for `gpg --batch --gen-key'.
            fd, gpg_script = tempfile.mkstemp()
            with open(gpg_script, 'w') as handle:
                handle.write(textwrap.dedent('''
                    Key-Type: DSA
                    Key-Length: 1024
                    Subkey-Type: ELG-E
                    Subkey-Length: 1024
                    Name-Real: {name}
                    Name-Comment: {description}
                    Name-Email: none
                    Expire-Date: 0
                    %pubring {public_key_file}
                    %secring {secret_key_file}
                    %commit
                ''').format(name=self.name,
                            description=self.description,
                            secret_key_file=self.secret_key_file,
                            public_key_file=self.public_key_file))

            # Generate the GPG key pair.
            logger.info("Generating GPG key pair %s (%s) ..", self.name, self.description)
            logger.debug("Private key: %s", format_path(self.secret_key_file))
            logger.debug("Public key: %s", format_path(self.public_key_file))
            logger.info("Please note: Generating a GPG key pair can take a long time. "
                        "If you are logged into a virtual machine or a remote server "
                        "over SSH, now is a good time to familiarize yourself with "
                        "the concept of entropy and how to make more of it :-)")
            start_time = time.time()
            initialize_gnupg()
            with EntropyGenerator():
                execute('gpg', '--batch', '--gen-key', gpg_script, logger=logger)
            logger.info("Finished generating GPG key pair in %s.",
                        format_timespan(time.time() - start_time))
            os.unlink(gpg_script)
Exemplo n.º 35
0
def main():
    """Command line interface for the ``rotate-backups`` program."""
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    rotation_scheme = {}
    kw = dict(include_list=[], exclude_list=[])
    parallel = False
    use_sudo = False
    # Internal state.
    selected_locations = []
    # Parse the command line arguments.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'M:H:d:w:m:y:I:x:jpri:c:r:uC:nvqh', [
            'minutely=', 'hourly=', 'daily=', 'weekly=', 'monthly=', 'yearly=',
            'include=', 'exclude=', 'parallel', 'prefer-recent', 'relaxed',
            'ionice=', 'config=', 'use-sudo', 'dry-run', 'removal-command=',
            'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-M', '--minutely'):
                rotation_scheme['minutely'] = coerce_retention_period(value)
            elif option in ('-H', '--hourly'):
                rotation_scheme['hourly'] = coerce_retention_period(value)
            elif option in ('-d', '--daily'):
                rotation_scheme['daily'] = coerce_retention_period(value)
            elif option in ('-w', '--weekly'):
                rotation_scheme['weekly'] = coerce_retention_period(value)
            elif option in ('-m', '--monthly'):
                rotation_scheme['monthly'] = coerce_retention_period(value)
            elif option in ('-y', '--yearly'):
                rotation_scheme['yearly'] = coerce_retention_period(value)
            elif option in ('-I', '--include'):
                kw['include_list'].append(value)
            elif option in ('-x', '--exclude'):
                kw['exclude_list'].append(value)
            elif option in ('-j', '--parallel'):
                parallel = True
            elif option in ('-p', '--prefer-recent'):
                kw['prefer_recent'] = True
            elif option in ('-r', '--relaxed'):
                kw['strict'] = False
            elif option in ('-i', '--ionice'):
                value = validate_ionice_class(value.lower().strip())
                kw['io_scheduling_class'] = value
            elif option in ('-c', '--config'):
                kw['config_file'] = parse_path(value)
            elif option in ('-u', '--use-sudo'):
                use_sudo = True
            elif option in ('-n', '--dry-run'):
                logger.info("Performing a dry run (because of %s option) ..", option)
                kw['dry_run'] = True
            elif option in ('-C', '--removal-command'):
                removal_command = shlex.split(value)
                logger.info("Using custom removal command: %s", removal_command)
                kw['removal_command'] = removal_command
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
            else:
                assert False, "Unhandled option! (programming error)"
        if rotation_scheme:
            logger.verbose("Rotation scheme defined on command line: %s", rotation_scheme)
        if arguments:
            # Rotation of the locations given on the command line.
            location_source = 'command line arguments'
            selected_locations.extend(coerce_location(value, sudo=use_sudo) for value in arguments)
        else:
            # Rotation of all configured locations.
            location_source = 'configuration file'
            selected_locations.extend(
                location for location, rotation_scheme, options
                in load_config_file(configuration_file=kw.get('config_file'), expand=True)
            )
        # Inform the user which location(s) will be rotated.
        if selected_locations:
            logger.verbose("Selected %s based on %s:",
                           pluralize(len(selected_locations), "location"),
                           location_source)
            for number, location in enumerate(selected_locations, start=1):
                logger.verbose(" %i. %s", number, location)
        else:
            # Show the usage message when no directories are given nor configured.
            logger.verbose("No location(s) to rotate selected.")
            usage(__doc__)
            return
    except Exception as e:
        logger.error("%s", e)
        sys.exit(1)
    # Rotate the backups in the selected directories.
    program = RotateBackups(rotation_scheme, **kw)
    if parallel:
        program.rotate_concurrent(*selected_locations)
    else:
        for location in selected_locations:
            program.rotate_backups(location)
Exemplo n.º 36
0
 def test_parse_path(self):
     """Test :func:`humanfriendly.parse_path()`."""
     friendly_path = os.path.join('~', '.vimrc')
     absolute_path = os.path.join(os.environ['HOME'], '.vimrc')
     self.assertEqual(absolute_path, humanfriendly.parse_path(friendly_path))
Exemplo n.º 37
0
 def directory_default(self):
     """The pathname of the default GnuPG home directory (a string)."""
     return parse_path('~/.gnupg')
Exemplo n.º 38
0
 def cache_directory(self):
     """The absolute pathname of the directory where ``node_modules`` directories are cached (a string)."""
     return ('/var/cache/npm-accel'
             if os.getuid() == 0 and os.access('/var/cache', os.W_OK) else
             parse_path('~/.cache/npm-accel'))
Exemplo n.º 39
0
def main():
    """Command line interface for the ``npm-accel`` program."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    program_opts = {}
    context_opts = {}
    directory = None
    action = 'install'
    # Parse the command line arguments.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'pi:c:l:nbr:vqh', [
            'production',
            'installer=',
            'cache-directory=',
            'cache-limit=',
            'no-cache',
            'benchmark',
            'remote-host=',
            'verbose',
            'quiet',
            'help',
        ])
        for option, value in options:
            if option in ('p', '--production'):
                program_opts['production'] = True
            elif option in ('i', '--installer'):
                program_opts['installer_name'] = value
            elif option in ('-c', '--cache-directory'):
                program_opts['cache_directory'] = parse_path(value)
            elif option in ('-l', '--cache-limit'):
                program_opts['cache_limit'] = int(value)
            elif option in ('-n', '--no-cache'):
                program_opts['write_to_cache'] = False
            elif option in ('-b', '--benchmark'):
                action = 'benchmark'
            elif option in ('-r', '--remote-host'):
                context_opts['ssh_alias'] = value
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
            else:
                assert False, "Unhandled option!"
        if arguments:
            directory = arguments.pop(0)
            if arguments:
                raise Exception("Got more positional arguments than expected!")
        if not directory:
            if context_opts.get('ssh_alias'):
                raise Exception(
                    "When operating on a remote system the directory needs to be specified explicitly!"
                )
            directory = os.getcwd()
    except Exception as e:
        warning("Error: Failed to parse command line arguments! (%s)" % e)
        sys.exit(1)
    # Perform the requested action(s).
    try:
        context = create_context(**context_opts)
        program_opts['context'] = context
        accelerator = NpmAccel(**program_opts)
        method = getattr(accelerator, action)
        method(directory)
    except NpmAccelError as e:
        warning("Error: %s", e)
        sys.exit(1)
    except Exception:
        logger.exception("Encountered unexpected exception! Aborting ..")
        sys.exit(1)
Exemplo n.º 40
0
def main():
    """Command line interface for the ``rotate-backups-s3`` program."""
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    aws_access_key_id = None
    aws_secret_access_key = None
    aws_host = 's3.amazonaws.com'
    config_file = None
    dry_run = False
    exclude_list = []
    include_list = []
    rotation_scheme = {}
    prefer_recent = False
    # Parse the command line arguments.
    try:
        options, arguments = getopt.getopt(sys.argv[1:],
                                           'U:P:H:d:w:m:y:I:x:c:nvhp', [
                                               'aws-access-key-id=',
                                               'aws-secret-access-key=',
                                               'aws-host=',
                                               'hourly=',
                                               'daily=',
                                               'weekly=',
                                               'monthly=',
                                               'yearly=',
                                               'include=',
                                               'exclude=',
                                               'config=',
                                               'dry-run',
                                               'verbose',
                                               'help',
                                               'prefer-recent',
                                           ])
        for option, value in options:
            if option in ('-H', '--hourly'):
                rotation_scheme['hourly'] = coerce_retention_period(value)
            elif option in ('-d', '--daily'):
                rotation_scheme['daily'] = coerce_retention_period(value)
            elif option in ('-w', '--weekly'):
                rotation_scheme['weekly'] = coerce_retention_period(value)
            elif option in ('-m', '--monthly'):
                rotation_scheme['monthly'] = coerce_retention_period(value)
            elif option in ('-y', '--yearly'):
                rotation_scheme['yearly'] = coerce_retention_period(value)
            elif option in ('-I', '--include'):
                include_list.append(value)
            elif option in ('-x', '--exclude'):
                exclude_list.append(value)
            elif option in ('-c', '--config'):
                config_file = parse_path(value)
            elif option in ('-U', '--aws-access-key-id'):
                aws_access_key_id = value
            elif option in ('-P', '--aws-secret-access-key'):
                aws_secret_access_key = value
            elif option in ('--aws-host'):
                aws_host = value
            elif option in ('-n', '--dry-run'):
                logger.info("Performing a dry run (because of %s option) ..",
                            option)
                dry_run = True
            elif option in ('-p', '--prefer-recent'):
                prefer_recent = True
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
            else:
                assert False, "Unhandled option! (programming error)"
        if rotation_scheme:
            logger.debug("Parsed rotation scheme: %s", rotation_scheme)

        # If no arguments are given but the system has a configuration file
        # then the backups in the configured directories are rotated.
        if not arguments:
            arguments.extend(s3path
                             for s3path, _, _ in load_config_file(config_file))
        # Show the usage message when no directories are given nor configured.
        if not arguments:
            usage(__doc__)
            return
    except Exception as e:
        logger.error("%s", e)
        sys.exit(1)
    # Rotate the backups in the given or configured directories.
    for s3path in arguments:
        prefix = ''
        bucket = s3path[5:] if s3path.startswith('s3://') else s3path

        pos = bucket.find('/')
        if pos != -1:
            prefix = bucket[pos:].strip('/')
            bucket = bucket[:pos]

        S3RotateBackups(
            rotation_scheme=rotation_scheme,
            aws_access_key_id=aws_access_key_id,
            aws_secret_access_key=aws_secret_access_key,
            aws_host=aws_host,
            include_list=include_list,
            exclude_list=exclude_list,
            dry_run=dry_run,
            prefer_recent=prefer_recent,
        ).rotate_backups(bucket, prefix)
Exemplo n.º 41
0
 def test_parse_path(self):
     """Test :func:`humanfriendly.parse_path()`."""
     friendly_path = os.path.join('~', '.vimrc')
     absolute_path = os.path.join(os.environ['HOME'], '.vimrc')
     self.assertEqual(absolute_path, humanfriendly.parse_path(friendly_path))
Exemplo n.º 42
0
def main():
    """Command line interface for the ``rotate-backups`` program."""
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    rotation_scheme = {}
    kw = dict(include_list=[], exclude_list=[])
    parallel = False
    use_sudo = False
    # Internal state.
    selected_locations = []
    # Parse the command line arguments.
    try:
        options, arguments = getopt.getopt(sys.argv[1:],
                                           'M:H:d:w:m:y:I:x:jpri:c:r:uC:nvqh',
                                           [
                                               'minutely=',
                                               'hourly=',
                                               'daily=',
                                               'weekly=',
                                               'monthly=',
                                               'yearly=',
                                               'include=',
                                               'exclude=',
                                               'parallel',
                                               'prefer-recent',
                                               'relaxed',
                                               'ionice=',
                                               'config=',
                                               'use-sudo',
                                               'dry-run',
                                               'removal-command=',
                                               'verbose',
                                               'quiet',
                                               'help',
                                           ])
        for option, value in options:
            if option in ('-M', '--minutely'):
                rotation_scheme['minutely'] = coerce_retention_period(value)
            elif option in ('-H', '--hourly'):
                rotation_scheme['hourly'] = coerce_retention_period(value)
            elif option in ('-d', '--daily'):
                rotation_scheme['daily'] = coerce_retention_period(value)
            elif option in ('-w', '--weekly'):
                rotation_scheme['weekly'] = coerce_retention_period(value)
            elif option in ('-m', '--monthly'):
                rotation_scheme['monthly'] = coerce_retention_period(value)
            elif option in ('-y', '--yearly'):
                rotation_scheme['yearly'] = coerce_retention_period(value)
            elif option in ('-I', '--include'):
                kw['include_list'].append(value)
            elif option in ('-x', '--exclude'):
                kw['exclude_list'].append(value)
            elif option in ('-j', '--parallel'):
                parallel = True
            elif option in ('-p', '--prefer-recent'):
                kw['prefer_recent'] = True
            elif option in ('-r', '--relaxed'):
                kw['strict'] = False
            elif option in ('-i', '--ionice'):
                value = validate_ionice_class(value.lower().strip())
                kw['io_scheduling_class'] = value
            elif option in ('-c', '--config'):
                kw['config_file'] = parse_path(value)
            elif option in ('-u', '--use-sudo'):
                use_sudo = True
            elif option in ('-n', '--dry-run'):
                logger.info("Performing a dry run (because of %s option) ..",
                            option)
                kw['dry_run'] = True
            elif option in ('-C', '--removal-command'):
                removal_command = shlex.split(value)
                logger.info("Using custom removal command: %s",
                            removal_command)
                kw['removal_command'] = removal_command
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
            else:
                assert False, "Unhandled option! (programming error)"
        if rotation_scheme:
            logger.verbose("Rotation scheme defined on command line: %s",
                           rotation_scheme)
        if arguments:
            # Rotation of the locations given on the command line.
            location_source = 'command line arguments'
            selected_locations.extend(
                coerce_location(value, sudo=use_sudo) for value in arguments)
        else:
            # Rotation of all configured locations.
            location_source = 'configuration file'
            selected_locations.extend(
                location
                for location, rotation_scheme, options in load_config_file(
                    configuration_file=kw.get('config_file'), expand=True))
        # Inform the user which location(s) will be rotated.
        if selected_locations:
            logger.verbose("Selected %s based on %s:",
                           pluralize(len(selected_locations), "location"),
                           location_source)
            for number, location in enumerate(selected_locations, start=1):
                logger.verbose(" %i. %s", number, location)
        else:
            # Show the usage message when no directories are given nor configured.
            logger.verbose("No location(s) to rotate selected.")
            usage(__doc__)
            return
    except Exception as e:
        logger.error("%s", e)
        sys.exit(1)
    # Rotate the backups in the selected directories.
    program = RotateBackups(rotation_scheme, **kw)
    if parallel:
        program.rotate_concurrent(*selected_locations)
    else:
        for location in selected_locations:
            program.rotate_backups(location)
Exemplo n.º 43
0
def pathname_normalize(p):
    return humanfriendly.parse_path(p)
Exemplo n.º 44
0
# URL: https://github.com/xolox/python-deb-pkg-tools
"""Configuration defaults for the `deb-pkg-tools` package."""

# Standard library modules.
import os

# External dependencies.
from humanfriendly import parse_path

system_config_directory = '/etc/deb-pkg-tools'
"""The pathname of the global (system wide) configuration directory used by `deb-pkg-tools` (a string)."""

system_cache_directory = '/var/cache/deb-pkg-tools'
"""The pathname of the global (system wide) package cache directory (a string)."""

user_config_directory = parse_path('~/.deb-pkg-tools')
"""
The pathname of the current user's configuration directory used by `deb-pkg-tools` (a string).

:default: The expanded value of ``~/.deb-pkg-tools``.
"""

user_cache_directory = parse_path('~/.cache/deb-pkg-tools')
"""
The pathname of the current user's package cache directory (a string).

:default: The expanded value of ``~/.cache/deb-pkg-tools``.
"""

# The location of the package cache. If we're running as root we have write
# access to the system wide package cache so we'll pick that; the more users