Пример #1
0
def run_command(cmd,
                shell=None,
                aliases=None,
                envvars=None,
                extra_commands=None,
                test_mode=False):
    shell = shell or get_default_shell()
    command_as_list = shlex.split(ensure_utf8(cmd))
    if len(command_as_list) and command_as_list[0] == "cd":
        cwd = os.getcwd()  # Save cwd
        directory = cmd.split()[1].strip()
        if directory == "-":  # Go back to $OLDPWD
            directory = os.environ.get("OLDPWD", directory)
        try:
            os.chdir(os.path.expandvars(os.path.expanduser(directory)))
        except OSError:
            echo("No such file or directory: {}".format(directory))
        else:
            os.environ["OLDPWD"] = cwd

    else:
        # Need to make a temporary command file so that $ENV are used correctly
        # and that shell built-ins, e.g. "source" work
        with NamedTemporaryFile("w") as fp:
            fp.write("#!{0}\n".format(shell))
            fp.write("# -*- coding: utf-8 -*-\n")
            # Make aliases work in bash:
            if "bash" in shell:
                fp.write("shopt -s expand_aliases\n")

            # Write envvars and aliases
            write_commands(fp, "export", envvars)
            write_commands(fp, "alias", aliases)
            if extra_commands:
                for command in extra_commands:
                    line = "{}\n".format(command)
                    fp.write(ensure_utf8(line))

            cmd_line = cmd + "\n"
            fp.write(ensure_utf8(cmd_line))
            fp.flush()
            try:
                if test_mode:
                    output = subprocess.check_output([shell, fp.name])
                    echo(output)
                else:
                    return subprocess.call([shell, fp.name])
            except KeyboardInterrupt:
                pass
Пример #2
0
def write_directives(fp, directive, args):
    if args:
        for arg in args:
            line = "#doitlive {directive}: {arg}\n".format(directive=directive,
                                                           arg=arg)
            fp.write(ensure_utf8(line))
    return None
Пример #3
0
def write_commands(fp, command, args):
    if args:
        for arg in args:
            line = "{command} {arg}\n".format(**locals())
            fp.write(ensure_utf8(line))
    return None
Пример #4
0
def run(
    commands,
    shell=None,
    prompt_template="default",
    speed=1,
    quiet=False,
    test_mode=False,
    commentecho=False,
):
    """Main function for "magic-running" a list of commands."""
    if not quiet:
        secho("We'll do it live!", fg="red", bold=True)
        secho(
            "STARTING SESSION: Press Ctrl-C at any time to exit.",
            fg="yellow",
            bold=True,
        )
        click.pause()

    click.clear()
    state = SessionState(
        shell=shell,
        prompt_template=prompt_template,
        speed=speed,
        test_mode=test_mode,
        commentecho=commentecho,
    )

    i = 0
    while i < len(commands):
        command = commands[i].strip()
        i += 1
        if not command:
            continue
        is_comment = command.startswith("#")
        if not is_comment:
            command_as_list = shlex.split(ensure_utf8(command))
        else:
            command_as_list = None
        shell_match = SHELL_RE.match(command)
        if is_comment:
            # Parse comment magic
            match = OPTION_RE.match(command)
            if match:
                option, arg = match.group("option"), match.group("arg")
                func = OPTION_MAP[option]
                func(state, arg)
            elif state.commentecho():
                comment = command.lstrip("#")
                secho(comment, fg="yellow", bold=True)
            continue
        # Handle 'export' and 'alias' commands by storing them in SessionState
        elif command_as_list and command_as_list[0] in ["alias", "export"]:
            magictype(command,
                      prompt_template=state["prompt_template"],
                      speed=state["speed"])
            # Store the raw commands instead of using add_envvar and add_alias
            # to avoid having to parse the command ourselves
            state.add_command(command)
        # Handle ```python and ```ipython by running "player" consoles
        elif shell_match:
            shell_name = shell_match.groups()[0].strip()
            py_commands = []
            more = True
            while more:  # slurp up all the python code
                try:
                    py_command = commands[i].rstrip()
                except IndexError:
                    raise SessionError("Unmatched {0} code block in "
                                       "session file.".format(shell_name))
                i += 1
                if py_command.startswith("```"):
                    i += 1
                    more = False
                else:
                    py_commands.append(py_command)
            # Run the player console
            magictype(
                shell_name,
                prompt_template=state["prompt_template"],
                speed=state["speed"],
            )

            if shell_name == "ipython":
                try:
                    from doitlive.ipython_consoles import start_ipython_player
                except ImportError:
                    raise RuntimeError(
                        "```ipython blocks require IPython to be installed")
                # dedent all the commands to account for IPython's autoindentation
                ipy_commands = [textwrap.dedent(cmd) for cmd in py_commands]
                start_ipython_player(ipy_commands, speed=state["speed"])
            else:
                start_python_player(py_commands, speed=state["speed"])
        else:
            # goto_stealthmode determines when to switch to stealthmode
            goto_stealthmode = magicrun(command, **state)
            # stealthmode allows user to type live commands outside of automated script
            i -= stealthmode(state, goto_stealthmode)
    echo_prompt(state["prompt_template"])
    wait_for(RETURNS)
    if not quiet:
        secho("FINISHED SESSION", fg="yellow", bold=True)
