Example #1
0
def setUpModule():
    """
    Prepare the test suite.

    This function does two things:

    1. Sets up verbose logging to the terminal. When a test fails the logging
       output can help to perform a post-mortem analysis of the failure in
       question (even when its hard to reproduce locally). This is especially
       useful when debugging remote test failures, whether they happened on
       Travis CI or a user's local system.

    2. Creates temporary directories where the pip download cache and the
       pip-accel binary cache are located. Isolating the pip-accel binary cache
       from the user's system is meant to ensure that the tests are as
       independent from the user's system as possible. The function
       :py:func:`tearDownModule` is responsible for cleaning up the temporary
       directory after the test suite finishes.
    """
    # Initialize verbose logging to the terminal.
    coloredlogs.install()
    coloredlogs.increase_verbosity()
    # Create temporary directories to store the pip download cache and
    # pip-accel's binary cache, to make sure these tests run isolated from the
    # rest of the system.
    os.environ['PIP_DOWNLOAD_CACHE'] = create_temporary_directory()
    os.environ['PIP_ACCEL_CACHE'] = create_temporary_directory()
Example #2
0
def main():
    """The command line interface for the ``pip-accel`` program."""
    arguments = sys.argv[1:]
    # If no arguments are given, the help text of pip-accel is printed.
    if not arguments:
        usage()
        sys.exit(0)
    # If no install subcommand is given we pass the command line straight
    # to pip without any changes and exit immediately afterwards.
    if 'install' not in arguments:
        # This will not return.
        os.execvp('pip', ['pip'] + arguments)
    else:
        arguments = [arg for arg in arguments if arg != 'install']
    # Initialize logging output.
    coloredlogs.install()
    # Adjust verbosity based on -v, -q, --verbose, --quiet options.
    for argument in list(arguments):
        if match_option(argument, '-v', '--verbose'):
            coloredlogs.increase_verbosity()
        elif match_option(argument, '-q', '--quiet'):
            coloredlogs.decrease_verbosity()
    # Perform the requested action(s).
    try:
        accelerator = PipAccelerator(Config())
        accelerator.install_from_arguments(arguments)
    except NothingToDoError as e:
        # Don't print a traceback for this (it's not very user friendly) and
        # exit with status zero to stay compatible with pip. For more details
        # please refer to https://github.com/paylogic/pip-accel/issues/47.
        logger.warning("%s", e)
        sys.exit(0)
    except Exception:
        logger.exception("Caught unhandled exception!")
        sys.exit(1)
Example #3
0
def parse_arguments(arguments):
    """
    Parse the command line arguments.

    :param arguments: A list of strings with command line options and/or arguments.
    :returns: A list of strings with the positional arguments.
    """
    try:
        options, arguments = getopt.gnu_getopt(arguments, 'vqh', [
            'verbose', 'quiet', 'help'
        ])
        for option, value in options:
            if option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(USAGE_TEXT)
                sys.exit(0)
            else:
                assert False, "Unhandled option!"
        if not arguments:
            usage(USAGE_TEXT)
            sys.exit(0)
        return arguments
    except Exception as e:
        warning("Error: Failed to parse command line arguments! (%s)", e)
        sys.exit(1)
Example #4
0
def main():
    """Command line interface for the ``dwim`` program."""
    from dwim import DEFAULT_PROFILE, dwim
    # Initialize logging to the terminal.
    coloredlogs.install()
    # Define the command line option defaults.
    profile_script = DEFAULT_PROFILE
    # Parse the command line arguments.
    try:
        options, _ = getopt.getopt(sys.argv[1:], 'c:vqh', [
            'config=', 'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-c', '--config'):
                profile_script = 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)
    except Exception as e:
        warning("Error: Failed to parse command line arguments! (%s)", e)
        sys.exit(1)
    # Execute the requested action(s).
    try:
        dwim(profile_script)
    except Exception:
        logger.exception("Caught a fatal exception! Terminating ..")
        sys.exit(1)
Example #5
0
def setUpModule():
    """
    Prepare the test suite.

    This function does two things:

    1. Sets up verbose logging to the terminal. When a test fails the logging
       output can help to perform a post-mortem analysis of the failure in
       question (even when its hard to reproduce locally). This is especially
       useful when debugging remote test failures, whether they happened on
       Travis CI or a user's local system.

    2. Creates temporary directories where the pip download cache and the
       pip-accel binary cache are located. Isolating the pip-accel binary cache
       from the user's system is meant to ensure that the tests are as
       independent from the user's system as possible. The function
       :func:`tearDownModule` is responsible for cleaning up the temporary
       directory after the test suite finishes.
    """
    # Initialize verbose logging to the terminal.
    coloredlogs.install()
    coloredlogs.increase_verbosity()
    # Create temporary directories to store the pip download cache and
    # pip-accel's binary cache, to make sure these tests run isolated from the
    # rest of the system.
    os.environ['PIP_DOWNLOAD_CACHE'] = create_temporary_directory()
    os.environ['PIP_ACCEL_CACHE'] = create_temporary_directory()
Example #6
0
def main():
    """The command line interface for the ``pip-accel`` program."""
    arguments = sys.argv[1:]
    # If no arguments are given, the help text of pip-accel is printed.
    if not arguments:
        usage()
        sys.exit(0)
    # If no install subcommand is given we pass the command line straight
    # to pip without any changes and exit immediately afterwards.
    if 'install' not in arguments:
        # This will not return.
        os.execvp('pip', ['pip'] + arguments)
    else:
        arguments = [arg for arg in arguments if arg != 'install']
    # Initialize logging output.
    coloredlogs.install()
    # Adjust verbosity based on -v, -q, --verbose, --quiet options.
    for argument in list(arguments):
        if match_option(argument, '-v', '--verbose'):
            coloredlogs.increase_verbosity()
        elif match_option(argument, '-q', '--quiet'):
            coloredlogs.decrease_verbosity()
    # Perform the requested action(s).
    try:
        accelerator = PipAccelerator(Config())
        accelerator.install_from_arguments(arguments)
    except NothingToDoError as e:
        # Don't print a traceback for this (it's not very user friendly).
        logger.error("%s", e)
        sys.exit(1)
    except Exception:
        logger.exception("Caught unhandled exception!")
        sys.exit(1)
Example #7
0
def main():
    """The command line interface for the ``pip-accel`` program."""
    arguments = sys.argv[1:]
    # If no arguments are given, the help text of pip-accel is printed.
    if not arguments:
        usage()
        sys.exit(0)
    # If no install subcommand is given we pass the command line straight
    # to pip without any changes and exit immediately afterwards.
    if 'install' not in arguments:
        # This will not return.
        os.execvp('pip', ['pip'] + arguments)
    else:
        arguments = [arg for arg in arguments if arg != 'install']
    # Initialize logging output.
    coloredlogs.install()
    # Adjust verbosity based on -v, -q, --verbose, --quiet options.
    for argument in list(arguments):
        if match_option(argument, '-v', '--verbose'):
            coloredlogs.increase_verbosity()
        elif match_option(argument, '-q', '--quiet'):
            coloredlogs.decrease_verbosity()
    # Perform the requested action(s).
    try:
        accelerator = PipAccelerator(Config())
        accelerator.install_from_arguments(arguments)
    except Exception:
        logger.exception("Caught unhandled exception!")
        sys.exit(1)
Example #8
0
def parse_arguments(arguments):
    """
    Parse the command line arguments.

    :param arguments: A list of strings with command line arguments.
    :returns: ``True`` if a dry run was requested, ``False`` otherwise.
    """
    dry_run = False
    try:
        options, arguments = getopt.gnu_getopt(
            arguments, 'nvqh', ['dry-run', 'verbose', 'quiet', 'help'])
        for option, value in options:
            if option in ('-n', '--dry-run'):
                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(USAGE_TEXT)
                sys.exit(0)
            else:
                assert False, "Unhandled option!"
        return dry_run
    except Exception as e:
        warning("Error: Failed to parse command line arguments! (%s)", e)
        sys.exit(1)
Example #9
0
def main():
    """Command line interface for the ``auto-adjust-display-brightness`` program."""
    # Initialize logging to the terminal.
    coloredlogs.install()
    # Parse the command line arguments.
    step_brightness = None
    try:
        options, arguments = getopt.getopt(
            sys.argv[1:], 'fvqh', ['force', 'verbose', 'quiet', 'help'])
        for option, value in options:
            if option in ('-f', '--force'):
                step_brightness = False
            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!"
    except Exception as e:
        warning("Failed to parse command line arguments! (%s)", e)
        sys.exit(1)
    # Load the configuration file(s).
    try:
        config = load_config()
    except ConfigurationError as e:
        warning("%s", e)
        sys.exit(1)
    # Determine whether to change the brightness at once or gradually.
    if step_brightness is None:
        if find_system_uptime() < 60 * 5:
            logger.info(
                "Changing brightness at once (system has just booted).")
            step_brightness = False
        else:
            logger.info(
                "Changing brightness gradually (system has been running for a while)."
            )
            step_brightness = True
    else:
        logger.info("Changing brightness at once (-f or --force was given).")
    # Change the brightness of the configured display(s).
    dark_outside = is_it_dark_outside(
        latitude=float(config['location']['latitude']),
        longitude=float(config['location']['longitude']),
        elevation=float(config['location']['elevation']))
    method = 'decrease_brightness' if dark_outside else 'increase_brightness'
    num_success, num_failed = 0, 0
    for controller in config['controllers']:
        try:
            getattr(controller, method)(10 if step_brightness else 100)
            num_success += 1
        except Exception as e:
            logger.warning("Failed to change brightness of %s! (%s)",
                           controller, e)
            num_failed += 1
    if num_failed > 0 and num_success == 0:
        sys.exit(1)
