Source From Here
1. invoke 可以做什麼?
invoke 是從著名的遠程部署工具 Fabric 中分離出來的,它與 paramiko 一起是 Fabric 的兩大最核心的基礎組件。
除了作為命令行工具,它專注於 “任務執行”(task execution),可以標註和組織任務,並通過 CLI(command-line interface,即命令行界面) 和 shell 命令來執行任務。同樣是任務自動化工具,invoke 與 tox/nox 在側重點上有所不同:
2. 怎麼使用invoke?
首先,安裝很簡單:pip install invoke。其次,簡單使用時有以下要素:
以下是一個簡單的範例:
- task.py
在上述代碼中,我們定義了兩個任務:
以上代碼寫在 tasks.py 文件中,首先導入裝飾器 from invoke import task,@task 裝飾器可以不帶參數,也可以帶參數(參見下一節),被它裝飾了的函數就是一個任務。上下文參數(即上例的 “c”)必須要顯式地指明,如果缺少這個參數,執行時會拋出異常:“TypeError: Tasks must have an initial Context argument!”
然後在 tasks.py 文件的同級目錄中,打開命令行窗口,執行命令。如果執行的位置找不到這個任務文件,則會報錯:“Can't find any collection named 'tasks'!”. 正常情況下,通過執行 inv --list 或者 inv -l,可以看到所有任務的列表(按字母表順序排序):
我們依次執行這兩個任務,其中傳參數時可以默認按位置參數傳參,也可以指定關鍵字傳參。結果是:
缺少傳參時,報錯:"'greet' did not receive required positional arguments: 'name'";多餘傳參時,報錯:"No idea what '???' is!"
3. 如何用好 invoke?
介紹完 invoke 的簡單用法,我們知道了它所需的幾項要素,也大致知道了它的使用步驟,接下來是它的其它用法。
3.1 添加幫助信息
在上例中,“inv -l” 只能看到任務名稱,缺少必要的輔助信息,為了加強可讀性,我們可以這樣寫:
其中,文檔字符串的第一行內容會作為摘錄,在 “inv -l” 的查詢結果中展示,而且完整的內容與 @task 的 help 內容,會對應在 “inv --help” 中展示:
3.2 任務的分解與組合
通常一個大任務可以被分解成一組小任務,反過來,一系列的小任務也可能被串連成一個大任務。在對任務作分解、抽象與組合時,這裡有兩種思路:
第一種思路很容易理解,實現與使用都很簡單,但是其缺點是缺少靈活性,難於單獨執行其中的某個/些子任務。適用於相對獨立的單個任務,通常也不需要invoke 就能做到(使用 invoke 的好處是,擁有命令行的支持); 第二種思路更加靈活,既方便單一任務的執行,也方便多任務的組合執行。實際上,這種場景才是 invoke 發揮最大價值的場景。
那麼,invoke 如何實現分步任務的組合呢?可以在 @task 裝飾器的 “pre” 與 “post” 參數中指定,分別表示前置任務與後置任務:
clean 與 message 任務作為子任務,可以單獨調用,也可以作為 build 任務的前置與後置任務而組合使用:
這兩個參數是列表類型,即可設置多個任務。另外,在默認情況下,@task 裝飾器的位置參數會被視為前置任務,接著上述代碼,我們寫一個:
然後執行,會發現 兩個參數都被視為了 前置任務:
3.3 模塊的拆分與整合
如果要管理很多相對獨立的大型任務,或者需要多個團隊分別維護各自的任務,那麼,就有必要對 tasks.py 作拆分與整合。
例如,現在有多份 tasks.py,彼此是相對完整而獨立的任務模塊,不方便把所有內容都放在一個文件中,那麼,如何有效地把它們整合起來管理呢?invoke 提供了這方面的支持。首先,只能保留一份名為 “tasks.py” 的文件,其次,在該文件中導入其它改名後的任務文件,最後,使用 invoke 的 Collection 類把它們關聯起來。我們把本文中第一個示例文件改名為 task1.py,並新建一個 tasks.py 文件,內容如下:
- tasks.py
每個 py 文件擁有獨立的命名空間,而在此處,我們用 Collection 可以創建出一個新的命名空間,從而實現對所有任務的統一管理。效果如下:
關於不同任務模塊的導入、嵌套、混合、起別名等內容,還有不少細節,請查閱 官方文檔 (Constructing namespaces) 了解。
3.4 交互式操作
某些任務可能需要交互式的輸入,例如要求輸入“y”,按回車鍵後才會繼續執行。如果在任務執行期間需要人工參與,那自動化任務的能力將大打折扣。
invoke 提供了在程序運行期的監控能力,可以監聽 stdout 和 stderr,並支持在 stdin 中輸入必要的信息。例如,假設某個任務(excitable-program)在執行時會提示 “Are you ready? [y/n]”,只有輸入了 “y” 並按下回車鍵,才會執行後續的操作。那麼,在代碼中指定 responses 參數的內容,只要監聽到匹配信息,程序會自動執行相應的操作:
responses 是字典類型,鍵值對分別為監聽內容及其回應內容。需注意,鍵值會被視為正則表達式,所以像本例中的方括號就要先轉義。
3.5 作為命令行工具庫
Python 中有不少好用的命令行工具庫,比如標準庫中的 argparse、Flask 作者開源的 click 與 谷歌 開源的 fire 等等,而 invoke 也可以作為命令行工具庫使用。
事實上,Fabric 項目最初把 invoke 分離成獨立的庫,就是想讓它承擔解析命令行與執行子命令的任務。所以,除了作為自動化任務管理工具,invoke 也可以被用於開發命令行工具。
官方文檔中給出了一個示例,我們可以了解到它的基本用法。假設我們要開發一個 tester工具,讓用戶 pip install tester 安裝,而此工具提供兩個執行命令:tester unit 和 tester intergration。這兩個子命令需要在 tasks.py 文件中定義:
然後在程序入口文件中引入它:
最後在打包文件中聲明入口函數:
如此打包發行的庫,就是一個功能齊全的命令行工具了:
上手容易,開箱即用,invoke 不失為一款可以考慮的命令行工具庫。更多詳細用法,請查閱文檔 (Reusing Invoke’s CLI module as a distinct binary)。
invoke 是從著名的遠程部署工具 Fabric 中分離出來的,它與 paramiko 一起是 Fabric 的兩大最核心的基礎組件。
除了作為命令行工具,它專注於 “任務執行”(task execution),可以標註和組織任務,並通過 CLI(command-line interface,即命令行界面) 和 shell 命令來執行任務。同樣是任務自動化工具,invoke 與 tox/nox 在側重點上有所不同:
2. 怎麼使用invoke?
首先,安裝很簡單:pip install invoke。其次,簡單使用時有以下要素:
以下是一個簡單的範例:
- task.py
- from invoke import task
- @task
- def hello(c):
- print("Hello world!")
- @task
- def greet(c, name):
- c.run(f"echo 'Nice to meet you, {name}'!")
以上代碼寫在 tasks.py 文件中,首先導入裝飾器 from invoke import task,@task 裝飾器可以不帶參數,也可以帶參數(參見下一節),被它裝飾了的函數就是一個任務。上下文參數(即上例的 “c”)必須要顯式地指明,如果缺少這個參數,執行時會拋出異常:“TypeError: Tasks must have an initial Context argument!”
然後在 tasks.py 文件的同級目錄中,打開命令行窗口,執行命令。如果執行的位置找不到這個任務文件,則會報錯:“Can't find any collection named 'tasks'!”. 正常情況下,通過執行 inv --list 或者 inv -l,可以看到所有任務的列表(按字母表順序排序):
我們依次執行這兩個任務,其中傳參數時可以默認按位置參數傳參,也可以指定關鍵字傳參。結果是:
缺少傳參時,報錯:"'greet' did not receive required positional arguments: 'name'";多餘傳參時,報錯:"No idea what '???' is!"
3. 如何用好 invoke?
介紹完 invoke 的簡單用法,我們知道了它所需的幾項要素,也大致知道了它的使用步驟,接下來是它的其它用法。
3.1 添加幫助信息
在上例中,“inv -l” 只能看到任務名稱,缺少必要的輔助信息,為了加強可讀性,我們可以這樣寫:
- @task(help={'name': 'A param for test'})
- def greet(c, name):
- """
- A test for shell command.
- Second line.
- """
- c.run(f"echo 'Nice to meet you, {name}'!")
3.2 任務的分解與組合
通常一個大任務可以被分解成一組小任務,反過來,一系列的小任務也可能被串連成一個大任務。在對任務作分解、抽象與組合時,這裡有兩種思路:
第一種思路很容易理解,實現與使用都很簡單,但是其缺點是缺少靈活性,難於單獨執行其中的某個/些子任務。適用於相對獨立的單個任務,通常也不需要invoke 就能做到(使用 invoke 的好處是,擁有命令行的支持); 第二種思路更加靈活,既方便單一任務的執行,也方便多任務的組合執行。實際上,這種場景才是 invoke 發揮最大價值的場景。
那麼,invoke 如何實現分步任務的組合呢?可以在 @task 裝飾器的 “pre” 與 “post” 參數中指定,分別表示前置任務與後置任務:
- @task
- def clean(c):
- c.run("echo clean")
- @task
- def message(c):
- c.run("echo message")
- @task(pre=[clean], post=[message])
- def build(c):
- c.run("echo build")
這兩個參數是列表類型,即可設置多個任務。另外,在默認情況下,@task 裝飾器的位置參數會被視為前置任務,接著上述代碼,我們寫一個:
- @task(clean, message)
- def test(c):
- c.run("echo test")
3.3 模塊的拆分與整合
如果要管理很多相對獨立的大型任務,或者需要多個團隊分別維護各自的任務,那麼,就有必要對 tasks.py 作拆分與整合。
例如,現在有多份 tasks.py,彼此是相對完整而獨立的任務模塊,不方便把所有內容都放在一個文件中,那麼,如何有效地把它們整合起來管理呢?invoke 提供了這方面的支持。首先,只能保留一份名為 “tasks.py” 的文件,其次,在該文件中導入其它改名後的任務文件,最後,使用 invoke 的 Collection 類把它們關聯起來。我們把本文中第一個示例文件改名為 task1.py,並新建一個 tasks.py 文件,內容如下:
- tasks.py
- from invoke import Collection, task
- import task1
- @task
- def deploy(c):
- c.run("echo deploy")
- namespace = Collection(task1, deploy)
關於不同任務模塊的導入、嵌套、混合、起別名等內容,還有不少細節,請查閱 官方文檔 (Constructing namespaces) 了解。
3.4 交互式操作
某些任務可能需要交互式的輸入,例如要求輸入“y”,按回車鍵後才會繼續執行。如果在任務執行期間需要人工參與,那自動化任務的能力將大打折扣。
invoke 提供了在程序運行期的監控能力,可以監聽 stdout 和 stderr,並支持在 stdin 中輸入必要的信息。例如,假設某個任務(excitable-program)在執行時會提示 “Are you ready? [y/n]”,只有輸入了 “y” 並按下回車鍵,才會執行後續的操作。那麼,在代碼中指定 responses 參數的內容,只要監聽到匹配信息,程序會自動執行相應的操作:
- responses = {r"Are you ready? \[y/n\] ": "y\n"}
- ctx.run("excitable-program", responses=responses)
3.5 作為命令行工具庫
Python 中有不少好用的命令行工具庫,比如標準庫中的 argparse、Flask 作者開源的 click 與 谷歌 開源的 fire 等等,而 invoke 也可以作為命令行工具庫使用。
事實上,Fabric 項目最初把 invoke 分離成獨立的庫,就是想讓它承擔解析命令行與執行子命令的任務。所以,除了作為自動化任務管理工具,invoke 也可以被用於開發命令行工具。
官方文檔中給出了一個示例,我們可以了解到它的基本用法。假設我們要開發一個 tester工具,讓用戶 pip install tester 安裝,而此工具提供兩個執行命令:tester unit 和 tester intergration。這兩個子命令需要在 tasks.py 文件中定義:
- # tasks.py
- from invoke import task
- @task
- def unit(c):
- print("Running unit tests!")
- @task
- def integration(c):
- print("Running integration tests!")
- # main.py
- from invoke import Collection, Program
- from tester import tasks
- program = Program(namespace=Collection.from_module(tasks), version='0.1.0')
- # setup.py
- setup(
- name='tester',
- version='0.1.0',
- packages=['tester'],
- install_requires=['invoke'],
- entry_points={
- 'console_scripts': ['tester = tester.main:program.run']
- }
- )
上手容易,開箱即用,invoke 不失為一款可以考慮的命令行工具庫。更多詳細用法,請查閱文檔 (Reusing Invoke’s CLI module as a distinct binary)。
沒有留言:
張貼留言