Пример #5
0
def write_directives(fp, directive, args):
    if args:
        for arg in args:
            line = '#doitlive {directive}: {arg}\n'.format(**locals())
            fp.write(ensure_utf8(line))
    return None
Пример #6
0
def run(commands, shell=None, prompt_template='default', speed=1,
        quiet=False, test_mode=False, commentecho=False):
    """Main function for "magic-running" a list of commands."""
    if not quiet:
        secho("We'll do it live!", fg='red', bold=True)
        secho('STARTING SESSION: Press Ctrl-C at any time to exit.',
              fg='yellow', bold=True)
        click.pause()

    click.clear()
    state = SessionState(shell=shell, prompt_template=prompt_template,
                         speed=speed, test_mode=test_mode,
                         commentecho=commentecho)

    i = 0
    while i < len(commands):
        command = commands[i].strip()
        command_as_list = shlex.split(ensure_utf8(command))
        i += 1
        if not command:
            continue
        shell_match = SHELL_RE.match(command)
        if command.startswith('#'):
            # Parse comment magic
            match = OPTION_RE.match(command)
            if match:
                option, arg = match.group('option'), match.group('arg')
                func = OPTION_MAP[option]
                func(state, arg)
            elif state.commentecho():
                comment = command.lstrip("#")
                secho(comment, fg='yellow', bold=True)
            continue
        # Handle 'export' and 'alias' commands by storing them in SessionState
        elif command_as_list and command_as_list[0] in ['alias', 'export']:
            magictype(command,
                      prompt_template=state['prompt_template'],
                      speed=state['speed'])
            # Store the raw commands instead of using add_envvar and add_alias
            # to avoid having to parse the command ourselves
            state.add_command(command)
        # Handle ```python and ```ipython by running "player" consoles
        elif shell_match:
            shell_name = shell_match.groups()[0].strip()
            py_commands = []
            more = True
            while more:  # slurp up all the python code
                try:
                    py_command = commands[i].rstrip()
                except IndexError:
                    raise SessionError('Unmatched {0} code block in '
                                       'session file.'.format(shell_name))
                i += 1
                if py_command.startswith('```'):
                    i += 1
                    more = False
                else:
                    py_commands.append(py_command)
            # Run the player console
            magictype(shell_name,
                      prompt_template=state['prompt_template'],
                      speed=state['speed'])
            if shell_name == 'ipython':
                try:
                    from doitlive.ipython_consoles import start_ipython_player
                except ImportError:
                    raise RuntimeError('```ipython blocks require IPython to be installed')
                # dedent all the commands to account for IPython's autoindentation
                ipy_commands = [textwrap.dedent(cmd) for cmd in py_commands]
                start_ipython_player(ipy_commands, speed=state['speed'])
            else:
                start_python_player(py_commands, speed=state['speed'])
        else:
            magicrun(command, **state)
    echo_prompt(state['prompt_template'])
    wait_for(RETURNS)
    if not quiet:
        secho("FINISHED SESSION", fg='yellow', bold=True)