天天看點

那個極爽的指令行糾錯軟體 The Fuck 是如何工作的

改好的指令

這裡最重要的部分就是比對規則了,規則是一個特殊子產品集,它有兩個方法:

<code>match(command: command)</code> → bool – 比對上規則則傳回 true;

<code>get_new_command(command: command)</code> → str|list[str] – 否則傳回修改後的指令或指令清單(當有多個可能比對項)

我想這個應用隻是因為它的規則才這麼有趣,編寫自己的規則也很簡單。目前有 75 條可用的規則,大都是有第三方貢獻者寫的。指令是一個類似命名元組namedtuple這樣的資料結構:

<code>command(script: str, stdout: str, stderr: str)</code>

其中 script 是與 shell 類型無關的錯誤指令。

<a target="_blank"></a>

在不同的 shell 中,描述 alias 的方式不同、文法不同(比如在 fish 中 &amp;&amp; 表示為 and)、曆史指令的處理方法也不同,且 shell 還依賴特定的配置檔案(<code>.bashre</code> ,<code>.zshrc</code> 等)。為了避免這些麻煩,在程式中有一個 shells 的子產品把這些與特定 shell 相關的指令轉化為與 sh 相容的類型,并展開别名和環境變量。 是以我們使用<code>shells.from_shell</code> 方法來獲得 command(前面的章節提到過的)的執行個體,在 sh 裡運作并且獲得 stdout 和 stderr。

出錯的指令 → from_shell 子產品 → 與 shell 類型無關的指令 → (可以)在 sh 内運作 –&gt; command 執行個體

對修改好的指令也做了相似地處理,即把與特定 shell 無關的指令通過 shells.to_shell 子產品轉化為與 shell 相關的指令。

the fuck 是一個高可配置的應用,使用者可以開啟或關閉規則、配置 ui、設定規則選項還有進行其他的操作。使用者可以通過修改 <code>~/.thefuck/settring.py</code> 檔案以及環境變量來配置應用:

預設配置 → 通過 setting.py 檔案更新 → 通過環境變量更新

之前版本中,配置對象以參數的形式傳遞到所有需要的場合,雖然那樣還不錯并且能夠測試,但存在過多的重複代碼。而現在是一個單例(<code>thefuck.conf.settings</code>),類似 django 中的 <code>django.conf.settings</code>。

the fuck 的 ui 很簡單,它允許使用者通過(上下)箭頭的方式在修正過的指令清單中進行選擇,使用 enter 來确認選擇,ctrl+c 來跳出程式。 美中不足的是在 python 标準庫中沒有辦法在非 windows 下不通過 curses 來讀取鍵盤輸入,由于别名alias的特性我們又不能在這裡使用 curses。但容易寫出針對 windows 的 <code>msvrt.getch</code>:

<code>import tty</code>

<code>import termios</code>

<code></code>

<code>def getch():</code>

<code>fd = sys.stdin.fileno()</code>

<code>old = termios.tcgetattr(fd)</code>

<code>try:</code>

<code>tty.setraw(fd)</code>

<code>ch = sys.stdin.read(1)</code>

<code>if ch == '\x03': # for compatibility with msvcrt.getch</code>

<code>raise keyboardinterrupt</code>

<code>return ch</code>

<code>finally:</code>

<code>termios.tcsetattr(fd, termios.tcsadrain, old)</code>

另外 ui 也需要修複好的程式指令組成的有序清單,且規則比對耗時應該盡量較短。而加入簡單的啟發式算法後效果還不錯,首先我們按照優先級來比對規則,第一個傳回的修複過的指令是有最大優先級的指令。當使用者按下箭頭按鍵時再選擇其他的指令。是以在大多數的使用場景中都能很快完成任務。

如果從整體來看一下這個應用,會發現它很簡單:

那個極爽的指令行糾錯軟體 The Fuck 是如何工作的

其中 controller(控制器)是當使用者使用 the fuck 來修複錯誤指令時的程式入口,它初始化設定、準備 shells 的互動環境、從 corrector (修正器)來擷取修正過的指令并在 ui 中選擇。corrector 使用所有可用的規則來比對目前指令并且傳回所有可用的修複過的指令。關于ui、設定和規則就說到這裡。

測試是所有軟體項目的最重要的部分之一。沒有測試,軟體可能會由于任一個改變而崩潰。我們使用 pytest 來進行單元測試。由于應用中存在規則,是以需要做很多測試來比對和确認修正過的指令。是以,參數化的測試用例是很有用的,典型的測試是這樣的:

<code>import pytest</code>

<code>from thefuck.rules.cd_mkdir import match, get_new_command</code>

<code>from tests.utils import command</code>

<code>@pytest.mark.parametrize('command', [</code>

<code>command(script='cd foo', stderr='cd: foo: no such file or directory'),</code>

<code>command(script='cd foo/bar/baz',</code>

<code>stderr='cd: foo: no such file or directory'),</code>

<code>command(script='cd foo/bar/baz', stderr='cd: can\'t cd to foo/bar/baz')])</code>

<code>def test_match(command):</code>

<code>assert match(command)</code>

the fuck 應用的最麻煩的部分是它的安裝,應用通過 pip 來釋出,由此産生了一些問題:

有些平台上依賴 python 的頭檔案(python-dev),是以我們需要告訴使用者手動地安裝;

pip 不支援安裝後自動完成一些自定義操作,是以使用者需要手動配置一個别名;

有些使用者使用不支援的 python 版本,應用隻支援 2.7 或者 3.3+ 的版本;

有些老版本的 pip 根本就不安裝依賴項;

有些版本的 pip 忽視 python 版本的依賴關系,是以需要為早于 3.4 的版本安裝 pathlib;

有趣的是有人對這個名字感到很憤怒并且嘗試從 pypi 中移除這個包;

原文釋出時間為:2017-05-05

本文來自雲栖社群合作夥伴“linux中國”