fexpect 源码

通过fabric 调用执行需要人机交互,输入确认信息时,一般有两种方案:

1、fabric 自身 with settings(prompts=prompt_restore)。
2、pexpect组件解决。

这里的fexpect,其实是对pexpect的包装。只是使用方式上与fabric 配搭起来更加灵活。其主要源码如下:

1、ilogue/fexpect/api.py
####################################
import fabric.api
from ilogue.fexpect.internals import wrapExpectations, wrapExpectationsLocal, ExpectationContext


def expect(promptexpr, response, exitAfter=-1):
    if not exitAfter == -1:
        return [(promptexpr, response, exitAfter)]
    return [(promptexpr, response)]

# Use inside an expect(), like:  `expect('>>>', controlchar('D'))`
def controlchar(char):
    char = char.lower()
    a = ord(char)
    if a >= 97 and a <= 122:
        a = a - ord('a') + 1
        return chr(a)
    d = {'@': 0, '`': 0,
        '[': 27, '{': 27,
        '\': 28, '|': 28,
        ']': 29, '}': 29,
        '^': 30, '~': 30,
        '_': 31,
        '?': 127}
    if char not in d:
        return 0
    return chr(d[char])

def expecting(e):
    return ExpectationContext(e)

def run(cmd, **kwargs):
    #run wrapper 
    if 'expectations' in fabric.state.env and 
        len(fabric.state.env.expectations) > 0:
        cmd = wrapExpectations(cmd)
    return fabric.api.run(cmd, **kwargs)

def sudo(cmd, **kwargs):
    #sudo wrapper
    if 'expectations' in fabric.state.env and 
        len(fabric.state.env.expectations) > 0:
        cmd = wrapExpectations(cmd)
    return fabric.api.sudo(cmd, **kwargs)

def local(cmd, **kwargs):
    #local wrapper
    if 'expectations' in fabric.state.env and 
        len(fabric.state.env.expectations) > 0:
        cmd = wrapExpectationsLocal(cmd)
    return fabric.api.local(cmd, **kwargs)


2、ilogue/fexpect/internals.py
#####################################
import shortuuid
from StringIO import StringIO
import fabric

class ExpectationContext(object):
    def __init__(self,expectations):
        self.expectations = expectations
    def __enter__(self):
        fabric.state.env.expectations = self.expectations
    def __exit__(self, type, value, tb):
        fabric.state.env.expectations = []

def wrapExpectations(cmd):
    script = createScript(cmd)
    remoteScript = '/tmp/fexpect_'+shortuuid.uuid()
    import pexpect
    pexpect_module = pexpect.__file__
    if pexpect_module.endswith('.pyc'):
        pexpect_module = pexpect_module[:-1]
    # If mode not set explicitly, and this is run as a privileged user, 
    # later command from an unpriviliged user will fail due to the permissions
    # on /tmp/pexpect.py
    fabric.api.put(pexpect_module,'/tmp/', mode=0777) 
    fabric.api.put(StringIO(script),remoteScript)
    wrappedCmd = 'python '+remoteScript
    return wrappedCmd

def wrapExpectationsLocal(cmd):
    script = createScript(cmd)
    remoteScript = '/tmp/fexpect_'+shortuuid.uuid()
    with open(remoteScript, 'w') as filehandle:
        filehandle.write(script)
    wrappedCmd = 'python '+remoteScript
    return wrappedCmd

def createScript(cmd):
    useShell =fabric.state.env.shell
    to = 30*60 # readline timeout 8 hours
    #write header:
    s = '#!/usr/bin/python
'
    s+= 'import sys
'
    s+= 'from time import sleep
'
    s+= 'import pexpect
'
    #write expectation list:
    s+= 'expectations=['
    for e in fabric.state.env.expectations:
        s+= '"{0}",'.format(e[0])
    s+= ']
'
    #start
    spwnTem = """child = pexpect.spawn("""{shellPrefix}{shell} "{cmd}" """,timeout={to})
"""
    s+= spwnTem.format(shell=useShell,cmd=cmd,to=to,shellPrefix=('' if useShell.startswith('/') else '/bin/'))
    s+= "child.logfile = sys.stdout
"
    s+= "while True:
"
    s+= "	try:
"
    s+= "		i = child.expect(expectations)
"
    i = 0
    for e in fabric.state.env.expectations:
        ifkeyw = 'if' if i == 0 else 'elif'
        s+= "		{0} i == {1}:
".format(ifkeyw,i)
        s+= "			child.sendline('{0}')
".format(e[1])
        s+= "			expectations[i]="__MANGLE__"

"
        if len(e)>2:
            s+= "			sleep({0})
".format(e[2])
            s+= "			print('Exiting fexpect for expected exit.')
"
            s+= '			break
'
        i += 1
    s+= '	except pexpect.EOF:
'
    s+= "		print('Exiting fexpect for EOF.')
"
    s+= '		break
'
    s+= '
'
    return s
原文地址:https://www.cnblogs.com/husbandmen/p/12360541.html