Example #10
0
def main():
    """Command line interface for the ``qpass`` program."""
    # Initialize logging to the terminal.
    coloredlogs.install()
    # Prepare for command line argument parsing.
    action = show_matching_entry
    program_opts = dict(exclude_list=[])
    show_opts = dict(filters=[], use_clipboard=is_clipboard_supported())
    verbosity = 0
    # Parse the command line arguments.
    try:
        options, arguments = getopt.gnu_getopt(
            sys.argv[1:],
            "elnp:f:x:vqh",
            ["edit", "list", "no-clipboard", "password-store=", "filter=", "exclude=", "verbose", "quiet", "help"],
        )
        for option, value in options:
            if option in ("-e", "--edit"):
                action = edit_matching_entry
            elif option in ("-l", "--list"):
                action = list_matching_entries
            elif option in ("-n", "--no-clipboard"):
                show_opts["use_clipboard"] = False
            elif option in ("-p", "--password-store"):
                stores = program_opts.setdefault("stores", [])
                stores.append(PasswordStore(directory=value))
            elif option in ("-f", "--filter"):
                show_opts["filters"].append(value)
            elif option in ("-x", "--exclude"):
                program_opts["exclude_list"].append(value)
            elif option in ("-v", "--verbose"):
                coloredlogs.increase_verbosity()
                verbosity += 1
            elif option in ("-q", "--quiet"):
                coloredlogs.decrease_verbosity()
                verbosity -= 1
            elif option in ("-h", "--help"):
                usage(__doc__)
                return
            else:
                raise Exception("Unhandled option! (programming error)")
        if not (arguments or action == list_matching_entries):
            usage(__doc__)
            return
    except Exception as e:
        warning("Error: %s", e)
        sys.exit(1)
    # Execute the requested action.
    try:
        show_opts["quiet"] = verbosity < 0
        kw = show_opts if action == show_matching_entry else {}
        action(QuickPass(**program_opts), arguments, **kw)
    except PasswordStoreError as e:
        # Known issues don't get a traceback.
        logger.error("%s", e)
        sys.exit(1)
    except KeyboardInterrupt:
        # If the user interrupted an interactive prompt they most likely did so
        # intentionally, so there's no point in generating more output here.
        sys.exit(1)
Example #11
0
def main():
    """Command line interface for the ``negotiator-guest`` program."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line arguments.
    list_commands = False
    execute_command = None
    start_daemon = False
    timeout = DEFAULT_TIMEOUT
    character_device = None
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'le:dt:c:vqh', [
            'list-commands', 'execute=', 'daemon', 'timeout=',
            'character-device=', 'verbose', 'quiet', 'help'
        ])
        for option, value in options:
            if option in ('-l', '--list-commands'):
                list_commands = True
            elif option in ('-e', '--execute'):
                execute_command = value
            elif option in ('-d', '--daemon'):
                start_daemon = True
            elif option in ('-t', '--timeout'):
                timeout = int(value)
            elif option in ('-c', '--character-device'):
                character_device = value
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage()
                sys.exit(0)
        if not (list_commands or execute_command or start_daemon):
            usage()
            sys.exit(0)
    except Exception:
        logger.exception("Failed to parse command line arguments!")
        sys.exit(1)
    # Start the guest daemon.
    try:
        if not character_device:
            channel_name = HOST_TO_GUEST_CHANNEL_NAME if start_daemon else GUEST_TO_HOST_CHANNEL_NAME
            character_device = find_character_device(channel_name)
        ga = GuestAgent(character_device)
        if start_daemon:
            ga.enter_main_loop()
        elif list_commands:
            with TimeOut(timeout):
                print('\n'.join(ga.call_remote_method('list_commands')))
        elif execute_command:
            with TimeOut(timeout):
                timer = Timer()
                output = ga.call_remote_method('execute', *shlex.split(execute_command), capture=True)
                logger.debug("Took %s to execute remote command.", timer)
                print(output.rstrip())
    except Exception:
        logger.exception("Caught a fatal exception! Terminating ..")
        sys.exit(1)
Example #12
0
def main():
    """Command line interface for the ``negotiator-guest`` program."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line arguments.
    list_commands = False
    execute_command = None
    start_daemon = False
    timeout = DEFAULT_TIMEOUT
    character_device = None
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'le:dt:c:vqh', [
            'list-commands', 'execute=', 'daemon', 'timeout=',
            'character-device=', 'verbose', 'quiet', 'help'
        ])
        for option, value in options:
            if option in ('-l', '--list-commands'):
                list_commands = True
            elif option in ('-e', '--execute'):
                execute_command = value
            elif option in ('-d', '--daemon'):
                start_daemon = True
            elif option in ('-t', '--timeout'):
                timeout = int(value)
            elif option in ('-c', '--character-device'):
                character_device = 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)
        if not (list_commands or execute_command or start_daemon):
            usage(__doc__)
            sys.exit(0)
    except Exception:
        warning("Error: Failed to parse command line arguments!")
        sys.exit(1)
    # Start the guest daemon.
    try:
        if not character_device:
            channel_name = HOST_TO_GUEST_CHANNEL_NAME if start_daemon else GUEST_TO_HOST_CHANNEL_NAME
            character_device = find_character_device(channel_name)
        ga = GuestAgent(character_device)
        if start_daemon:
            ga.enter_main_loop()
        elif list_commands:
            with TimeOut(timeout):
                print('\n'.join(ga.call_remote_method('list_commands')))
        elif execute_command:
            with TimeOut(timeout):
                timer = Timer()
                output = ga.call_remote_method('execute', *shlex.split(execute_command), capture=True)
                logger.debug("Took %s to execute remote command.", timer)
                print(output.rstrip())
    except Exception:
        logger.exception("Caught a fatal exception! Terminating ..")
        sys.exit(1)
def main():
    """Command line interface for ``debuntu-nodejs-installer``."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    silence_urllib_logger()
    # Parse the command line arguments.
    action = None
    context_opts = dict()
    installer_opts = dict()
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'iV:s:r:vqh', [
            'install',
            'version=',
            'sources-file=',
            'remote-host=',
            'verbose',
            'quiet',
            'help',
        ])
        for option, value in options:
            if option in ('-i', '--install'):
                action = 'install'
            elif option in ('-V', '--version'):
                installer_opts['nodejs_version'] = value
            elif option in ('-s', '--sources-file'):
                installer_opts['sources_file'] = value
            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__)
                sys.exit(0)
            else:
                raise Exception("Unhandled option!")
        if arguments:
            raise Exception(
                "This program doesn't accept any positional arguments!")
        if not action:
            usage(__doc__)
            sys.exit(0)
    except Exception as e:
        warning("Failed to parse command line arguments! (%s)", e)
        sys.exit(1)
    # Execute the requested action.
    context = create_context(**context_opts)
    try:
        installer = NodeInstaller(context=context, **installer_opts)
        getattr(installer, action)()
    except (UnsupportedSystemError, ExternalCommandFailed) as e:
        logger.error("%s", e)
        sys.exit(1)
    except Exception:
        logger.exception("Encountered unexpected exception on %s!", context)
        sys.exit(1)
Example #14
0
def main():
    """
    Main logic of the ``pip-accel`` command.
    """
    arguments = sys.argv[1:]
    # If no arguments are given, the help text of pip-accel is printed.
    if not arguments:
        print_usage()
        sys.exit(0)
    # If no install subcommand is given we pass the command line straight
    # to pip without any changes and exit immediately afterwards.
    elif 'install' not in arguments:
        sys.exit(os.spawnvp(os.P_WAIT, 'pip', ['pip'] + arguments))
    # Initialize logging output.
    coloredlogs.install()
    # Increase verbosity based on -v, --verbose options.
    for argument in arguments:
        if argument == '--verbose' or (len(argument) >= 2 and argument[0] ==
                '-' and argument[1] != '-' and 'v' in argument):
            coloredlogs.increase_verbosity()
    # Make sure the prefix is the same as the environment.
    if not os.path.samefile(sys.prefix, ENVIRONMENT):
        logger.error("You are trying to install packages in environment #1 which is different from environment #2 where pip-accel is installed! Please install pip-accel under environment #1 to install packages there.")
        logger.info("Environment #1: %s ($VIRTUAL_ENV)", ENVIRONMENT)
        logger.info("Environment #2: %s (installation prefix)", sys.prefix)
        sys.exit(1)
    main_timer = Timer()
    initialize_directories()
    build_directory = tempfile.mkdtemp()
    # Execute "pip install" in a loop in order to retry after intermittent
    # error responses from servers (which can happen quite frequently).
    try:
        for i in xrange(1, MAX_RETRIES):
            try:
                requirements = unpack_source_dists(arguments, build_directory)
            except DistributionNotFound:
                logger.warn("We don't have all source distributions yet!")
                download_source_dists(arguments, build_directory)
            else:
                if not requirements:
                    logger.info("No unsatisfied requirements found, probably there's nothing to do.")
                else:
                    install_requirements(requirements)
                    logger.info("Done! Took %s to install %i package%s.", main_timer, len(requirements), '' if len(requirements) == 1 else 's')
                return
            logger.warn("pip failed, retrying (%i/%i) ..", i + 1, MAX_RETRIES)
    except InstallationError:
        # Abort early when pip reports installation errors.
        logger.fatal("pip reported unrecoverable installation errors. Please fix and rerun!")
        sys.exit(1)
    finally:
        # Always cleanup temporary build directory.
        shutil.rmtree(build_directory)
    # Abort when after N retries we still failed to download source distributions.
    logger.fatal("External command failed %i times, aborting!" % MAX_RETRIES)
    sys.exit(1)
Example #15
0
def main():
    """Command line interface for the ``qpass`` program."""
    # Initialize logging to the terminal.
    coloredlogs.install()
    # Prepare for command line argument parsing.
    action = show_matching_entry
    program_opts = dict()
    show_opts = dict(use_clipboard=is_clipboard_supported())
    # Parse the command line arguments.
    try:
        options, arguments = getopt.gnu_getopt(sys.argv[1:], 'elnp:vqh', [
            'edit',
            'list',
            'no-clipboard',
            'password-store=',
            'verbose',
            'quiet',
            'help',
        ])
        for option, value in options:
            if option in ('-e', '--edit'):
                action = edit_matching_entry
            elif option in ('-l', '--list'):
                action = list_matching_entries
            elif option in ('-n', '--no-clipboard'):
                show_opts['use_clipboard'] = False
            elif option in ('-p', '--password-store'):
                stores = program_opts.setdefault('stores', [])
                stores.append(PasswordStore(directory=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:
                raise Exception("Unhandled option! (programming error)")
        if not (arguments or action == list_matching_entries):
            usage(__doc__)
            return
    except Exception as e:
        warning("Error: %s", e)
        sys.exit(1)
    # Execute the requested action.
    try:
        action(QuickPass(**program_opts), arguments,
               **(show_opts if action == show_matching_entry else {}))
    except PasswordStoreError as e:
        # Known issues don't get a traceback.
        logger.error("%s", e)
        sys.exit(1)
    except KeyboardInterrupt:
        # If the user interrupted an interactive prompt they most likely did so
        # intentionally, so there's no point in generating more output here.
        sys.exit(1)
Example #16
0
def build_and_parse_args(args=None):
    parser = create_parser()
    if args is None:
        args = argv[1:]
    known, unknown = parser.parse_known_args(args)
    for _ in list(range(0, known.verbose)):
        increase_verbosity()
    for _ in list(range(0, known.quiet)):
        decrease_verbosity()
    return unknown
Example #17
0
def main():
    """Command line interface for the ``negotiator-host`` program."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line arguments.
    actions = []
    context = Context()
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'gce:t:dvqh', [
            'list-guests', 'list-commands', 'execute=', 'timeout=', 'daemon',
            'verbose', 'quiet', 'help'
        ])
        for option, value in options:
            if option in ('-g', '--list-guests'):
                actions.append(context.print_guest_names)
            elif option in ('-c', '--list-commands'):
                assert len(arguments) == 1, \
                    "Please provide the name of a guest as the 1st and only positional argument!"
                actions.append(
                    functools.partial(context.print_commands, arguments[0]))
            elif option in ('-e', '--execute'):
                assert len(arguments) == 1, \
                    "Please provide the name of a guest as the 1st and only positional argument!"
                actions.append(
                    functools.partial(context.execute_command, arguments[0],
                                      value))
            elif option in ('-t', '--timeout'):
                context.timeout = int(value)
            elif option in ('-d', '--daemon'):
                actions.append(HostDaemon)
            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)
        if not actions:
            usage(__doc__)
            sys.exit(0)
    except Exception:
        warning("Failed to parse command line arguments!")
        sys.exit(1)
    # Execute the requested action(s).
    try:
        for action in actions:
            action()
    except GuestDiscoveryError as e:
        # Don't spam the logs with tracebacks when the libvirt daemon is down.
        logger.error("%s", e)
        sys.exit(1)
    except Exception:
        # Do log a traceback for `unexpected' exceptions.
        logger.exception("Caught a fatal exception! Terminating ..")
        sys.exit(1)
Example #18
0
def main():
    """Command line interface for ``debuntu-kernel-manager``."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line arguments.
    action = 'render_summary'
    context_opts = dict()
    manager_opts = dict()
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'cfp:r:vqh', [
            'clean',
            'remove',
            'force',
            'preserve-count=',
            'remote-host=',
            'verbose',
            'quiet',
            'help',
        ])
        for option, value in options:
            if option in ('-c', '--clean', '--remove'):
                action = 'cleanup_packages'
            elif option in ('-f', '--force'):
                manager_opts['force'] = True
            elif option in ('-p', '--preserve-count'):
                manager_opts['preserve_count'] = int(value)
            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:
                raise Exception("Unhandled option!")
        # Any positional arguments are passed to apt-get.
        manager_opts['apt_options'] = arguments
    except Exception as e:
        warning("Failed to parse command line arguments! (%s)", e)
        sys.exit(1)
    # Execute the requested action(s).
    context = create_context(**context_opts)
    try:
        manager = KernelPackageManager(context=context, **manager_opts)
        getattr(manager, action)()
    except (CleanupError, ExternalCommandFailed) as e:
        logger.error("%s", e)
        sys.exit(1)
    except Exception:
        logger.exception("Encountered unexpected exception on %s!", context)
        sys.exit(1)
Example #19
0
def main():
    """Command line interface for the ``update-dotdee`` program."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line arguments.
    context_opts = {}
    program_opts = {}
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'fur:vqh', [
            'force',
            'use-sudo',
            'remote-host=',
            'verbose',
            'quiet',
            'help',
        ])
        for option, value in options:
            if option in ('-f', '--force'):
                program_opts['force'] = True
            elif option in ('-u', '--use-sudo'):
                context_opts['sudo'] = True
            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__)
                sys.exit(0)
            else:
                # Programming error...
                assert False, "Unhandled option!"
        if not arguments:
            usage(__doc__)
            sys.exit(0)
        if len(arguments) != 1:
            raise Exception(
                "Expected a filename as the first and only argument!")
        program_opts['filename'] = arguments[0]
    except Exception as e:
        warning("Error: %s", e)
        sys.exit(1)
    # Run the program.
    try:
        # Initialize the execution context.
        program_opts['context'] = create_context(**context_opts)
        # Initialize the program and update the file.
        UpdateDotDee(**program_opts).update_file()
    except Exception as e:
        logger.exception("Encountered unexpected exception, aborting!")
        sys.exit(1)
Example #20
0
def main():
    """Command line interface for the ``negotiator-host`` program."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line arguments.
    actions = []
    context = Context()
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'gce:t:dvqh', [
            'list-guests', 'list-commands', 'execute=', 'timeout=', 'daemon',
            'verbose', 'quiet', 'help'
        ])
        for option, value in options:
            if option in ('-g', '--list-guests'):
                actions.append(context.print_guest_names)
            elif option in ('-c', '--list-commands'):
                assert len(arguments) == 1, \
                    "Please provide the name of a guest as the 1st and only positional argument!"
                actions.append(functools.partial(context.print_commands, arguments[0]))
            elif option in ('-e', '--execute'):
                assert len(arguments) == 1, \
                    "Please provide the name of a guest as the 1st and only positional argument!"
                actions.append(functools.partial(context.execute_command, arguments[0], value))
            elif option in ('-t', '--timeout'):
                context.timeout = int(value)
            elif option in ('-d', '--daemon'):
                actions.append(HostDaemon)
            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)
        if not actions:
            usage(__doc__)
            sys.exit(0)
    except Exception:
        warning("Failed to parse command line arguments!")
        sys.exit(1)
    # Execute the requested action(s).
    try:
        for action in actions:
            action()
    except GuestDiscoveryError as e:
        # Don't spam the logs with tracebacks when the libvirt daemon is down.
        logger.error("%s", e)
        sys.exit(1)
    except Exception:
        # Do log a traceback for `unexpected' exceptions.
        logger.exception("Caught a fatal exception! Terminating ..")
        sys.exit(1)
Example #21
0
def main():
    """Command line interface for ``debuntu-kernel-manager``."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line arguments.
    action = "render_summary"
    context_opts = dict()
    manager_opts = dict()
    try:
        options, arguments = getopt.getopt(
            sys.argv[1:],
            "cfp:r:vqh",
            [
                "clean", "remove", "force", "preserve-count=", "remote-host=",
                "verbose", "quiet", "help"
            ],
        )
        for option, value in options:
            if option in ("-c", "--clean", "--remove"):
                action = "cleanup_packages"
            elif option in ("-f", "--force"):
                manager_opts["force"] = True
            elif option in ("-p", "--preserve-count"):
                manager_opts["preserve_count"] = int(value)
            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:
                raise Exception("Unhandled option!")
        # Any positional arguments are passed to apt-get.
        manager_opts["apt_options"] = arguments
    except Exception as e:
        warning("Failed to parse command line arguments! (%s)", e)
        sys.exit(1)
    # Execute the requested action(s).
    context = create_context(**context_opts)
    try:
        manager = KernelPackageManager(context=context, **manager_opts)
        getattr(manager, action)()
    except (CleanupError, ExternalCommandFailed) as e:
        logger.error("%s", e)
        sys.exit(1)
    except Exception:
        logger.exception("Encountered unexpected exception on %s!", context)
        sys.exit(1)
