Esempio n. 1
0
    def run(self, spec):
        """Execute the various tasks given in the spec list."""

        try:

            if output.debug:
                names = ", ".join(info[0] for info in spec)
                print("Tasks to run: %s" % names)

            call_hooks('commands.before', self.tasks, spec)

            # Initialise the default stage if none are given as the first task.
            if 'stages' in env:
                if spec[0][0] not in env.stages:
                    self.execute_task(env.stages[0], (), {}, None)
                else:
                    self.execute_task(*spec.pop(0))

            # Load the config YAML file if specified.
            if env.config_file:
                config_path = realpath(expanduser(env.config_file))
                config_path = join(self.directory, config_path)
                config_file = open(config_path, 'rb')
                config = load_yaml(config_file.read())
                if not config:
                    env.config = AttrDict()
                elif not isinstance(config, dict):
                    abort("Invalid config file found at %s" % config_path)
                else:
                    env.config = AttrDict(config)
                config_file.close()

            call_hooks('config.loaded')

            # Execute the tasks in order.
            for info in spec:
                self.execute_task(*info)

            if output.status:
                msg = "\nDone."
                if env.colors:
                    msg = env.color_settings['finish'](msg)
                print(msg)

        except SystemExit:
            raise
        except KeyboardInterrupt:
            if output.status:
                msg = "\nStopped."
                if env.colors:
                    msg = env.color_settings['finish'](msg)
                print >> sys.stderr, msg
            sys.exit(1)
        except:
            sys.excepthook(*sys.exc_info())
            sys.exit(1)
        finally:
            call_hooks('commands.after')
            disconnect_all()
Esempio n. 2
0
def handle_failure(cmd, warn_only):
    if hasattr(cmd, '__name__'):
        cmd = cmd.__name__ + '()'
    message = 'Error running `%s`\n\n%s' % (cmd, indent(format_exc()))
    if warn_only:
        warn(message)
    else:
        abort(message)
Esempio n. 3
0
def init_task_runner(filename, cwd):
    """Return a TaskRunner initialised from the located Boltfile."""

    cwd = abspath(cwd)
    if sep in filename:
        path = join(cwd, filename)
        if not exists(path):
            abort("Couldn't find Boltfile: %s" % filename)
    else:
        prev = None
        while cwd:
            if cwd == prev:
                abort("Couldn't find Boltfile: %s" % filename)
            path = join(cwd, filename)
            if exists(path):
                break
            elif filename == "Boltfile" and exists(join(cwd, "boltfile.py")):
                path = join(cwd, "boltfile.py")
                break
            prev = cwd
            cwd = dirname(cwd)

    directory = dirname(path)
    if directory not in sys.path:
        sys.path.insert(0, directory)

    chdir(directory)

    sys.dont_write_bytecode = 1
    boltfile = load_source('boltfile', path)
    sys.dont_write_bytecode = 0

    tasks = dict(
        (var.replace('_', '-'), obj) for var, obj in vars(boltfile).items()
        if hasattr(obj, '__task__')
        )

    stages = environ.get('BOLT_STAGES', env.get('stages'))
    if stages:
        if isinstance(stages, basestring):
            stages = [stage.strip() for stage in stages.split(',')]
        env.stages = stages
        for stage in stages:
            set_env_stage_command(tasks, stage)

    return TaskRunner(directory, path, boltfile.__doc__, tasks)
Esempio n. 4
0
def init_task_runner(filename, cwd):
    """Return a TaskRunner initialised from the located Boltfile."""

    cwd = abspath(cwd)
    if sep in filename:
        path = join(cwd, filename)
        if not exists(path):
            abort("Couldn't find Boltfile: %s" % filename)
    else:
        prev = None
        while cwd:
            if cwd == prev:
                abort("Couldn't find Boltfile: %s" % filename)
            path = join(cwd, filename)
            if exists(path):
                break
            prev = cwd
            cwd = dirname(cwd)

    directory = dirname(path)
    if directory not in sys.path:
        sys.path.insert(0, directory)

    chdir(directory)

    sys.dont_write_bytecode = 1
    boltfile = load_source('boltfile', path)
    sys.dont_write_bytecode = 0

    tasks = dict(
        (var.replace('_', '-'), obj) for var, obj in vars(boltfile).items()
        if hasattr(obj, '__task__')
        )

    stages = environ.get('BOLT_STAGES', env.get('stages'))
    if stages:
        if isinstance(stages, basestring):
            stages = [stage.strip() for stage in stages.split(',')]
        env.stages = stages
        for stage in stages:
            set_env_stage_command(tasks, stage)

    return TaskRunner(directory, path, boltfile.__doc__, tasks)
Esempio n. 5
0
 def multisudo(self, *args, **kwargs):
     abort("multisudo is not supported on this setup")
Esempio n. 6
0
 def multirun(self, *args, **kwargs):
     abort("multirun is not supported on this setup")
Esempio n. 7
0
 def multilocal(self, *args, **kwargs):
     abort("multilocal is not supported on this setup")
