зеркало из https://github.com/mozilla/gecko-dev.git
325 строки
8.9 KiB
ReStructuredText
325 строки
8.9 KiB
ReStructuredText
:mod:`mozprocess` --- Launch and manage processes
|
|
=================================================
|
|
|
|
Mozprocess is a process-handling module that provides some additional
|
|
features beyond those available with python's subprocess:
|
|
|
|
* better handling of child processes, especially on Windows
|
|
* the ability to timeout the process after some absolute period, or some
|
|
period without any data written to stdout/stderr
|
|
* the ability to specify output handlers that will be called
|
|
for each line of output produced by the process
|
|
* the ability to specify handlers that will be called on process timeout
|
|
and normal process termination
|
|
|
|
Running a process
|
|
-----------------
|
|
|
|
mozprocess consists of two classes: ProcessHandler inherits from ProcessHandlerMixin.
|
|
|
|
Let's see how to run a process.
|
|
First, the class should be instanciated with at least one argument which is a command (or a list formed by the command followed by its arguments).
|
|
Then the process can be launched using the *run()* method.
|
|
Finally the *wait()* method will wait until end of execution.
|
|
|
|
.. code-block:: python
|
|
|
|
from mozprocess import processhandler
|
|
|
|
# under Windows replace by command = ['dir', '/a']
|
|
command = ['ls', '-l']
|
|
p = processhandler.ProcessHandler(command)
|
|
print("execute command: %s" % p.commandline)
|
|
p.run()
|
|
p.wait()
|
|
|
|
Note that using *ProcessHandler* instead of *ProcessHandlerMixin* will print the output of executed command. The attribute *commandline* provides the launched command.
|
|
|
|
Collecting process output
|
|
-------------------------
|
|
|
|
Let's now consider a basic shell script that will print numbers from 1 to 5 waiting 1 second between each.
|
|
This script will be used as a command to launch in further examples.
|
|
|
|
**proc_sleep_echo.sh**:
|
|
|
|
.. code-block:: sh
|
|
|
|
#!/bin/sh
|
|
|
|
for i in 1 2 3 4 5
|
|
do
|
|
echo $i
|
|
sleep 1
|
|
done
|
|
|
|
If you are running under Windows, you won't be able to use the previous script (unless using Cygwin).
|
|
So you'll use the following script:
|
|
|
|
**proc_sleep_echo.bat**:
|
|
|
|
.. code-block:: bat
|
|
|
|
@echo off
|
|
FOR %%A IN (1 2 3 4 5) DO (
|
|
ECHO %%A
|
|
REM if you have TIMEOUT then use it instead of PING
|
|
REM TIMEOUT /T 1 /NOBREAK
|
|
PING -n 2 127.0.0.1 > NUL
|
|
)
|
|
|
|
Mozprocess allows the specification of custom output handlers to gather process output while running.
|
|
ProcessHandler will by default write all outputs on stdout. You can also provide (to ProcessHandler or ProcessHandlerMixin) a function or a list of functions that will be used as callbacks on each output line generated by the process.
|
|
|
|
In the following example the command's output will be stored in a file *output.log* and printed in stdout:
|
|
|
|
.. code-block:: python
|
|
|
|
import sys
|
|
from mozprocess import processhandler
|
|
|
|
fd = open('output.log', 'w')
|
|
|
|
def tostdout(line):
|
|
sys.stdout.write("<%s>\n" % line)
|
|
|
|
def tofile(line):
|
|
fd.write("<%s>\n" % line)
|
|
|
|
# under Windows you'll replace by 'proc_sleep_echo.bat'
|
|
command = './proc_sleep_echo.sh'
|
|
outputs = [tostdout, tofile]
|
|
|
|
p = processhandler.ProcessHandlerMixin(command, processOutputLine=outputs)
|
|
p.run()
|
|
p.wait()
|
|
|
|
fd.close()
|
|
|
|
The process output can be saved (*obj = ProcessHandler(..., storeOutput=True)*) so as it is possible to request it (*obj.output*) at any time. Note that the default value for *stroreOutput* is *True*, so it is not necessary to provide it in the parameters.
|
|
|
|
.. code-block:: python
|
|
|
|
import time
|
|
import sys
|
|
from mozprocess import processhandler
|
|
|
|
command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat'
|
|
|
|
p = processhandler.ProcessHandler(command, storeOutput=True)
|
|
p.run()
|
|
for i in xrange(10):
|
|
print(p.output)
|
|
time.sleep(0.5)
|
|
p.wait()
|
|
|
|
In previous example, you will see the *p.output* list growing.
|
|
|
|
Execution
|
|
---------
|
|
|
|
Status
|
|
``````
|
|
|
|
It is possible to query the status of the process via *poll()* that will return None if the process is still running, 0 if it ended without failures and a negative value if it was killed by a signal (Unix-only).
|
|
|
|
.. code-block:: python
|
|
|
|
import time
|
|
import signal
|
|
from mozprocess import processhandler
|
|
|
|
command = './proc_sleep_echo.sh'
|
|
p = processhandler.ProcessHandler(command)
|
|
p.run()
|
|
time.sleep(2)
|
|
print("poll status: %s" % p.poll())
|
|
time.sleep(1)
|
|
p.kill(signal.SIGKILL)
|
|
print("poll status: %s" % p.poll())
|
|
|
|
Timeout
|
|
```````
|
|
|
|
A timeout can be provided to the *run()* method. If the process last more than timeout seconds, it will be stopped.
|
|
|
|
After execution, the property *timedOut* will be set to True if a timeout was reached.
|
|
|
|
It is also possible to provide functions (*obj = ProcessHandler[Mixin](..., onTimeout=functions)*) that will be called if the timeout was reached.
|
|
|
|
.. code-block:: python
|
|
|
|
from mozprocess import processhandler
|
|
|
|
def ontimeout():
|
|
print("REACHED TIMEOUT")
|
|
|
|
command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat'
|
|
functions = [ontimeout]
|
|
p = processhandler.ProcessHandler(command, onTimeout=functions)
|
|
p.run(timeout=2)
|
|
p.wait()
|
|
print("timedOut = %s" % p.timedOut)
|
|
|
|
By default the process will be killed on timeout but it is possible to prevent this by setting *kill_on_timeout* to *False*.
|
|
|
|
.. code-block:: python
|
|
|
|
p = processhandler.ProcessHandler(command, onTimeout=functions, kill_on_timeout=False)
|
|
p.run(timeout=2)
|
|
p.wait()
|
|
print("timedOut = %s" % p.timedOut)
|
|
|
|
In this case, no output will be available after the timeout, but the process will still be running.
|
|
|
|
Waiting
|
|
```````
|
|
|
|
It is possible to wait until the process exits as already seen with the method *wait()*, or until the end of a timeout if given. Note that in last case the process is still alive after the timeout.
|
|
|
|
.. code-block:: python
|
|
|
|
command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat'
|
|
p = processhandler.ProcessHandler(command)
|
|
p.run()
|
|
p.wait(timeout=2)
|
|
print("timedOut = %s" % p.timedOut)
|
|
p.wait()
|
|
|
|
Killing
|
|
```````
|
|
|
|
You can request to kill the process with the method *kill*. f the parameter "ignore_children" is set to False when the process handler class is initialized, all the process's children will be killed as well.
|
|
|
|
Except on Windows, you can specify the signal with which to kill method the process (e.g.: *kill(signal.SIGKILL)*).
|
|
|
|
.. code-block:: python
|
|
|
|
import time
|
|
from mozprocess import processhandler
|
|
|
|
command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat'
|
|
p = processhandler.ProcessHandler(command)
|
|
p.run()
|
|
time.sleep(2)
|
|
p.kill()
|
|
|
|
End of execution
|
|
````````````````
|
|
|
|
You can provide a function or a list of functions to call at the end of the process using the initilization parameter *onFinish*.
|
|
|
|
.. code-block:: python
|
|
|
|
from mozprocess import processhandler
|
|
|
|
def finish():
|
|
print("Finished!!")
|
|
|
|
command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat'
|
|
|
|
p = processhandler.ProcessHandler(command, onFinish=finish)
|
|
p.run()
|
|
p.wait()
|
|
|
|
Child management
|
|
----------------
|
|
|
|
Consider the following scripts:
|
|
|
|
**proc_child.sh**:
|
|
|
|
.. code-block:: sh
|
|
|
|
#!/bin/sh
|
|
for i in a b c d e
|
|
do
|
|
echo $i
|
|
sleep 1
|
|
done
|
|
|
|
**proc_parent.sh**:
|
|
|
|
.. code-block:: sh
|
|
|
|
#!/bin/sh
|
|
./proc_child.sh
|
|
for i in 1 2 3 4 5
|
|
do
|
|
echo $i
|
|
sleep 1
|
|
done
|
|
|
|
For windows users consider:
|
|
|
|
**proc_child.bat**:
|
|
|
|
.. code-block:: bat
|
|
|
|
@echo off
|
|
FOR %%A IN (a b c d e) DO (
|
|
ECHO %%A
|
|
REM TIMEOUT /T 1 /NOBREAK
|
|
PING -n 2 127.0.0.1 > NUL
|
|
)
|
|
|
|
**proc_parent.bat**:
|
|
|
|
.. code-block:: bat
|
|
|
|
@echo off
|
|
call proc_child.bat
|
|
FOR %%A IN (1 2 3 4 5) DO (
|
|
ECHO %%A
|
|
REM TIMEOUT /T 1 /NOBREAK
|
|
PING -n 2 127.0.0.1 > NUL
|
|
)
|
|
|
|
For processes that launch other processes, mozprocess allows you to get child running status, wait for child termination, and kill children.
|
|
|
|
Ignoring children
|
|
`````````````````
|
|
|
|
By default the *ignore_children* option is False. In that case, killing the main process will kill all its children at the same time.
|
|
|
|
.. code-block:: python
|
|
|
|
import time
|
|
from mozprocess import processhandler
|
|
|
|
def finish():
|
|
print("Finished")
|
|
|
|
command = './proc_parent.sh'
|
|
p = processhandler.ProcessHandler(command, ignore_children=False, onFinish=finish)
|
|
p.run()
|
|
time.sleep(2)
|
|
print("kill")
|
|
p.kill()
|
|
|
|
If *ignore_children* is set to *True*, killing will apply only to the main process that will wait children end of execution before stoping (join).
|
|
|
|
.. code-block:: python
|
|
|
|
import time
|
|
from mozprocess import processhandler
|
|
|
|
def finish():
|
|
print("Finished")
|
|
|
|
command = './proc_parent.sh'
|
|
p = processhandler.ProcessHandler(command, ignore_children=True, onFinish=finish)
|
|
p.run()
|
|
time.sleep(2)
|
|
print("kill")
|
|
p.kill()
|
|
|
|
API Documentation
|
|
-----------------
|
|
|
|
.. module:: mozprocess
|
|
.. autoclass:: ProcessHandlerMixin
|
|
:members: __init__, timedOut, commandline, run, kill, processOutputLine, onTimeout, onFinish, wait
|
|
.. autoclass:: ProcessHandler
|
|
:members:
|