def main():
    """Command line interface for ``reboot-remote-system``."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line arguments.
    do_shell = False
    try:
        options, arguments = getopt.gnu_getopt(sys.argv[1:], 'svqh', [
            'shell',
            'verbose',
            'quiet',
            'help',
        ])
        for option, value in options:
            if option in ('-s', '--shell'):
                do_shell = 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) > 1:
            raise Exception("only one positional argument allowed")
    except Exception as e:
        warning("Failed to parse command line arguments! (%s)", e)
        sys.exit(1)
    # Reboot the remote system.
    try:
        account = RemoteAccount(arguments[0])
        context = get_post_context(arguments[0])
        reboot_remote_system(context=context, name=account.ssh_alias)
        if do_shell:
            start_interactive_shell(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)
Example #23
0
 def test_increase_verbosity(self):
     """Make sure increase_verbosity() respects default and custom levels."""
     assert coloredlogs.root_handler.level == logging.INFO
     coloredlogs.increase_verbosity()
     assert coloredlogs.root_handler.level == logging.VERBOSE
     coloredlogs.increase_verbosity()
     assert coloredlogs.root_handler.level == logging.DEBUG
     coloredlogs.increase_verbosity()
     assert coloredlogs.root_handler.level == logging.NOTSET
     coloredlogs.increase_verbosity()
     assert coloredlogs.root_handler.level == logging.NOTSET
Example #24
0
def main():
    """Command line interface for the ``preview`` program."""
    # Initialize logging to the terminal.
    coloredlogs.install()
    # Parse the command line arguments.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'vqh', [
            'verbose', 'quiet', 'help'
        ])
        for option, value in options:
            if option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage()
                return
            else:
                assert False, "Unhandled option!"
        if not arguments:
            arguments = ['.']
        elif len(arguments) > 1:
            raise Exception("Only one positional argument may be given!")
    except Exception as e:
        print("Failed to parse command line arguments! (%s)" % e)
        print("")
        usage()
        sys.exit(1)
    try:
        if os.path.isdir(arguments[0]):
            start_webserver(find_readme_file(arguments[0]))
        elif os.path.isfile(arguments[0]):
            start_webserver(arguments[0])
        else:
            raise Exception("Input doesn't exist!")
    except KeyboardInterrupt:
        sys.stderr.write('\r')
        logger.error("Interrupted by Control-C, terminating ..")
        sys.exit(1)
    except Exception:
        logger.exception("Encountered an unhandled exception, terminating!")
        sys.exit(1)
Example #25
0
 def test_increase_verbosity(self):
     """Make sure increase_verbosity() respects default and custom levels."""
     # Start from a known state.
     set_level(logging.INFO)
     assert get_level() == logging.INFO
     # INFO -> VERBOSE.
     increase_verbosity()
     assert get_level() == logging.VERBOSE
     # VERBOSE -> DEBUG.
     increase_verbosity()
     assert get_level() == logging.DEBUG
     # DEBUG -> SPAM.
     increase_verbosity()
     assert get_level() == logging.SPAM
     # SPAM -> NOTSET.
     increase_verbosity()
     assert get_level() == logging.NOTSET
     # NOTSET -> NOTSET.
     increase_verbosity()
     assert get_level() == logging.NOTSET
Example #26
0
 def test_increase_verbosity(self):
     """Make sure increase_verbosity() respects default and custom levels."""
     # Start from a known state.
     set_level(logging.INFO)
     assert get_level() == logging.INFO
     # INFO -> VERBOSE.
     increase_verbosity()
     assert get_level() == logging.VERBOSE
     # VERBOSE -> DEBUG.
     increase_verbosity()
     assert get_level() == logging.DEBUG
     # DEBUG -> SPAM.
     increase_verbosity()
     assert get_level() == logging.SPAM
     # SPAM -> NOTSET.
     increase_verbosity()
     assert get_level() == logging.NOTSET
     # NOTSET -> NOTSET.
     increase_verbosity()
     assert get_level() == logging.NOTSET
Example #27
0
def main():
    """
    Command line interface for the ``redock`` program.
    """
    # Initialize coloredlogs.
    coloredlogs.install()
    # Parse and validate the command line arguments.
    try:
        # Command line option defaults.
        hostname = None
        message = None
        # Parse the command line options.
        options, arguments = getopt.getopt(sys.argv[1:], 'b:n:m:vh',
                                          ['hostname=', 'message=', 'verbose', 'help'])
        for option, value in options:
            if option in ('-n', '--hostname'):
                hostname = value
            elif option in ('-m', '--message'):
                message = value
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-h', '--help'):
                usage()
                return
            else:
                # Programming error...
                assert False, "Unhandled option!"
        # Handle the positional arguments.
        if len(arguments) < 2:
            usage()
            return
        supported_actions = ('start', 'commit', 'kill', 'delete')
        action = arguments.pop(0)
        if action not in supported_actions:
            msg = "Action not supported: %r (supported actions are: %s)"
            raise Exception, msg % (action, ', '.join(supported_actions))
    except Exception, e:
        logger.error("Failed to parse command line arguments!")
        logger.exception(e)
        usage()
        sys.exit(1)
Example #28
0
def main():
    """Command line interface for the ``dwim`` program."""
    # Initialize logging to the terminal.
    coloredlogs.install()
    # Define the command line option defaults.
    profile = '~/.dwimrc'
    # Parse the command line arguments.
    try:
        options, arguments = getopt.getopt(
            sys.argv[1:], 'c:vqh', ['config=', 'verbose', 'quiet', 'help'])
        for option, value in options:
            if option in ('-c', '--config'):
                profile = value
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage()
                sys.exit(0)
    except Exception:
        logger.exception("Failed to parse command line arguments!")
        sys.exit(1)
    # Execute the requested action(s).
    try:
        logger.info("Initializing dwim %s ..", __version__)
        # Load the user's profile script.
        filename = os.path.expanduser(profile)
        environment = dict(
            __file__=filename,
            __name__='dwimrc',
            launch_program=launch_program,
            LaunchStatus=LaunchStatus,
            set_random_background=set_random_background,
            wait_for_internet_connection=wait_for_internet_connection)
        logger.info("Loading %s ..", filename)
        execfile(filename, environment, environment)
    except Exception:
        logger.exception("Caught a fatal exception! Terminating ..")
        sys.exit(1)
Example #29
0
def main():
    """Command line interface for the ``apache-manager`` program."""
    # Configure logging output.
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    data_file = '/tmp/apache-manager.txt'
    dry_run = False
    max_memory_active = None
    max_memory_idle = None
    max_ss = None
    watch = False
    zabbix_discovery = False
    verbosity = 0
    # Parse the command line options.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'wa:i:t:f:znvqh', [
            'watch', 'max-memory-active=', 'max-memory-idle=', 'max-ss=',
            'max-time=', 'data-file=', 'zabbix-discovery', 'dry-run',
            'simulate', 'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-w', '--watch'):
                watch = True
            elif option in ('-a', '--max-memory-active'):
                max_memory_active = parse_size(value)
            elif option in ('-i', '--max-memory-idle'):
                max_memory_idle = parse_size(value)
            elif option in ('-t', '--max-ss', '--max-time'):
                max_ss = parse_timespan(value)
            elif option in ('-f', '--data-file'):
                data_file = value
            elif option in ('-z', '--zabbix-discovery'):
                zabbix_discovery = True
            elif option in ('-n', '--dry-run', '--simulate'):
                logger.info("Performing a dry run ..")
                dry_run = True
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
                verbosity += 1
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
                verbosity -= 1
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
    except Exception as e:
        sys.stderr.write("Error: %s!\n" % e)
        sys.exit(1)
    # Execute the requested action(s).
    manager = ApacheManager()
    try:
        if max_memory_active or max_memory_idle or max_ss:
            manager.kill_workers(
                max_memory_active=max_memory_active,
                max_memory_idle=max_memory_idle,
                timeout=max_ss,
                dry_run=dry_run,
            )
        elif watch and connected_to_terminal(sys.stdout):
            watch_metrics(manager)
        elif zabbix_discovery:
            report_zabbix_discovery(manager)
        elif data_file != '-' and verbosity >= 0:
            for line in report_metrics(manager):
                if line_is_heading(line):
                    line = ansi_wrap(line, color=HIGHLIGHT_COLOR)
                print(line)
    finally:
        if (not watch) and (data_file == '-' or not dry_run):
            manager.save_metrics(data_file)
Example #30
0
def main():
    pref_locale = locale.getlocale()[0]
    locale.setlocale(locale.LC_TIME, pref_locale)
    locale.setlocale(locale.LC_MONETARY, pref_locale)

    logger = logging.getLogger('srmlf')
    coloredlogs.install(fmt='%(message)s',
                        level=logging.INFO)
    try:

        parser = argparse.ArgumentParser(description='SRMLF is a lightweight '
                                         'accountability tracker')
        parser.add_argument('-v', '--verbose', help='Show debug info',
                            action='store_true', dest='verbose')

        commands = parser.add_subparsers(help='Commands help', dest='command')
        init = commands.add_parser('init', aliases=['i'])
        init.add_argument('project_name', help='Project to use',
                          action='store')
        init.add_argument('-t', '--total', help='Total amount to reach',
                          type=int,
                          action='store')
        init.add_argument('users', help='Names of users', type=str,
                          action='store', nargs='+')

        add = commands.add_parser('add', aliases=['a'])
        add.add_argument('project_name', help='Project to use',
                         action='store')
        add.add_argument('-d', '--date', help='date of the contribution you '
                         'want to create (format: {})'
                         .format(locale.nl_langinfo(locale.D_FMT)
                                 .replace('%', '%%')),
                         default=datetime.now(),
                         type=valid_date)
        add.add_argument('label', help='Label of the contribution',
                         type=str)
        add.add_argument('contribs', type=valid_user_contrib,
                         help='User names and amounts',
                         action='store', nargs='+')

        view = commands.add_parser('view', aliases=['v'])
        view.add_argument('project_name', help='Project to use',
                          action='store')

        args = parser.parse_args()

        if args.verbose:
            coloredlogs.increase_verbosity()

        if not os.path.isdir(DATA_DIR):
            logger.debug('Creating inexistant data directory (%s)', DATA_DIR)
            os.mkdir(DATA_DIR)

        if args.command == 'init':
            logger.info('Creating project %s…', args.project_name)
            Project.create(args.project_name, args.users, args.total)

        elif args.command == 'add':
            logger.info('Adding %d contribution%s…',
                        len(args.contribs),
                        's' if len(args.contribs) > 1 else '')
            project = Project(args.project_name)
            project.add_contribs(args.label, args.date, args.contribs)
            project.save()

        elif args.command == 'view':
            project = Project(args.project_name)
            print(project)

        else:
            parser.print_help()

    except SRMLFException as e:
        logger.error(e)
    except Exception as e:
        logger.error(e)
        raise
Example #31
0
def main():
    """Command line interface for the ``apt-smart`` program."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    context = LocalContext()
    updater = AptMirrorUpdater(context=context)
    limit = MAX_MIRRORS
    url_char_len = URL_CHAR_LEN
    actions = []
    # Parse the command line arguments.
    try:
        options, arguments = getopt.getopt(sys.argv[1:],
                                           'r:fF:blL:c:aux:m:vVR:qh', [
                                               'remote-host=',
                                               'find-current-mirror',
                                               'find-best-mirror',
                                               'file-to-read=',
                                               'list-mirrors',
                                               'url-char-len=',
                                               'change-mirror',
                                               'auto-change-mirror',
                                               'update',
                                               'update-package-lists',
                                               'exclude=',
                                               'max=',
                                               'verbose',
                                               'version',
                                               'create-chroot=',
                                               'quiet',
                                               'help',
                                           ])
        for option, value in options:
            if option in ('-r', '--remote-host'):
                if actions:
                    msg = "The %s option should be the first option given on the command line!"
                    raise Exception(msg % option)
                context = RemoteContext(value)
                updater = AptMirrorUpdater(context=context)
            elif option in ('-f', '--find-current-mirror'):
                actions.append(
                    functools.partial(report_current_mirror, updater))
            elif option in ('-F', '--file-to-read'):
                updater.custom_mirror_file_path = value
            elif option in ('-b', '--find-best-mirror'):
                actions.append(functools.partial(report_best_mirror, updater))
            elif option in ('-l', '--list-mirrors'):
                actions.append(
                    functools.partial(report_available_mirrors, updater))
            elif option in ('-L', '--url-char-len'):
                url_char_len = int(value)
            elif option in ('-c', '--change-mirror'):
                if value.strip().startswith(('http://', 'https://', 'ftp://')):
                    actions.append(
                        functools.partial(updater.change_mirror, value))
                else:
                    raise Exception("\'%s\' is not a valid mirror URL" % value)
            elif option in ('-a', '--auto-change-mirror'):
                actions.append(updater.change_mirror)
            elif option in ('-u', '--update', '--update-package-lists'):
                actions.append(updater.smart_update)
            elif option in ('-x', '--exclude'):
                actions.insert(0,
                               functools.partial(updater.ignore_mirror, value))
            elif option in ('-m', '--max'):
                limit = int(value)
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-V', '--version'):
                output("Version: %s on Python %i.%i", updater_version,
                       sys.version_info[0], sys.version_info[1])
                return
            elif option in ('-R', '--create-chroot'):
                actions.append(functools.partial(updater.create_chroot, value))
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
            else:
                assert False, "Unhandled option!"
        if not actions:
            usage(__doc__)
            return
        # Propagate options to the Python API.
        updater.max_mirrors = limit
        updater.url_char_len = url_char_len
    except Exception as e:
        warning("Error: Failed to parse command line arguments! (%s)" % e)
        sys.exit(1)
    # Perform the requested action(s).
    try:
        for callback in actions:
            callback()
    except Exception:
        logger.exception("Encountered unexpected exception! Aborting ..")
        sys.exit(1)
