天天看點

Python 指令行之旅:使用 docopt 實作 git 指令Python 指令行之旅:使用 docopt 實作 git 指令

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