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

我們將使用 docoptgitpython 庫來實現這 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,說明輸入了 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

六、小結

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

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

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

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

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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章