Esempio n. 8
0
def main(argv=None):
    """Handle the bolt command line call."""

    if argv is None:
        argv = sys.argv[1:]

    op = OptionParser(
        usage="bolt <command-1> <command-2> ... [options]",
        )

    op.add_option(
        '-v', '--version', action='store_true', default=False,
        help="show program's version number and exit"
        )

    op.add_option(
        '-f', dest='file', default="Boltfile",
        help="set the name or path of the bolt file [Boltfile]"
        )

    op.add_option(
        '-d', dest='defaults_file', default=_rc_path(),
        help="set the path of the defaults file [~/.bolt.yaml]"
        )

    op.add_option(
        '-i',  dest='identity', action='append', default=None,
        help="path to SSH private key file(s) -- may be repeated"
        )

    op.add_option(
        '--hide', metavar='LEVELS',
        help="comma-separated list of output levels to hide"
        )

    op.add_option(
        '--show', metavar='LEVELS',
        help="comma-separated list of output levels to show"
        )

    op.add_option(
        '--disable', metavar='HOOKS',
        help="comma-separated list of hooks to disable"
        )

    op.add_option(
        '--enable', metavar='HOOKS',
        help="comma-separated list of hooks to enable"
        )

    op.add_option(
        '--list', action='store_true', default=False,
        help="show the list of available tasks and exit"
        )

    op.add_option(
        '--no-pty', action='store_true', default=False,
        help="do not use pseudo-terminal in run/sudo"
        )

    options, args = op.parse_args(argv)
    setup_defaults(options.defaults_file)

    # Load the Boltfile.
    runner = init_task_runner(options.file, getcwd())

    # Autocompletion support.
    autocomplete_items = runner.tasks.keys()
    if 'autocomplete' in env:
        autocomplete_items += env.autocomplete

    autocomplete(op, ListCompleter(autocomplete_items))

    if options.version:
        print("bolt %s" % __version__)
        sys.exit()

    if options.no_pty:
        env.always_use_pty = False

    if options.identity:
        env.key_filename = options.identity

    split_string = lambda s: filter(None, map(str.strip, s.split(',')))

    # Handle output levels.
    if options.show:
        for level in split_string(options.show):
            output[level] = True

    if options.hide:
        for level in split_string(options.hide):
            output[level] = False

    if output.debug:
        print("Using Boltfile: %s" % runner.path)

    # Handle hooks related options.
    if options.disable:
        for hook in split_string(options.disable):
            DISABLED_HOOKS.append(hook)

    if options.enable:
        for hook in split_string(options.enable):
            ENABLED_HOOKS.append(hook)

    if options.list:
        print('\n'.join(sorted(runner.tasks)))
        sys.exit()

    tasks = []
    idx = 0

    # Parse command line arguments.
    for task in args:

        # Initialise variables.
        _args = []
        _kwargs = {}
        _ctx = None

        # Handle +env flags.
        if task.startswith('+'):
            if ':' in task:
                name, value = task[1:].split(':', 1)
                env[name] = value
            else:
                env[task[1:]] = True
            continue

        # Handle @context specifiers.
        if task.startswith('@'):
            if not idx:
                continue
            ctx = (task[1:],)
            existing = tasks[idx-1][3]
            if existing:
                new = list(existing)
                new.extend(ctx)
                ctx = tuple(new)
            tasks[idx-1][3] = ctx
            continue

        # Handle tasks with parameters.
        if ':' in task:
            task, argstr = task.split(':', 1)
            for pair in _escape_split(',', argstr):
                k, _, v = pair.partition('=')
                if _:
                    _kwargs[k] = v
                else:
                    _args.append(k)

        idx += 1
        task_name = task.replace('_', '-')

        if task_name not in runner.tasks:
            abort("Task not found:\n\n%s" % indent(task))

        tasks.append([task_name, _args, _kwargs, _ctx])

    if not tasks:
        runner.display_listing()
        sys.exit()

    runner.run(tasks)
Esempio n. 9
0
def setup_defaults(path=None):
    """Initialise ``env`` and ``output`` to default values."""

    env.update({
        'again_prompt': 'Sorry, try again.',
        'always_use_pty': True,
        'colors': False,
        'color_settings': {
            'abort': yellow,
            'error': yellow,
            'finish': cyan,
            'host_prefix': green,
            'prefix': red,
            'prompt': blue,
            'task': red,
            'warn': yellow
            },
        'combine_stderr': True,
        'command': None,
        'command_prefixes': [],
        'config_file': None,
        'ctx': (),
        'cwd': '',
        'disable_known_hosts': False,
        'echo_stdin': True,
        'hook': None,
        'host': None,
        'host_string': None,
        'key_filename': None,
        'lcwd': '',
        'multirun_child_timeout': 10,
        'multirun_pool_size': 10,
        'no_agent': False,
        'no_keys': False,
        'output_prefix': True,
        'password': None,
        'passwords': {},
        'port': None,
        'reject_unknown_hosts': False,
        'shell': '/bin/bash -l -c',
        'shell_history_file': '~/.bolt-shell-history',
        'sudo_prefix': "sudo -S -p '%s' ",
        'sudo_prompt': 'sudo password:'******'use_shell': True,
        'user': _get_system_username(),
        'warn_only': False
        })

    output.update({
        'aborts': True,
        'debug': False,
        'running': True,
        'status': True,
        'stderr': True,
        'stdout': True,
        'user': True,
        'warnings': True,
        }, {
        'everything': ['output', 'running', 'user', 'warnings'],
        'output': [ 'stderr', 'stdout']
        })

    # Load defaults from a YAML file.
    if path and exists(path):
        fileobj = open(path, 'rb')
        mapping = load_yaml(fileobj.read())
        if not isinstance(mapping, dict):
            abort(
                "Got a %r value when loading %r. Mapping expected." %
                (type(mapping), path)
                )
        env.update(mapping)