Python 指令行之旅:使用 docopt 實作 git 指令
原文發表于
Prodesire 部落格。
一、前言
在前面兩篇介紹
docopt
的文章中,我們全面了解了
docopt
的能力。按照慣例,我們要像使用
argparse
一樣使用
docopt
來實作 git 指令。
為了讓沒讀過
使用 argparse 實作 git 指令
的小夥伴也能讀明白本文,我們仍會對 git 常用指令和 gitpython 做一個簡單介紹。
本系列文章預設使用 Python 3 作為解釋器進行講解。
若你仍在使用 Python 2,請注意兩者之間文法和庫的使用差異哦~
二、git 常用指令
當你寫好一段代碼或增删一些檔案後,會用如下指令檢視檔案狀态:
git status
确認檔案狀态後,會用如下指令将的一個或多個檔案(夾)添加到暫存區:
git add [pathspec [pathspec ...]]
然後使用如下指令送出資訊:
git commit -m "your commit message"
最後使用如下指令将送出推送到遠端倉庫:
git push
我們将使用
docopt
和
gitpython
庫來實作這 4 個子指令。
三、關于 gitpython
gitpython是一個和
git
倉庫互動的 Python 第三方庫。
我們将借用它的能力來實作真正的
git
邏輯。
安裝:
pip install gitpython
四、思考
在實作前,我們不妨先思考下會用到
docopt
的哪些功能?整個程式的結構是怎樣的?
docopt
不同于使用
argparse
時需要考慮嵌套解析器、各類參數等問題,在使用
docopt
隻需将我們要實作的 git 指令用接口描述先定義清楚即可。
程式結構
程式結構上,除了開頭處定義接口描述外,其餘和使用
argparse
實作 git 指令的結構是一樣的:
- 指令行程式需要一個
函數來作為統一的入口,它負責建構解析器,并解析指令行參數cli
- 我們還需要四個
函數響應對應的子指令handle_xxx
則基本結構如下:
import os
import docopt
from git.cmd import Git
def cli():
"""
git 命名程式入口
"""
pass
def handle_status(git):
"""
處理 status 指令
"""
pass
def handle_add(git, pathspec):
"""
處理 add 指令
"""
pass
def handle_commit(git, msg):
"""
處理 -m <msg> 指令
"""
pass
def handle_push(git):
"""
處理 push 指令
"""
pass
if __name__ == '__main__':
cli()
下面我們将一步步地實作我們的
git
程式。
五、實作
假定我們在
docopt-git.py檔案中實作我們的
git
5.1 定義接口描述
根據我們的要求,可以很容易的定義出接口描述:
Usage:
git status
git add [<pathspec>...]
git commit -m msg
git push
Options:
-h --help Show help.
-m --message msg Commit with message.
進而就可以在
cli()
中解析指令行:
def cli():
"""
git 命名程式入口
"""
args = docopt(__doc__)
git = Git(os.getcwd())
5.2 status 子指令
如果
args['status']
為
True
,說明輸入了 status 子指令,那麼就調用
handle_status
函數進行處理。
def cli():
...
if args['status']:
handle_status(git)
def handle_status(git):
"""
處理 status 指令
"""
cmd = ['git', 'status']
output = git.execute(cmd)
print(output)
不難看出,我們最後調用了真正的
git status
來實作,并列印了輸出。
5.3 add 子指令
args['add']
True
,說明輸入了 add 子指令,那麼就調用
handle_add
函數進行處理,需要傳入
args['<pathspec>']
表示添加的路徑。
def cli():
...
elif args['add']:
handle_add(git, args['<pathspec>'])
def handle_add(git, pathspec):
"""
處理 add 指令
"""
cmd = ['git', 'add'] + pathspec
output = git.execute(cmd)
print(output)
5.4 commit 子指令
args['commit']
True
,說明輸入了 commit 子指令,那麼就調用
handle_commit
args['--message']
表示送出的資訊。
def cli():
...
elif args['commit']:
handle_commit(git, args['--message'])
def handle_commit(git, msg):
"""
處理 -m <msg> 指令
"""
cmd = ['git', 'commit', '-m', msg]
output = git.execute(cmd)
print(output)
5.5 push 子指令
args['push']
True
handle_push
def cli():
...
elif args['push']:
handle_push(git)
def handle_push(git):
"""
處理 push 指令
"""
cmd = ['git', 'push']
output = git.execute(cmd)
print(output)
至此,我們就實作了一個簡單的
git
指令行,使用
python docopt-git.py status
便可查詢項目狀态。
想看整個源碼,請戳
六、小結
本文簡單介紹了日常工作中常用的
git
指令,然後提出實作它的思路,最終一步步地使用
docopt
gitpython
實作了
git
對比
argparse
的實作版本,你會發現使用
docopt
來實作變得非常簡單,子解析器、參數類型什麼的統統不需要關心!這可以說是
docopt
最大的優勢了。
關于
docopt
的講解将告一段落,回顧下
docopt
的三步曲,加上今天的内容,感覺它的使用方式還是比
argparse
簡單不少的。
現在,你已學會了兩個指令行解析庫的使用了。但你以為這就夠了嗎?
但人類的智慧是多麼璀璨呀,有些人并不喜歡這兩個庫的使用方式,于是他們有開辟了一個全新的思路。
在下篇文章中,将為大家介紹一個在 Python 界十分流行的指令行庫 ——
click