Can I catch error codes when using Fabric to run()

2019-01-30 22:13发布

Normally Fabric quits as soon as a run() call returns a non-zero exit code. For some calls, however, this is expected. For example, PNGOut returns an error code of 2 when it is unable to compress a file.

Currently I can only circumvent this limitation by either using shell logic (do_something_that_fails || true or do_something_that_fails || do_something_else), but I'd rather be able to keep my logic in plain Python (as is the Fabric promise).

Is there a way to check for an error code and react to it rather than having Fabric panic and die? I still want the default behaviours for other calls, so changing its behaviour by modifying the environment doesn't seem like a good option (and as far as I recall, you can only use that to tell it to warn instead of dying anyway).

4条回答
做自己的国王
2楼-- · 2019-01-30 22:22

Apparently messing with the environment is the answer.

fabric.api.settings can be used as a context manager (with with) to apply it to individual statements. The return value of run(), local() and sudo() calls isn't just the output of the shell command, but also has special properties (return_code and failed) that allow reacting to the errors.

I guess I was looking for something closer to the behaviour of subprocess.Popen or Python's usual exception handling.

查看更多
Fickle 薄情
3楼-- · 2019-01-30 22:39

Yes, you can. Just change the environment's abort_exception. For example:

from fabric.api import settings

class FabricException(Exception):
    pass

with settings(abort_exception = FabricException):
    try:
        run(<something that might fail>)
    except FabricException:
        <handle the exception>

The documentation on abort_exception is here.

查看更多
我想做一个坏孩纸
4楼-- · 2019-01-30 22:46

You can prevent aborting on non-zero exit codes by using the settings context manager and the warn_only setting:

from fabric.api import settings

with settings(warn_only=True):
    result = run('pngout old.png new.png')
    if result.return_code == 0: 
        do something
    elif result.return_code == 2: 
        do something else 
    else: #print error to user
        print result
        raise SystemExit()

Update: My answer is outdated. See comments below.

查看更多
Root(大扎)
5楼-- · 2019-01-30 22:48

try this

from fabric.api import run, env
env.warn_only = True # if you want to ignore exceptions and handle them yurself

command = "your command"
x = run(command, capture=True) # run or local or sudo
if(x.stderr != ""):
    error = "On %s: %s" %(command, x.stderr)
    print error
    print x.return_code # which may be 1 or 2
    # do what you want or
    raise Exception(error) #optional
else:
    print "the output of %s is: %s" %(command, x)
    print x.return_code # which is 0
查看更多
登录 后发表回答