Example #32
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)
Example #33
0
def main():
    """The command line interface."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line options.
    try:
        options, arguments = getopt.gnu_getopt(
            sys.argv[1:],
            "b:m:Wc:B:l:nvqh",
            [
                "block-size=",
                "hash-method=",
                "whole-file",
                "concurrency=",
                "benchmark=",
                "listen=",
                "dry-run",
                "verbose",
                "quiet",
                "help",
            ],
        )
    except Exception as e:
        warning("Error: %s", e)
        sys.exit(1)
    # Command line option defaults.
    client_opts = {}
    server_opts = {}
    # Map parsed options to variables.
    for option, value in options:
        if option in ("-b", "--block-size"):
            client_opts["block_size"] = parse_size(value)
        elif option in ("-m", "--hash-method"):
            client_opts["hash_method"] = value
        elif option in ("-W", "--whole-file"):
            client_opts["delta_transfer"] = False
        elif option in ("-c", "--concurrency"):
            client_opts["concurrency"] = int(value)
            server_opts["concurrency"] = int(value)
        elif option in ("-B", "--benchmark"):
            client_opts["benchmark"] = int(value)
        elif option in ("-l", "--listen"):
            server_opts["address"] = value
        elif option in ("-n", "--dry-run"):
            client_opts["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__)
            sys.exit(0)
    # Execute the requested action.
    try:
        if arguments:
            if len(arguments) != 2:
                warning("Error: Two positional arguments expected!")
                sys.exit(1)
            client_opts['source'] = arguments[0]
            client_opts['target'] = arguments[1]
            run_client(**client_opts)
        else:
            run_server(**server_opts)
    except Exception:
        logger.exception("Program terminating due to exception!")
        sys.exit(1)
Example #34
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)
Example #35
0
def main():
    """Command line interface for the ``deb-pkg-tools`` program."""
    # Configure logging output.
    coloredlogs.install()
    # Command line option defaults.
    prompt = True
    actions = []
    control_file = None
    control_fields = {}
    directory = None
    # Initialize the package cache.
    cache = get_default_cache()
    # Parse the command line options.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'i:c:C:p:s:b:u:a:d:w:yvh', [
            'inspect=', 'collect=', 'check=', 'patch=', 'set=', 'build=',
            'update-repo=', 'activate-repo=', 'deactivate-repo=', 'with-repo=',
            'gc', 'garbage-collect', 'yes', 'verbose', 'help'
        ])
        for option, value in options:
            if option in ('-i', '--inspect'):
                actions.append(functools.partial(show_package_metadata, archive=value))
            elif option in ('-c', '--collect'):
                directory = check_directory(value)
            elif option in ('-C', '--check'):
                actions.append(functools.partial(check_package, archive=value, cache=cache))
            elif option in ('-p', '--patch'):
                control_file = os.path.abspath(value)
                assert os.path.isfile(control_file), "Control file does not exist!"
            elif option in ('-s', '--set'):
                name, _, value = value.partition(':')
                control_fields[name] = value.strip()
            elif option in ('-b', '--build'):
                actions.append(functools.partial(
                    build_package,
                    check_directory(value),
                    repository=tempfile.gettempdir(),
                ))
            elif option in ('-u', '--update-repo'):
                actions.append(functools.partial(update_repository,
                                                 directory=check_directory(value),
                                                 cache=cache))
            elif option in ('-a', '--activate-repo'):
                actions.append(functools.partial(activate_repository, check_directory(value)))
            elif option in ('-d', '--deactivate-repo'):
                actions.append(functools.partial(deactivate_repository, check_directory(value)))
            elif option in ('-w', '--with-repo'):
                actions.append(functools.partial(with_repository_wrapper,
                                                 directory=check_directory(value),
                                                 command=arguments,
                                                 cache=cache))
            elif option in ('--gc', '--garbage-collect'):
                actions.append(functools.partial(cache.collect_garbage, force=True))
            elif option in ('-y', '--yes'):
                prompt = False
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
        # We delay the patch_control_file() and collect_packages() partials
        # until all command line options have been parsed, to ensure that the
        # order of the command line options doesn't matter.
        if control_file:
            if not control_fields:
                raise Exception("Please specify one or more control file fields to patch!")
            actions.append(functools.partial(patch_control_file, control_file, control_fields))
        if directory:
            actions.append(functools.partial(collect_packages,
                                             archives=arguments,
                                             directory=directory,
                                             prompt=prompt,
                                             cache=cache))
    except Exception as e:
        warning("Error: %s", e)
        sys.exit(1)
    # Execute the selected action.
    try:
        if actions:
            for action in actions:
                action()
            cache.collect_garbage()
        else:
            usage(__doc__)
    except Exception as e:
        logger.exception("An error occurred!")
        sys.exit(1)
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)
Example #37
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)
Example #38
0
def main():
    """
    Command line interface for the ``deb-pkg-tools`` program.
    """
    # Configure logging output.
    coloredlogs.install()
    # Enable printing of Unicode strings even when our standard output and/or
    # standard error streams are not connected to a terminal. This is required
    # on Python 2.x but will break on Python 3.x which explains the ugly
    # version check. See also: http://stackoverflow.com/q/4374455/788200.
    if sys.version_info[0] == 2:
        sys.stdout = codecs.getwriter(OUTPUT_ENCODING)(sys.stdout)
        sys.stderr = codecs.getwriter(OUTPUT_ENCODING)(sys.stderr)
    # Command line option defaults.
    prompt = True
    actions = []
    control_file = None
    control_fields = {}
    # Initialize the package cache.
    cache = get_default_cache()
    # Parse the command line options.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'i:c:C:p:s:b:u:a:d:w:yvh', [
            'inspect=', 'collect=', 'check=', 'patch=', 'set=', 'build=',
            'update-repo=', 'activate-repo=', 'deactivate-repo=', 'with-repo=',
            'yes', 'verbose', 'help'
        ])
        for option, value in options:
            if option in ('-i', '--inspect'):
                actions.append(functools.partial(show_package_metadata, archive=value))
            elif option in ('-c', '--collect'):
                actions.append(functools.partial(collect_packages,
                                                 archives=arguments,
                                                 directory=check_directory(value),
                                                 prompt=prompt,
                                                 cache=cache))
                arguments = []
            elif option in ('-C', '--check'):
                actions.append(functools.partial(check_package, archive=value, cache=cache))
            elif option in ('-p', '--patch'):
                control_file = os.path.abspath(value)
                assert os.path.isfile(control_file), "Control file does not exist!"
            elif option in ('-s', '--set'):
                name, _, value = value.partition(':')
                control_fields[name] = value.strip()
            elif option in ('-b', '--build'):
                actions.append(functools.partial(build_package, check_directory(value)))
            elif option in ('-u', '--update-repo'):
                actions.append(functools.partial(update_repository,
                                                 directory=check_directory(value),
                                                 cache=cache))
            elif option in ('-a', '--activate-repo'):
                actions.append(functools.partial(activate_repository, check_directory(value)))
            elif option in ('-d', '--deactivate-repo'):
                actions.append(functools.partial(deactivate_repository, check_directory(value)))
            elif option in ('-w', '--with-repo'):
                actions.append(functools.partial(with_repository_wrapper,
                                                 directory=check_directory(value),
                                                 command=arguments,
                                                 cache=cache))
            elif option in ('-y', '--yes'):
                prompt = False
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-h', '--help'):
                usage()
                return
        if control_file:
            assert control_fields, "Please specify one or more control file fields to patch!"
            actions.append(functools.partial(patch_control_file, control_file, control_fields))
    except Exception as e:
        logger.error(e)
        print
        usage()
        sys.exit(1)
    # Execute the selected action.
    try:
        if actions:
            for action in actions:
                action()
            cache.collect_garbage()
        else:
            usage()
    except Exception as e:
        if isinstance(e, KeyboardInterrupt):
            logger.error("Interrupted by Control-C, aborting!")
        else:
            logger.exception("An error occurred!")
        sys.exit(1)
Example #39
0
def main():
    """Command line interface for the ``executor`` program."""
    # Enable logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    command_timeout = 0
    exclusive = False
    fudge_factor = 0
    lock_name = None
    lock_timeout = 0
    # Parse the command line options.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'eT:l:t:f:vqh', [
            'exclusive', 'lock-timeout=', 'lock-file=', 'timeout=',
            'fudge-factor=', 'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-e', '--exclusive'):
                exclusive = True
            elif option in ('-T', '--lock-timeout'):
                lock_timeout = parse_timespan(value)
            elif option in ('-l', '--lock-file'):
                lock_name = value
            elif option in ('-t', '--timeout'):
                command_timeout = parse_timespan(value)
            elif option in ('-f', '--fudge-factor'):
                fudge_factor = parse_timespan(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 program to execute.
        if not arguments:
            usage(__doc__)
            sys.exit(0)
        # Make sure the program actually exists.
        program_name = arguments[0]
        if not os.path.isfile(program_name):
            # Only search the $PATH if the given program name
            # doesn't already include one or more path segments.
            if program_name == os.path.basename(program_name):
                matching_programs = which(program_name)
                if matching_programs:
                    program_name = matching_programs[0]
        # The subprocess.Popen() call later on doesn't search the $PATH so we
        # make sure to give it the absolute pathname to the program.
        arguments[0] = program_name
    except Exception as e:
        warning("Failed to parse command line arguments: %s", e)
        sys.exit(1)
    # Apply the requested fudge factor.
    apply_fudge_factor(fudge_factor)
    # Run the requested command.
    try:
        if exclusive:
            # Select a default lock file name?
            if not lock_name:
                lock_name = os.path.basename(arguments[0])
                logger.debug("Using base name of command as lock file name (%s).", lock_name)
            lock_file = get_lock_path(lock_name)
            lock = InterProcessLock(path=lock_file, logger=logger)
            logger.debug("Trying to acquire exclusive lock: %s", lock_file)
            if lock.acquire(blocking=(lock_timeout > 0), max_delay=lock_timeout):
                logger.info("Successfully acquired exclusive lock: %s", lock_file)
                run_command(arguments, timeout=command_timeout)
            else:
                logger.error("Failed to acquire exclusive lock: %s", lock_file)
                sys.exit(1)
        else:
            run_command(arguments, timeout=command_timeout)
    except ExternalCommandFailed as e:
        logger.error("%s", e.error_message)
        sys.exit(e.command.returncode)
Example #40
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)
Example #41
0
def main():
    """Command line interface for the ``executor`` program."""
    # Enable logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    command_timeout = 0
    exclusive = False
    fudge_factor = 0
    lock_name = None
    lock_timeout = 0
    # Parse the command line options.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'eT:l:t:f:vqh', [
            'exclusive', 'lock-timeout=', 'lock-file=', 'timeout=',
            'fudge-factor=', 'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-e', '--exclusive'):
                exclusive = True
            elif option in ('-T', '--lock-timeout'):
                lock_timeout = parse_timespan(value)
            elif option in ('-l', '--lock-file'):
                lock_name = value
            elif option in ('-t', '--timeout'):
                command_timeout = parse_timespan(value)
            elif option in ('-f', '--fudge-factor'):
                fudge_factor = parse_timespan(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 program to execute.
        if not arguments:
            usage(__doc__)
            sys.exit(0)
        # Make sure the program actually exists.
        program_name = arguments[0]
        if not os.path.isfile(program_name):
            # Only search the $PATH if the given program name
            # doesn't already include one or more path segments.
            if program_name == os.path.basename(program_name):
                matching_programs = which(program_name)
                if matching_programs:
                    program_name = matching_programs[0]
        # The subprocess.Popen() call later on doesn't search the $PATH so we
        # make sure to give it the absolute pathname to the program.
        arguments[0] = program_name
    except Exception as e:
        warning("Failed to parse command line arguments: %s", e)
        sys.exit(1)
    # Apply the requested fudge factor.
    apply_fudge_factor(fudge_factor)
    # Run the requested command.
    try:
        if exclusive:
            # Select a default lock file name?
            if not lock_name:
                lock_name = os.path.basename(arguments[0])
                logger.debug("Using base name of command as lock file name (%s).", lock_name)
            lock_file = get_lock_path(lock_name)
            lock = InterProcessLock(path=lock_file, logger=logger)
            logger.debug("Trying to acquire exclusive lock: %s", lock_file)
            if lock.acquire(blocking=(lock_timeout > 0), max_delay=lock_timeout):
                logger.info("Successfully acquired exclusive lock: %s", lock_file)
                run_command(arguments, timeout=command_timeout)
            else:
                logger.error("Failed to acquire exclusive lock: %s", lock_file)
                sys.exit(1)
        else:
            run_command(arguments, timeout=command_timeout)
    except ExternalCommandFailed as e:
        logger.error("%s", e.error_message)
        sys.exit(e.command.returncode)
Example #42
0
def main():
    """Command line interface for the ``apache-manager`` program."""
    # Configure logging output.
    coloredlogs.install()
    # Command line option defaults.
    data_file = '/tmp/apache-manager.txt'
    dry_run = False
    max_memory_active = None
    max_memory_idle = None
    max_ss = None
    watch = False
    zabbix_discovery = False
    verbosity = 0
    # Parse the command line options.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'wa:i:t:f:znvqh', [
            'watch', 'max-memory-active=', 'max-memory-idle=', 'max-ss=',
            'max-time=', 'data-file=', 'zabbix-discovery', 'dry-run',
            'simulate', 'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-w', '--watch'):
                watch = True
            elif option in ('-a', '--max-memory-active'):
                max_memory_active = parse_size(value)
            elif option in ('-i', '--max-memory-idle'):
                max_memory_idle = parse_size(value)
            elif option in ('-t', '--max-ss', '--max-time'):
                max_ss = parse_timespan(value)
            elif option in ('-f', '--data-file'):
                data_file = value
            elif option in ('-z', '--zabbix-discovery'):
                zabbix_discovery = True
            elif option in ('-n', '--dry-run', '--simulate'):
                logger.info("Performing a dry run ..")
                dry_run = True
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
                verbosity += 1
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
                verbosity -= 1
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
    except Exception as e:
        sys.stderr.write("Error: %s!\n" % e)
        sys.exit(1)
    # Execute the requested action(s).
    manager = ApacheManager()
    try:
        if max_memory_active or max_memory_idle or max_ss:
            manager.kill_workers(
                max_memory_active=max_memory_active,
                max_memory_idle=max_memory_idle,
                timeout=max_ss,
                dry_run=dry_run,
            )
        if watch and connected_to_terminal(sys.stdout):
            watch_metrics(manager)
        elif zabbix_discovery:
            report_zabbix_discovery(manager)
        elif data_file != '-' and verbosity >= 0:
            for line in report_metrics(manager):
                if line_is_heading(line):
                    line = ansi_wrap(line, color=HIGHLIGHT_COLOR)
                print(line)
    finally:
        if (not watch) and (data_file == '-' or not dry_run):
            manager.save_metrics(data_file)
Example #43
0
def main():
    """
    Command line interface for the ``deb-pkg-tools`` program.
    """
    # Configure logging output.
    coloredlogs.install()
    # Enable printing of Unicode strings even when our standard output and/or
    # standard error streams are not connected to a terminal. This is required
    # on Python 2.x but will break on Python 3.x which explains the ugly
    # version check. See also: http://stackoverflow.com/q/4374455/788200.
    if sys.version_info[0] == 2:
        sys.stdout = codecs.getwriter(OUTPUT_ENCODING)(sys.stdout)
        sys.stderr = codecs.getwriter(OUTPUT_ENCODING)(sys.stderr)
    # Command line option defaults.
    prompt = True
    actions = []
    control_file = None
    control_fields = {}
    # Initialize the package cache.
    cache = get_default_cache()
    # Parse the command line options.
    try:
        options, arguments = getopt.getopt(
            sys.argv[1:], 'i:c:C:p:s:b:u:a:d:w:yvh', [
                'inspect=', 'collect=', 'check=', 'patch=', 'set=', 'build=',
                'update-repo=', 'activate-repo=', 'deactivate-repo=',
                'with-repo=', 'yes', 'verbose', 'help'
            ])
        for option, value in options:
            if option in ('-i', '--inspect'):
                actions.append(
                    functools.partial(show_package_metadata, archive=value))
            elif option in ('-c', '--collect'):
                actions.append(
                    functools.partial(collect_packages,
                                      archives=arguments,
                                      directory=check_directory(value),
                                      prompt=prompt,
                                      cache=cache))
                arguments = []
            elif option in ('-C', '--check'):
                actions.append(
                    functools.partial(check_package,
                                      archive=value,
                                      cache=cache))
            elif option in ('-p', '--patch'):
                control_file = os.path.abspath(value)
                assert os.path.isfile(
                    control_file), "Control file does not exist!"
            elif option in ('-s', '--set'):
                name, _, value = value.partition(':')
                control_fields[name] = value.strip()
            elif option in ('-b', '--build'):
                actions.append(
                    functools.partial(build_package, check_directory(value)))
            elif option in ('-u', '--update-repo'):
                actions.append(
                    functools.partial(update_repository,
                                      directory=check_directory(value),
                                      cache=cache))
            elif option in ('-a', '--activate-repo'):
                actions.append(
                    functools.partial(activate_repository,
                                      check_directory(value)))
            elif option in ('-d', '--deactivate-repo'):
                actions.append(
                    functools.partial(deactivate_repository,
                                      check_directory(value)))
            elif option in ('-w', '--with-repo'):
                actions.append(
                    functools.partial(with_repository_wrapper,
                                      directory=check_directory(value),
                                      command=arguments,
                                      cache=cache))
            elif option in ('-y', '--yes'):
                prompt = False
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-h', '--help'):
                usage()
                return
        if control_file:
            assert control_fields, "Please specify one or more control file fields to patch!"
            actions.append(
                functools.partial(patch_control_file, control_file,
                                  control_fields))
    except Exception as e:
        logger.error(e)
        print
        usage()
        sys.exit(1)
    # Execute the selected action.
    try:
        if actions:
            for action in actions:
                action()
            cache.collect_garbage()
        else:
            usage()
    except Exception as e:
        if isinstance(e, KeyboardInterrupt):
            logger.error("Interrupted by Control-C, aborting!")
        else:
            logger.exception("An error occurred!")
        sys.exit(1)
Example #44
0
def main():
    """Command line interface for the ``rsync-system-backup`` program."""
    # Initialize logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Parse the command line arguments.
    context_opts = dict()
    program_opts = dict()
    dest_opts = dict()
    try:
        options, arguments = getopt.gnu_getopt(sys.argv[1:], 'bsrm:c:t:i:unx:fvqh', [
            'backup', 'snapshot', 'rotate', 'mount=', 'crypto=', 'tunnel=',
            'ionice=', 'no-sudo', 'dry-run', 'multi-fs', 'exclude=', 'force',
            'disable-notifications', 'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-b', '--backup'):
                enable_explicit_action(program_opts, 'backup_enabled')
            elif option in ('-s', '--snapshot'):
                enable_explicit_action(program_opts, 'snapshot_enabled')
            elif option in ('-r', '--rotate'):
                enable_explicit_action(program_opts, 'rotate_enabled')
            elif option in ('-m', '--mount'):
                program_opts['mount_point'] = value
            elif option in ('-c', '--crypto'):
                program_opts['crypto_device'] = value
            elif option in ('-t', '--tunnel'):
                ssh_user, _, value = value.rpartition('@')
                ssh_alias, _, port_number = value.partition(':')
                tunnel_opts = dict(
                    ssh_alias=ssh_alias,
                    ssh_user=ssh_user,
                    # The port number of the rsync daemon.
                    remote_port=RSYNCD_PORT,
                )
                if port_number:
                    # The port number of the SSH server.
                    tunnel_opts['port'] = int(port_number)
                dest_opts['ssh_tunnel'] = SecureTunnel(**tunnel_opts)
            elif option in ('-i', '--ionice'):
                value = value.lower().strip()
                validate_ionice_class(value)
                program_opts['ionice'] = value
            elif option in ('-u', '--no-sudo'):
                program_opts['sudo_enabled'] = False
            elif option in ('-n', '--dry-run'):
                logger.info("Performing a dry run (because of %s option) ..", option)
                program_opts['dry_run'] = True
            elif option in ('-f', '--force'):
                program_opts['force'] = True
            elif option in ('-x', '--exclude'):
                program_opts.setdefault('exclude_list', [])
                program_opts['exclude_list'].append(value)
            elif option == '--multi-fs':
                program_opts['multi_fs'] = True
            elif option == '--disable-notifications':
                program_opts['notifications_enabled'] = False
            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:
                raise Exception("Unhandled option! (programming error)")
        if len(arguments) > 2:
            msg = "Expected one or two positional arguments! (got %i)"
            raise Exception(msg % len(arguments))
        if len(arguments) == 2:
            # Get the source from the first of two arguments.
            program_opts['source'] = arguments.pop(0)
        if arguments:
            # Get the destination from the second (or only) argument.
            dest_opts['expression'] = arguments[0]
            program_opts['destination'] = Destination(**dest_opts)
        elif not os.environ.get('RSYNC_MODULE_PATH'):
            # Show a usage message when no destination is given.
            usage(__doc__)
            return
    except Exception as e:
        warning("Error: %s", e)
        sys.exit(1)
    try:
        # Inject the source context into the program options.
        program_opts['source_context'] = create_context(**context_opts)
        # Initialize the program with the command line
        # options and execute the requested action(s).
        RsyncSystemBackup(**program_opts).execute()
    except Exception as e:
        if isinstance(e, RsyncSystemBackupError):
            # Special handling when the backup disk isn't available.
            if isinstance(e, MissingBackupDiskError):
                # Check if we're connected to a terminal to decide whether the
                # error should be propagated or silenced, the idea being that
                # rsync-system-backup should keep quiet when it's being run
                # from cron and the backup disk isn't available.
                if not connected_to_terminal():
                    logger.info("Skipping backup: %s", e)
                    sys.exit(0)
            # Known problems shouldn't produce
            # an intimidating traceback to users.
            logger.error("Aborting due to error: %s", e)
        else:
            # Unhandled exceptions do get a traceback,
            # because it may help fix programming errors.
            logger.exception("Aborting due to unhandled exception!")
        sys.exit(1)
Example #45
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)
Example #46
0
def main():
    """
    Main logic of the ``pip-accel`` command.
    """
    arguments = sys.argv[1:]
    # If no arguments are given, the help text of pip-accel is printed.
    if not arguments:
        print_usage()
        sys.exit(0)
    # If no install subcommand is given we pass the command line straight
    # to pip without any changes and exit immediately afterwards.
    elif 'install' not in arguments:
        sys.exit(os.spawnvp(os.P_WAIT, 'pip', ['pip'] + arguments))
    # Initialize logging output.
    coloredlogs.install()
    # Increase verbosity based on -v, --verbose options.
    for argument in arguments:
        if argument == '--verbose' or (len(argument) >= 2
                                       and argument[0] == '-'
                                       and argument[1] != '-'
                                       and 'v' in argument):
            coloredlogs.increase_verbosity()
    # Make sure the prefix is the same as the environment.
    if not os.path.samefile(sys.prefix, ENVIRONMENT):
        logger.error(
            "You are trying to install packages in environment #1 which is different from environment #2 where pip-accel is installed! Please install pip-accel under environment #1 to install packages there."
        )
        logger.info("Environment #1: %s ($VIRTUAL_ENV)", ENVIRONMENT)
        logger.info("Environment #2: %s (installation prefix)", sys.prefix)
        sys.exit(1)
    main_timer = Timer()
    initialize_directories()
    build_directory = tempfile.mkdtemp()
    # Execute "pip install" in a loop in order to retry after intermittent
    # error responses from servers (which can happen quite frequently).
    try:
        for i in xrange(1, MAX_RETRIES):
            try:
                requirements = unpack_source_dists(arguments, build_directory)
            except DistributionNotFound:
                logger.warn("We don't have all source distributions yet!")
                download_source_dists(arguments, build_directory)
            else:
                if not requirements:
                    logger.info(
                        "No unsatisfied requirements found, probably there's nothing to do."
                    )
                else:
                    install_requirements(requirements)
                    logger.info("Done! Took %s to install %i package%s.",
                                main_timer, len(requirements),
                                '' if len(requirements) == 1 else 's')
                return
            logger.warn("pip failed, retrying (%i/%i) ..", i + 1, MAX_RETRIES)
    except InstallationError:
        # Abort early when pip reports installation errors.
        logger.fatal(
            "pip reported unrecoverable installation errors. Please fix and rerun!"
        )
        sys.exit(1)
    finally:
        # Always cleanup temporary build directory.
        shutil.rmtree(build_directory)
    # Abort when after N retries we still failed to download source distributions.
    logger.fatal("External command failed %i times, aborting!" % MAX_RETRIES)
    sys.exit(1)
Example #47
0
def main():
    """
    Command line interface for the ``py2deb`` program.
    """
    # Configure terminal output.
    coloredlogs.install()
    try:
        # Initialize a package converter.
        converter = PackageConverter()
        # Parse and validate the command line options.
        options, arguments = getopt.getopt(sys.argv[1:], 'c:r:yvh', [
            'config=', 'repository=', 'name-prefix=', 'no-name-prefix=',
            'rename=', 'install-prefix=', 'install-alternative=',
            'python-callback=', 'report-dependencies=',
            'yes', 'verbose', 'help',
        ])
        control_file_to_update = None
        for option, value in options:
            if option in ('-c', '--config'):
                converter.load_configuration_file(value)
            elif option in ('-r', '--repository'):
                converter.set_repository(value)
            elif option == '--name-prefix':
                converter.set_name_prefix(value)
            elif option == '--no-name-prefix':
                converter.rename_package(value, value)
            elif option == '--rename':
                python_package_name, _, debian_package_name = value.partition(',')
                converter.rename_package(python_package_name, debian_package_name)
            elif option == '--install-prefix':
                converter.set_install_prefix(value)
            elif option == '--install-alternative':
                link, _, path = value.partition(',')
                converter.install_alternative(link, path)
            elif option == '--python-callback':
                converter.set_python_callback(value)
            elif option == '--report-dependencies':
                control_file_to_update = value
                if not os.path.isfile(control_file_to_update):
                    msg = "The given control file doesn't exist! (%s)"
                    raise Exception(msg % control_file_to_update)
            elif option in ('-y', '--yes'):
                converter.set_auto_install(True)
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
            else:
                assert False, "Unhandled option!"
    except Exception as e:
        warning("Failed to parse command line arguments: %s", e)
        sys.exit(1)
    # Convert the requested package(s).
    try:
        if arguments:
            archives, relationships = converter.convert(arguments)
            if relationships and control_file_to_update:
                patch_control_file(control_file_to_update, dict(depends=relationships))
        else:
            usage(__doc__)
    except Exception:
        logger.exception("Caught an unhandled exception!")
        sys.exit(1)
Example #48
0
def main():
    """The command line interface of the ``vcs-tool`` program."""
    # Initialize logging to the terminal.
    coloredlogs.install()
    # Command line option defaults.
    repository = None
    revision = None
    actions = []
    # Parse the command line arguments.
    try:
        options, arguments = getopt.gnu_getopt(sys.argv[1:], 'r:dnisume:vqh', [
            'repository=', 'rev=', 'revision=', 'release=', 'find-directory',
            'find-revision-number', 'find-revision-id', 'list-releases',
            'select-release=', 'sum-revisions', 'vcs-control-field', 'update',
            'merge-up', 'export=', 'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-r', '--repository'):
                value = value.strip()
                assert value, "Please specify the name of a repository! (using -r, --repository)"
                repository = coerce_repository(value)
            elif option in ('--rev', '--revision'):
                revision = value.strip()
                assert revision, "Please specify a nonempty revision string!"
            elif option == '--release':
                # TODO Right now --release and --merge-up cannot be combined
                #      because the following statements result in a global
                #      revision id which is immutable. If release objects had
                #      something like an optional `mutable_revision_id' it
                #      should be possible to support the combination of
                #      --release and --merge-up.
                assert repository, "Please specify a repository first!"
                release_id = value.strip()
                assert release_id in repository.releases, "The given release identifier is invalid!"
                revision = repository.releases[release_id].revision.revision_id
            elif option in ('-d', '--find-directory'):
                assert repository, "Please specify a repository first!"
                actions.append(functools.partial(print_directory, repository))
            elif option in ('-n', '--find-revision-number'):
                assert repository, "Please specify a repository first!"
                actions.append(functools.partial(print_revision_number, repository, revision))
            elif option in ('-i', '--find-revision-id'):
                assert repository, "Please specify a repository first!"
                actions.append(functools.partial(print_revision_id, repository, revision))
            elif option == '--list-releases':
                assert repository, "Please specify a repository first!"
                actions.append(functools.partial(print_releases, repository))
            elif option == '--select-release':
                assert repository, "Please specify a repository first!"
                release_id = value.strip()
                assert release_id, "Please specify a nonempty release identifier!"
                actions.append(functools.partial(print_selected_release, repository, release_id))
            elif option in ('-s', '--sum-revisions'):
                assert len(arguments) >= 2, "Please specify one or more repository/revision pairs!"
                actions.append(functools.partial(print_summed_revisions, arguments))
                arguments = []
            elif option == '--vcs-control-field':
                assert repository, "Please specify a repository first!"
                actions.append(functools.partial(print_vcs_control_field, repository, revision))
            elif option in ('-u', '--update'):
                assert repository, "Please specify a repository first!"
                actions.append(functools.partial(repository.update))
            elif option in ('-m', '--merge-up'):
                assert repository, "Please specify a repository first!"
                actions.append(functools.partial(
                    repository.merge_up,
                    target_branch=revision,
                    feature_branch=arguments[0] if arguments else None,
                ))
            elif option in ('-e', '--export'):
                directory = value.strip()
                assert repository, "Please specify a repository first!"
                assert directory, "Please specify the directory where the revision should be exported!"
                actions.append(functools.partial(repository.export, directory, revision))
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                return
        if not actions:
            usage(__doc__)
            return
    except Exception as e:
        warning("Error: %s", e)
        sys.exit(1)
    # Execute the requested action(s).
    try:
        for action in actions:
            action()
    except Exception:
        logger.exception("Failed to execute requested action(s)!")
        sys.exit(1)