简体   繁体   English

如何将参数传递给python fabric自定义任务

[英]how to pass arguments to a python fabric custom task

I cannot figure out how to actually pass arguments to a fabric custom task. 我无法弄清楚如何将参数实际传递给结构定制任务。

I have a bunch of tasks that all need to do the same setup, so I was hoping to subclass the task and have the base class do the setup and then run the specific subtasks. 我有一堆的任务都需要执行相同的设置,因此我希望将其子类化,并让基类进行设置,然后运行特定的子任务。 Both the setup code and the subtasks need access to some arguments that are passed in from the command-line to the task. 设置代码和子任务都需要访问从命令行传递到任务的某些参数。 I also need to be able to set default values for the arguments. 我还需要能够为参数设置默认值。

Original Attempt 原始尝试

My original attempt shows what I am trying to do without any sub classes. 我最初的尝试显示了我在没有任何子类的情况下要做的事情。 This code works correctly. 此代码正常工作。 The code below is in file tmp1.py: 以下代码在文件tmp1.py中:

from fabric.api import task

def do_setup(myarg):
    ''' common setup for all tasks '''
    print "in do_setup(myarg=%s)" % myarg
    # do setup using myarg for something important

@task
def actual_task1(myarg='default_value', alias='at'):
    print "In actual_task1(myarg=%s)" % myarg
    do_setup(myarg)
    # do rest of work ...

@task
def actual_task2(myarg='default_value', alias='at'):
    print "In actual_task2(myarg=%s)" % myarg
    do_setup(myarg)
    # do rest of work ...

I run it from the command-line without any args and correctly see the default for myarg of 'default_value' 我从命令行运行它而没有任何参数,并且正确地看到了myarg的默认值'default_value'

fab -f ./tmp1.py actual_task1

Prints: 印刷品:

In actual_task1(myarg=default_value)
in do_setup(myarg=default_value)
Done.

Then I call it with myarg='hello' and see that 'hello' gets passed through correctly 然后我用myarg ='hello'称呼它,然后看到'hello'正确通过

fab -f ./tmp1.py actual_task1:myarg='hello'

It outputs: 它输出:

In actual_task1(myarg=hello)
in do_setup(myarg=hello)
Done.

Attempt with a custom task 尝试执行自定义任务

My next attempt is to make a common task to encapsulate the setup part. 我的下一个尝试是做一个常见的任务来封装安装部分。 This is copied from http://docs.fabfile.org/en/1.5/usage/tasks.html The code below is in the file tmp2.py: 这是从http://docs.fabfile.org/en/1.5/usage/tasks.html复制的。以下代码位于文件tmp2.py中:

from fabric.api import task
from fabric.tasks import Task

def do_setup(myarg):
    ''' common setup for all tasks '''
    print "in do_setup(myarg=%s)" % myarg
    # do setup using myarg for something important

'''
Attempt to make a common task to encapsulate the setup part
copied from http://docs.fabfile.org/en/1.5/usage/tasks.html
'''
class CustomTask(Task):
    def init(self, func, myarg, args, *kwargs):
        super(CustomTask, self).init(args, *kwargs)
        print("=> init(myarg=%s, args=%s, kwargs=%s" % (myarg, args, kwargs))
        self.func = func
        self.myarg = myarg
        print "in init: self.func=",self.func,"self.myarg=",self.myarg

    def run(self, *args, **kwargs):
        return self.func(self.myarg, *args, **kwargs)

@task(task_class=CustomTask, myarg='default_value', alias='at')
def actual_task1():
    print "In actual_task1(myarg=%s)" % myarg
    # do rest of work ...

When run, there are 2 problems: 运行时,有两个问题:

  1. __init__ gets "default_value" instead of "Hello" __init__获取“ default_value”而不是“ Hello”

  2. It complains that actual_task1() expects 0 arguments 它抱怨actual_task1()需要0个参数

I run it this way: 我这样运行:

fab -f ./tmp2.py actual_task1:myarg="Hello"

Prints: 印刷品:

