[ADD] run function

This commit is contained in:
Benedek Racz 2020-01-20 13:27:40 +01:00
parent c7a4e092c8
commit ba20b3f0d8
2 changed files with 119 additions and 7 deletions

View File

@ -11,6 +11,7 @@ from .console_reader import ConsoleReaderPipe
from .spawn import Spawn
from .spawn import Spawn as spawn
from .spawn import run
__all__ = ['split_command_line', 'join_args', 'ExceptionPexpect', 'EOF', 'TIMEOUT',
'ConsoleReaderSocket', 'ConsoleReaderPipe', 'spawn', 'Spawn']
'ConsoleReaderSocket', 'ConsoleReaderPipe', 'spawn', 'Spawn', 'run']

View File

@ -70,6 +70,7 @@ import os
import shutil
import re
import traceback
import types
import pywintypes
import win32process
@ -80,10 +81,117 @@ import winerror
import win32pipe
import socket
from wexpect_util import ExceptionPexpect
from wexpect_util import EOF
from wexpect_util import TIMEOUT
from wexpect_util import split_command_line
from .wexpect_util import ExceptionPexpect
from .wexpect_util import EOF
from .wexpect_util import TIMEOUT
from .wexpect_util import split_command_line
def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None, logfile=None, cwd=None, env=None):
"""
This function runs the given command; waits for it to finish; then
returns all output as a string. STDERR is included in output. If the full
path to the command is not given then the path is searched.
Note that lines are terminated by CR/LF (\\r\\n) combination even on
UNIX-like systems because this is the standard for pseudo ttys. If you set
'withexitstatus' to true, then run will return a tuple of (command_output,
exitstatus). If 'withexitstatus' is false then this returns just
command_output.
The run() function can often be used instead of creating a spawn instance.
For example, the following code uses spawn::
child = spawn('scp foo myname@host.example.com:.')
child.expect ('(?i)password')
child.sendline (mypassword)
The previous code can be replace with the following::
Examples
========
Start the apache daemon on the local machine::
run ("/usr/local/apache/bin/apachectl start")
Check in a file using SVN::
run ("svn ci -m 'automatic commit' my_file.py")
Run a command and capture exit status::
(command_output, exitstatus) = run ('ls -l /bin', withexitstatus=1)
Tricky Examples
===============
The following will run SSH and execute 'ls -l' on the remote machine. The
password 'secret' will be sent if the '(?i)password' pattern is ever seen::
run ("ssh username@machine.example.com 'ls -l'", events={'(?i)password':'secret\\n'})
This will start mencoder to rip a video from DVD. This will also display
progress ticks every 5 seconds as it runs. For example::
The 'events' argument should be a dictionary of patterns and responses.
Whenever one of the patterns is seen in the command out run() will send the
associated response string. Note that you should put newlines in your
string if Enter is necessary. The responses may also contain callback
functions. Any callback is function that takes a dictionary as an argument.
The dictionary contains all the locals from the run() function, so you can
access the child spawn object or any other variable defined in run()
(event_count, child, and extra_args are the most useful). A callback may
return True to stop the current run process otherwise run() continues until
the next event. A callback may also return a string which will be sent to
the child. 'extra_args' is not used by directly run(). It provides a way to
pass data to a callback function through run() through the locals
dictionary passed to a callback. """
if timeout == -1:
child = Spawn(command, maxread=2000, logfile=logfile, cwd=cwd, env=env)
else:
child = Spawn(command, timeout=timeout, maxread=2000, logfile=logfile, cwd=cwd, env=env)
if events is not None:
patterns = list(events.keys())
responses = list(events.values())
else:
patterns=None # We assume that EOF or TIMEOUT will save us.
responses=None
child_result_list = []
event_count = 0
while 1:
try:
index = child.expect (patterns)
if type(child.after) in (str,):
child_result_list.append(child.before + child.after)
else: # child.after may have been a TIMEOUT or EOF, so don't cat those.
child_result_list.append(child.before)
if type(responses[index]) in (str,):
child.send(responses[index])
elif type(responses[index]) is types.FunctionType:
callback_result = responses[index](locals())
sys.stdout.flush()
if type(callback_result) in (str,):
child.send(callback_result)
elif callback_result:
break
else:
raise TypeError ('The callback must be a string or function type.')
event_count = event_count + 1
except TIMEOUT:
child_result_list.append(child.before)
break
except EOF:
child_result_list.append(child.before)
break
child_result = ''.join(child_result_list)
if withexitstatus:
child.close()
return (child_result, child.exitstatus)
else:
return child_result
class Spawn:
@ -171,6 +279,7 @@ class Spawn:
try:
self.terminate()
self.disconnect_from_child()
except:
pass
@ -393,6 +502,10 @@ class Spawn:
def connect_to_child(self, host, port):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((host, port))
def disconnect_from_child(self):
if self.sock:
self.sock.close()
def startChild(self, args, env):
@ -433,8 +546,6 @@ class Spawn:
"import time;"
f"wexpect.ConsoleReaderSocket(wexpect.join_args({args}), {pid}, port=4321);"
)
print(commandLine)
self.conproc, _, conpid, __otid = win32process.CreateProcess(None, commandLine, None, None, False,
win32process.CREATE_NEW_CONSOLE, None, None, si)