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
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
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
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)
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
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)