sirosen/SALVE

View on GitHub
salve/cli/parser.py

Summary

Maintainability
A
25 mins
Test Coverage
from __future__ import unicode_literals
import argparse
import textwrap

import salve
from salve.config import SALVEConfig
from salve.context import ExecutionContext
from salve.cli.default_subparser import set_default_subparser
import salve.cli.deploy
import salve.cli.backup


def add_backup_args(parser):  # pragma: no cover
    """
    Takes in an argparse parser and adds the options for the backup subcommand.
    This is necessary because of the way that argparse handles subparsers --
    namely, that they are created automatically at the time of addition.
    """
    parser.add_argument(
        '-r', '--recover', dest='recover', action='store_true',
        default=False,
        help='Boolean flag, indicates that recovery should be performed.')
    parser.add_argument(
        '-s', '--show-versions', dest='show_versions',
        action='store_true', default=False,
        help='Boolean flag, indicates that the file\'s versions should be ' +
        'displayed with varying generation numbers and dates.')
    parser.add_argument(
        '-f', '--filename', dest='filename', default=None,
        required=True, help='The absolute path to the file to act upon.')

    parser.set_defaults(func=salve.cli.backup.main)


def add_deploy_args(parser):
    """
    Takes in an argparse parser and adds the options for the deploy subcommand.
    This is necessary because of the way that argparse handles subparsers --
    namely, that they are created automatically at the time of addition.
    """
    parser.add_argument(
        '-m', '--manifest', dest='manifest', default=None,
        required=True, help='The root manifest file for execution.')
    parser.add_argument(
        '-d', '--directory', dest='directory', default=None,
        help='The directory to which relative paths in manifests refer. ' +
        'Will be removed in version 3.')
    parser.add_argument(
        '--ver3', '--version3', dest='version3',
        default=False, action='store_true', help='Enable version 3 mode ' +
        '(turn on all options which will become defaults in version 3).')
    parser.add_argument(
        '--version3-relative-paths', dest='v3_relpath',
        default=False, action='store_true', help='Expand relative paths ' +
        'in manifests relative to the current manifest, rather than ' +
        'the root manifest.')

    parser.set_defaults(func=salve.cli.deploy.main)


def get_parser():
    """
    Produces a command line option parser for SALVE using argparse.

    We only support Python 2.6 when argparse is installed.
    """
    class SALVESharedParser(argparse.ArgumentParser):
        def __init__(self, *args, **kwargs):
            argparse.ArgumentParser.__init__(self, *args, **kwargs)
            self.add_argument(
                '-c', '--config-file', dest='configfile',
                default=None, help='A SALVE config file (INI format).')
            self.add_argument(
                '-l', '--log-level', dest='log_level',
                default='INFO', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
                help='Log level to display.')
            self.add_argument(
                '--version', action='version',
                version="%(prog)s " + salve.__version__)

    description = textwrap.dedent("""Run a SALVE command.
        SALVE is a configuration deployment language that guarantees the
        properties of idempotence, safety, and recoverability that are
        necessary in order to manage personal configuration files in a
        straightforward way.
        For a full description of SALVE and its capabilities, visit
        http://salve.sirosen.net/""")

    parser = SALVESharedParser(prog='SALVE', description=description)

    subparsers = parser.add_subparsers(
        title='Subcommands',
        parser_class=SALVESharedParser, metavar='')

    # don't yet add the backup parser -- it isn't supported yet
    # backup_parser = subparsers.add_parser('backup',
    #         help='Directly manipulate, inspect, and restore from backups.')
    # add_backup_args(backup_parser)

    deploy_parser = subparsers.add_parser(
        'deploy', help='Run on a manifest' +
        ' tree and deploy the described configuration.')
    add_deploy_args(deploy_parser)

    # make the deploy subcommand the default
    set_default_subparser(parser, 'deploy')

    return parser


def load_args():
    """
    Generates a parser, reads commandline arguments, and then does basic
    post-processing of arguments whose meanings and effects are either general
    across subcommands or which have effects related to argument parsing (like
    deprecation warnings).
    """
    parser = get_parser()
    args = parser.parse_args()

    # load and store config data from config file (if present)
    conf = SALVEConfig(filename=args.configfile)
    ExecutionContext()['config'] = conf

    if args.log_level:
        salve.logger.setLevel(salve.log.str_to_level(args.log_level))

    # do 'deploy' specific actions to clean/validate args
    if args.func is salve.cli.deploy.main:
        # set all v3 options if version3 is set
        if args.version3:
            args.v3_relpath = True

        # warn about deprecations coming in v3
        if args.directory:
            salve.logger.warn(
                'Deprecation Warning: --directory will be ' +
                'removed in version 3 as --version3-relative-paths becomes ' +
                'the default.')

    return args