Python 命令行之旅:使用 docopt 實現 git 命令

Python 命令行之旅:使用 docopt 實現 git 命令

作者:HelloGitHub-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[2] 是一個和 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 命令
"""
pass
def handle_push(git):
"""
處理 push 命令
"""
pass
if __name__ == '__main__':
cli()

下面我們將一步步地實現我們的 git 程序。

五、實現

假定我們在 docopt-git.py[3] 文件中實現我們的 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.
/<pathspec>

進而就可以在 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>'] 表示添加的路徑。/<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)
/<pathspec>

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 命令
"""
cmd = ['git', 'commit', '-m', msg]
output = git.execute(cmd)
print(output)

5.5 push 子命令

如果 args['push'] 為 True,說明輸入了 commit 子命令,那麼就調用 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 便可查詢項目狀態。

想看整個源碼,請戳 docopt-git.py[4]

六、小結

本文簡單介紹了日常工作中常用的 git 命令,然後提出實現它的思路,最終一步步地使用 docopt 和 gitpython 實現了 git 程序。

對比 argparse 的實現版本,你會發現使用 docopt 來實現變得非常簡單,子解析器、參數類型什麼的統統不需要關心!這可以說是 docopt 最大的優勢了。

關於 docopt 的講解將告一段落,回顧下 docopt 的三步曲,加上今天的內容,感覺它的使用方式還是比 argparse 簡單不少的。

現在,你已學會了兩個命令行解析庫的使用了。但你以為這就夠了嗎?

但人類的智慧是多麼璀璨呀,有些人並不喜歡這兩個庫的使用方式,於是他們有開闢了一個全新的思路。

在下篇文章中,將為大家介紹一個在 Python 界十分流行的命令行庫 —— click。

[1]HelloGitHub-Team 倉庫: https://github.com/HelloGitHub-Team/Article

[2]python: https://gitpython.readthedocs.io/en/stable/intro.html

[3]docopt-git.py: https://github.com/HelloGitHub-Team/Article/blob/master/contents/Python/cmdline/docopt-git.py

[4]docopt-git.py: https://github.com/HelloGitHub-Team/Article/blob/master/contents/Python/cmdline/docopt-git.py


『講解開源項目系列』——讓對開源項目感興趣的人不再畏懼、讓開源項目的發起者不再孤單。跟著我們的文章,你會發現編程的樂趣、使用和發現參與開源項目如此簡單。歡迎留言聯繫我們、加入我們,讓更多人愛上開源、貢獻開源~


分享到:


相關文章: