envoy 是对 Python 标准库中 subprocess 模块的封装, 虽然功能对比原生 subprocess 来说少了很多,但是更易于使用,Github 项目地址
代码解析
envoy 只有一个文件,两百多行代码,非常的简单
tree envoy |
envoy 可以非常轻松通过管道传递数据
from envoy.core import run |
我们先看看 run 函数
run 函数接接收 命令,管道数据,超时时间,kill 超时时间,扩展环境变量,执行目录 作为参数
run 函数是对 Command.run 的封装,首先通过 expand_args 函数解析命令,通过 Command.run 执行多个命令,如果有多个命令的话,将上个命令的输出传递给下一个命令,实现管道间的数据传递,并返回一个 Response 对象
def run(command, data=None, timeout=None, kill_timeout=None, env=None, cwd=None): |
我们再看看 envoy 是如何解析我们传入的命令的
如果传入的类型的是 str 或者 unicode, 则通过 shelx 模块对其进行解析成 subprocess 需要的格式
def expand_args(command): |
我们手动传入一条命令,看一下它的返回
from envoy.core import expand_args |
我们再仔细看一下,envoy 里面是如何通过管道传递数据的
首先 初始化一个 history 列表,保存每一次执行的命令,如果 len(history) > 0,也说明执行的命令超过一条,则将上条命令的 std_out 前 10 KiB 的数据赋值给 data
再将 data 传递给 Command.run 方法,也就是下个命令的 std_in
def run(command, data=None, timeout=None, kill_timeout=None, env=None, cwd=None): |
envoy 中最关键的就是 Command.run 这个方法了,我们来看看它是如何封装 subprocess 的
Command 的构造函数接收一个命令作为参数
run 方法则比较复杂,里面定义了一个 target 函数,target 函数封装 subprocess.Popen,然后将管道中的数据传入 communicate 方法
然后启动了一个新的线程,等待线程执行完成或者超时,并做一些检查 以保证进程完全退出,最后返回 std_out 和 std_err
class Command(object): |
总结
envoy 的代码还是很简单的,代码里面也没有用什么黑魔法,毕竟只是一个简单的封装