diff options
Diffstat (limited to 'rtemstoolkit/execute.py')
-rwxr-xr-x | rtemstoolkit/execute.py | 129 |
1 files changed, 110 insertions, 19 deletions
diff --git a/rtemstoolkit/execute.py b/rtemstoolkit/execute.py index ed81589..c7d8134 100755 --- a/rtemstoolkit/execute.py +++ b/rtemstoolkit/execute.py @@ -37,9 +37,11 @@ from __future__ import print_function import functools +import codecs import io import os import re +import shlex import sys import subprocess import threading @@ -124,6 +126,14 @@ class execute(object): self.timing_out = False self.proc = None + @staticmethod + def _shlex_join(elements): + try: + return shlex.join(elements) + except AttributeError: + # Python older than 3.8 does not have shlex.join + return ' '.join(elements) + def capture(self, proc, command = 'pipe', timeout = None): """Create 3 threads to read stdout and stderr and send to the output handler and call an input handler is provided. Based on the 'communicate' code @@ -194,6 +204,10 @@ class execute(object): stacktraces.trace() if trace_threads: print('execute:_readthread: start') + if sys.stdout.encoding is not None: + decoder = codecs.getincrementaldecoder(sys.stdout.encoding)() + else: + decoder = None count = 0 line = '' try: @@ -213,8 +227,8 @@ class execute(object): _output_line(line + '\n', exe, prefix, out, count) break # str and bytes are the same type in Python2 - if type(data) is not str and type(data) is bytes: - data = data.decode(sys.stdout.encoding) + if decoder is not None and type(data) is not str and type(data) is bytes: + data = decoder.decode(data) last_ch = data[-1] sd = (line + data).split('\n') if last_ch != '\n': @@ -355,10 +369,17 @@ class execute(object): a string.""" if self.output is None: raise error.general('capture needs an output handler') - cs = command - if type(command) is list: - def add(x, y): return x + ' ' + str(y) - cs = functools.reduce(add, command, '')[1:] + # If a string split and not a shell command split + if not shell and isinstance(command, str): + command = shlex.split(command) + if shell and isinstance(command, list): + command = execute._shlex_join(command) + if self.shell_exe: + command = self.shell_exe + ' ' + command + if isinstance(command, list): + cs = execute._shlex_join(command) + else: + cs = command what = 'spawn' if shell: what = 'shell' @@ -389,11 +410,50 @@ class execute(object): r, e = os.path.splitext(command[0]) if e not in ['.exe', '.com', '.bat']: command[0] = command[0] + '.exe' - proc = subprocess.Popen(command, shell = shell, - cwd = cwd, env = env, - stdin = stdin, stdout = stdout, - stderr = stderr, - close_fds = False) + pipe_commands = [] + if shell: + pipe_commands.append(command) + else: + # See if there is a pipe operator in the command. If present + # split the commands by the pipe and run them with the pipe. + # if no pipe it is the normal stdin and stdout + current_command = [] + for cmd in command: + if cmd == '|': + pipe_commands.append(current_command) + current_command = [] + else: + current_command.append(cmd) + pipe_commands.append(current_command) + proc = None + if len(pipe_commands) == 1: + cmd = pipe_commands[0] + proc = subprocess.Popen( + cmd, shell = shell, + cwd = cwd, env = env, + stdin = stdin, stdout = stdout, + stderr = stderr, + close_fds = False) + else: + for i, cmd in enumerate(pipe_commands): + if i == 0: + proc = subprocess.Popen( + cmd, shell=shell, + cwd=cwd, env=env, + stdin=stdin, stdout=subprocess.PIPE) + elif i == len(pipe_commands) - 1: + proc = subprocess.Popen( + cmd, shell=shell, + cwd=cwd, env=env, + stdin=proc.stdout, + stdout=stdout, stderr=stderr, + close_fds=False) + else: + proc = subprocess.Popen( + cmd, shell=shell, + cwd=cwd, env=env, + stdin=proc.stdout, + stdout=subprocess.PIPE) if not capture: return (0, proc) if self.output is None: @@ -560,16 +620,28 @@ class capture_execution(execute): if __name__ == "__main__": def run_tests(e, commands, use_shell): for c in commands['shell']: - e.shell(c) + ec, out = e.shell(c) + if ec != 0: + raise RuntimeError('ec = {}'.format(ec)) + for c in commands['error']: + ec, out = e.shell(c) + if ec == 0: + raise RuntimeError('ec = {}'.format(ec)) for c in commands['spawn']: - e.spawn(c) + ec, out = e.spawn(c) + if ec != 0: + raise RuntimeError('ec = {}'.format(ec)) for c in commands['cmd']: if type(c) is str: - e.command(c, shell = use_shell) + ec, out = e.command(c, shell = use_shell) else: - e.command(c[0], c[1], shell = use_shell) + ec, out = e.command(c[0], c[1], shell = use_shell) + if ec != 0: + raise RuntimeError('ec = {}'.format(ec)) for c in commands['csubsts']: - e.command_subst(c[0], c[1], shell = use_shell) + ec, out = e.command_subst(c[0], c[1], shell = use_shell) + if ec != 0: + raise RuntimeError('ec = {}'.format(ec)) ec, proc = e.command(commands['pipe'][0], commands['pipe'][1], capture = False, stdin = subprocess.PIPE) if ec == 0: @@ -583,6 +655,15 @@ if __name__ == "__main__": proc.stdin.close() e.capture(proc) del proc + else: + raise RuntimeError('ec = {}'.format(ec)) + for c in commands['open']: + ec, proc = e.open(c) + if ec == 0: + e.capture(proc) + del proc + else: + raise RuntimeError('ec = {}'.format(ec)) def capture_output(text): print(text, end = '') @@ -595,19 +676,29 @@ if __name__ == "__main__": commands = {} commands['windows'] = {} commands['unix'] = {} - commands['windows']['shell'] = ['cd', 'dir /w', '.\\xyz', cmd_shell_test] + commands['windows']['shell'] = ['cd', 'dir /w', cmd_shell_test] + commands['windows']['error'] = ['.\\xyz'] commands['windows']['spawn'] = ['hostname', 'hostnameZZ', ['netstat', '/e']] commands['windows']['cmd'] = [('ipconfig'), ('nslookup', 'www.python.org')] commands['windows']['csubsts'] = [('netstat %0', ['-a']), ('netstat %0 %1', ['-a', '-n'])] commands['windows']['pipe'] = ('ftp', None, 'help\nquit') - commands['unix']['shell'] = ['pwd', 'ls -las', './xyz', sh_shell_test] - commands['unix']['spawn'] = ['ls', 'execute.pyc', ['ls', '-i']] + commands['windows']['open'] = [ + ["echo", "hello rtems", "|", "findstr", "rtems"], + " ".join(["echo", "hello rtems", "|", "findstr", "rtems"]) + ] + commands['unix']['shell'] = ['pwd', 'ls -las', sh_shell_test, 'ls -las'] + commands['unix']['error'] = ['./xyz'] + commands['unix']['spawn'] = ['ls', ['ls', '-i'], 'ls -l'] commands['unix']['cmd'] = [('date'), ('date', '-R'), ('date', ['-u', '+%d %D']), ('date', '-u "+%d %D %S"')] commands['unix']['csubsts'] = [('date %0 "+%d %D %S"', ['-u']), ('date %0 %1', ['-u', '+%d %D %S'])] commands['unix']['pipe'] = ('grep', 'hello', 'hello world') + commands['unix']['open'] = [ + ["echo", "hello world", "|", "cut", "-d ", "-f2"], + " ".join(["echo", "hello world", "|", "cut", "-d\" \"", "-f2"]) + ] print(arg_list('cmd a1 a2 "a3 is a string" a4')) print(arg_list('cmd b1 b2 "b3 is a string a4')) |