=> init(myarg=default_value, args=(), kwargs={'alias': 'at'}
in init: self.func= self.myarg= default_value
Traceback (most recent call last):
File "/home/xxx/Documents/pyenvs/xxx/local/lib/python2.7/site-packages/fabric/main.py", line 743,      in main args, *kwargs
File "/home/xxx/Documents/pyenvs/xxx/local/lib/python2.7/site-packages/fabric/tasks.py", line 405,  in execute results[''] = task.run(args, *new_kwargs)
File "/home/xxx/test_fab/tmp2.py", line 21, in run
return self.func(self.myarg, args, *kwargs)
TypeError: actual_task1() takes no arguments (1 given)

I spent quite a bit of time trying to make this work but I cannot seem to solve the default_value issue. 我花了很多时间尝试使之工作,但似乎无法解决default_value问题。 I must be missing something? 我肯定错过了什么?

I would appreciate some help figuring out how to make this sample program run. 我希望能得到一些帮助,以弄清楚如何使此示例程序运行。 The second version with the custom task needs to behave just like the original version I showed. 具有自定义任务的第二个版本的行为必须与我显示的原始版本相同。

Thank you for any help with this issue. 感谢您对这个问题的任何帮助。

Fixed example with setup: 固定示例安装:

from fabric.api import task
from fabric.tasks import Task

def do_setup(foo, verbose):
    ''' common setup for all tasks '''
    print "IN do_setup(foo=%s, verbose=%s)" % (foo, verbose)
    # do setup using foo and verbose...

class CustomTask(Task):
    def __init__(self, func, *args, **kwargs):
        ''' 
        The special args like hosts and roles do not show up in
        args, and kwargs, they are stripped already.

        args and kwargs may contain task specific special arguments
        (e.g. aliases, alias, default, and name) to customize the
        task. They are set in the @task decorator and cannot be passed
        on the command-line. Note also that these special task
        arguments are not passed to the run method.

        Non-special arguments (there are none in this example) are
        set in the task decorator. These other arguments are not
        passed to the run method and cannot be overridden from the
        command-line.

        Note that if you pass any "task specific special arguments" or
        "non-special arguments declared in the task decorator" from the
        command-line, they are treated as different arguments and the
        command-line values are passed to the run method but not to
        this method.
        '''
        super(CustomTask, self).__init__(*args, **kwargs)
        print "IN __init__(args=%s, kwargs=%s)" % (args, kwargs)
        self.func = func

    def run(self, foo='foo_default_val', verbose='verbose_default_val', 
            *args, **kwargs):
        ''' 
        The arguments to this method will be:
        1) arguments from the actual task (e.g. foo and verbose). This method
        is where you set a default value for the arguments from the
        actual_task, not on the actual_task.
        2) task specific arguments from the command-line
        (e.g. actual_task:bar='xxx'). This example is not expecting any,
        so it strips them and does not pass them to the
        actual_function one (e.g. it calls self.func with only foo
        and verbose and does not pass args and kwargs)
        '''
        print "IN run(foo=%s, verbose=%s, args=%s, kwargs=%s)" % \
                  (foo, verbose, args, kwargs)
        do_setup(foo, verbose)
        return self.func(foo, verbose)

@task(task_class=CustomTask, alias="RUNME")
def actual_task(foo, verbose):
    print 'IN task actual_task(foo=%s, verbose=%s)' % (foo, verbose)

Run with only host specified on the command-line: 仅在命令行上指定的主机上运行:

fab -f ./example_with_setup.py actual_task:host='hhh'

IN __init__(args=(), kwargs={'alias': 'RUNME'})
[hhh] Executing task 'actual_task'
IN run(foo=foo_default_val, verbose=verbose_default_val, args=(), kwargs={})
IN do_setup(foo=foo_default_val, verbose=verbose_default_val)
IN task actual_task(foo=foo_default_val, verbose=verbose_default_val)

Run specifying foo on the commandline: 在命令行上运行指定foo:

fab -f ./example_with_setup.py actual_task:host='hhh',foo='bar'

IN __init__(args=(), kwargs={'alias': 'RUNME'})
[hhh] Executing task 'actual_task'
IN run(foo=bar, verbose=verbose_default_val, args=(), kwargs={})
IN do_setup(foo=bar, verbose=verbose_default_val)
IN task actual_task(foo=bar, verbose=verbose_default_val)

Run specifying both foo and verbose on the command-line: 在命令行上同时指定foo和verbose:

fab -f ./example_with_setup.py actual_task:host='hhh',foo='bar',verbose=True

IN __init__(args=(), kwargs={'alias': 'RUNME'})
[hhh] Executing task 'actual_task'
IN run(foo=bar, verbose=True, args=(), kwargs={})
IN do_setup(foo=bar, verbose=True)
IN task actual_task(foo=bar, verbose=True)

In the custom class section, the function actual_task1 doesn't actually take arguments, so the only valid way to invoke your fabric file is: 在自定义类部分中,函数actual_task1实际上并不接受参数,因此调用结构文件的唯一有效方法是:

fab -f ./tmp2.py actual_task1

Furthermore, I don't think you're actually calling do_setup in either CustomTask or actual_task1 此外,我认为您实际上并do_setupCustomTaskactual_task1调用actual_task1

This is the fixed example. 这是固定的示例。

# fixed the example from http://docs.fabfile.org/en/1.8/usage/tasks.html
from fabric.api import task
from fabric.tasks import Task

class CustomTask(Task):
    def __init__(self, func, myarg1, *args, **kwargs):
        ''' 
        The special args like hosts and roles do not show up in
        args, and kwargs, they are stripped already.

        args and kwargs may contain task specific special arguments
        (e.g. aliases, alias, default, and name) to customize the
        task. They are set in the @task decorator and cannot be passed
        on the command-line. Note also that these special task
        arguments are not passed to the run method.

        Non-special arguments (in this example myarg1) are set in the task
        decorator. These other arguments are not passed to the run
        method and cannot be overridden from the command-line. 

        Note that if you pass any "task specific special arguments" or
        "non-special arguments declared in the task decorator" from the
        command-line, they are treated as different arguments and the
        command-line values are passed to the run method but not to
        this method.
        '''
        super(CustomTask, self).__init__(*args, **kwargs)
        print "IN __init__(myarg1=%s, args=%s, kwargs=%s)" % \
            (myarg1, args, kwargs)
        self.func = func
        self.myarg1 = myarg1

    def run(self, myarg2='default_value2', *args, **kwargs):
        ''' 
        The arguments to this method will be:
        1) arguments from the actual task (e.g. myarg2). This method
        is where you set a default value for the arguments from the
        actual_task, not on the actual_task.
        2) task specific arguments from the command-line
        (e.g. actual_host:foo='foo'). This example is not expecting
        any, so it strips them and does not pass them to the
        actual_function (e.g. it calls self.func with only myarg2 and
        does not pass args and kwargs)
        '''
        print "IN run(myarg2=%s, args=%s, kwargs=%s)" % \
            (myarg2, args, kwargs)
        return self.func(myarg2)

@task(task_class=CustomTask, myarg1='special_value', alias='RUNME')
def actual_task(myarg2):
    print "IN actual_task(myarg2=%s)" % myarg2

Run with only hosts specified on the command-line: 仅在命令行上指定的主机上运行:

fab -f ./fixed_example actual_task:hosts="hhh"

IN __init__(myarg1=special_value, args=(), kwargs={'alias': 'RUNME'})
[hhh] Executing task 'actual_task'
IN run(myarg2=default_value2, args=(), kwargs={})
IN actual_task(myarg2=default_value2)

Run specifying myarg2 on the command-line: 在命令行上运行指定myarg2:

fab -f ./fixed_example actual_task:hosts="hhh",myarg2="good_value"

IN __init__(myarg1=special_value, args=(), kwargs={'alias': 'RUNME'})
[hhh] Executing task 'actual_task'
IN run(myarg2=good_value, args=(), kwargs={})
IN actual_task(myarg2=good_value)

Bad run specifying myarg1 and alias on the command-line. 在命令行上指定myarg1和别名时运行错误。 Notice that init gets the values specified in the task decorator and not the values from the command-line. 请注意, init获取的是任务装饰器中指定的值,而不是命令行中的值。 Notice that run gets myarg1 and alias as arguments now. 请注意,运行现在将myarg1和别名作为参数。

fab -f ./fixed_example actual_task:hosts="hhh",myarg1="myarg1_from_commandline",alias="alias_from_commandline"

IN __init__(myarg1=special_value, args=(), kwargs={'alias': 'RUNME'})
[hhh] Executing task 'actual_task'
IN run(myarg2=default_value2, args=(), kwargs={'alias': 'alias_from_commandline', 'myarg1': 'myarg1_from_commandline'})
IN actual_task(myarg2=default_value2)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM