bgo: 具備擴充套件性的 go 程式構建工具

hedzr發表於2022-02-06

bgo v0.3.0+

前言

我們已經在 bgo: 讓構建 go 程式更容易 中介紹了 bgo 的基本能力。

經過幾天的迭代,初步感覺到比較穩定了,因此發了 0.3.0 版本,作為是春節前的劃斷。

新版本有了

節後嘛,得益於 cmdr 原有的 Aliases 功能的升級(除夕時遇到很多意外,都是忙亂惹的禍),bgo 向著不僅只是個 main 包批量構建器邁出了一小步:

我們通過 Aliases 的方式提供了預建的 check-code-quanlities 功能。

這是 v0.3.1+ 之後提供的新功能。

check-code-qualities 功能

這個功能是需要第三方工具的。當前需要 golint 和 gocyclo 在場,此外也需要 gofmt 工具。前兩者需要提前安裝:

go install golang.org/x/lint/golint
go install github.com/fzipp/gocyclo

當上述工具有效時,bgo 可以代為行使上述工具提供的質量檢查功能:

bgo check-code-quanlities
bgo chk
# Or
bgo chk ./...

這個命令依次執行 gofmt, golint 以及 gocyclo 工具,對你的當前資料夾以及下級進行程式碼質量檢測。

你可以附帶引數如 ./... 或者其它指定的資料夾偏移。

Homebrew

brew 版本預建了安裝指令碼,你需要更新 hedzr/brew Tap 然後 reinstall bgo。

由於 brew 通過 update 命令來更新它自己以及所有的taps,因此其效率可能太低下。我覺得,一個變通的方法是:

brew untap hedzr/brew
brew tap hedzr/brew

brew 現在會安裝預置配置檔案到 /usr/local/etc/bgo/。

後文我們會介紹其它環境應該怎麼辦。

正文

上面提到的功能,是依賴於 cmdr 的 Aliases 能力。因此我們對此有必要進行解釋。

bgo 新版本的安裝

首先來講,現在 bgo 的 release 下載包中攜帶了一個 etc/bgo 子目錄,你需要將其移動為 $HOME/.bgo 目錄:

wget https://github.com/hedzr/bgo/releases/download/v0.3.3/bgo-darwin-amd64.tgz
tar -xf bgo-darwin-amd64.tgz
mv bin/bgo /usr/local/bin/bgo
mv etc/bgo ~/.bgo

# 如果使用 zsh 環境,重新生成自動完成指令碼
bgo gen sh --zsh

現在在 $HOME/.bgo 目錄包含了預建 aliases 命令的定義。

具體來講,它( $HOME/.bgo/conf.d/80.aliases.yml )是這樣的:

app:

  aliases:
    # group:                                  # group-name (optional). such as: "別名".
    commands:
      # - title: list
      #   short-name: ls
      #   # aliases: []
      #   # name: ""
      #   invoke-sh: ls -la -G                # for macOS, -G = --color; for linux: -G = --no-group
      #   # invoke: "another cmdr command"
      #   # invoke-proc: "..." # same with invoke-sh
      #   desc: list the current directory

      - title: check-code-qualities
        short-name: chk
        # aliases: [check]
        # name: ""
        # group: ""
        # hidden: false
        invoke-sh: |
          echo "Command hit: { {.Cmd.GetDottedNamePath}}"
          echo "fmt { {.ArgsString}}"
          gofmt -l -s -w { {range .Args}}{ {.}}{ {end}}
          echo "lint { {.ArgsString}}"
          golint { {.ArgsString}}
          echo "cyclo ."
          gocyclo -top 20 .
        # invoke: "another cmdr command"
        # invoke-proc: "..." # same with invoke-sh
        shell: /usr/bin/env bash  # optional, default is /bin/bash
        desc: pre-options before releasing. typically fmt,lint,cyclo,...

想必我無需額外解釋了。

正式發版時這個檔案具有更多命令別名定義

這裡提供了一套擴充機制(通過 shell 指令碼片段),你可以繼續擴充你自己的特定命令,透過 bgo 的命令系統來進一步簡化構建前後的各種任務。

在上面的 yaml 程式碼中,解除 title: list 所在的 map 的註釋即可使能一條 list 命令,這是 ls 的同義詞。它當然沒有實際意義,其目的在於向你解釋怎麼新增自己的另一條命令(或者另 n 條)。

建立多級子命令系統

在 cmdr 的 examples/fluent) 的附帶的配置檔案 91.cmd-aliases.yml 中,為你展示瞭如何通過 Aliases 能力構建自己的子命令系統:

app:

  aliases:
    group:                                  # group-name (optional). such as: "別名".
    commands:
      - title: list
        short-name: ls
        # aliases: []
        # name: ""
        invoke-sh: ls -la -G                # for macOS, -G = --color; for linux: -G = --no-group
        # invoke: "another cmdr command"
        # invoke-proc: "..." # same with invoke-sh
        desc: list the current directory
      - title: pwd
        invoke-sh: pwd
        desc: print the current directory
      - title: services
        desc: "the service commands and options"
        subcmds:
          - title: ls
            invoke: /server/list            # invoke a command from the command tree in this app
            invoke-proc:                    # invoke the external commands (via: executable)
            invoke-sh:                      # invoke the external commands (via: shell)
            shell: /bin/bash                # or /usr/bin/env bash|zsh|...
            desc: list the services
          - title: start
            flags: []
            desc: start a service
          - title: stop
            flags: []
            desc: stop a service
          - title: git-version
            invoke-proc: git describe --tags --abbrev=0
            desc: print the git version
            group: Proc
          - title: git-revision
            invoke-proc: git rev-parse --short HEAD
            desc: print the git revision
            group: Proc
          - title: kx1
            invoke: /kb
            desc: invoke /kb command
            group: Internal
          - title: kx2
            invoke: ../.././//kb --size 32mb   # allow related path to seek a cmdr-command, and the ugly path is allowed (multiple slashes, ...)
            desc: invoke /kb command
            group: Internal
          - title: kx3
            invoke: /kb --size 2kb
            desc: invoke /kb command
            group: Internal
        flags:
          - title: name
            default: noname
            type: string          # bool, string, duration, int, uint, ...
            group:
            toggle-group:
            desc: specify the name of a service

不僅如此,甚至於你還能為子命令提供專屬的 flag 選項。

使用標誌(Flag)選項

由於 invoke, invoke-proc, invoke-sh 欄位都支援模板展開,所以你可以通過模板語法提取到某個 flag 的實際值,實際值是指使用者在命令列輸入的,又或是該 flag 的預設值。

一個示例的 aliases 定義可以是這樣:

      - title: echo
        invoke-sh: |
          # pwd
          echo "{ {$flg := index .Cmd.Flags 0}}{ {$dpath :=$flg.GetDottedNamePath}} { {$fullpath := .Store.Wrap $dpath}} { {$fullpath}} | { {.Store.GetString $fullpath}}"
        desc: print the name
        flags:
          - title: name
            default:              # default value
            type: string          # bool, string, duration, int, uint, ...
            group:
            toggle-group:
            desc: specify the name to be printed

該模板字串序列幾乎等價於 Golang 程式碼:

flg := obj.Cmd.Flags[0]
dpath := flg.GetDottedNamePath()
fullpath := obj.Store.Wrap(dpath)
stringVal := obj.Store.GetString(dpath) // 從 cmdr Option Store 中抽出該選項的實際值,以字串的形式

模板從上下文變數環境 obj 中得到命中的子命令 echo,即 obj.Cmd;類似的,obj.Store 獲得 cmdr Option Store 的例項,然後是一系列 cmdr 介面呼叫,從而獲得 cmdr 處理命令列引數後設定到 Option Store 中的 --name 的實際值。

其執行的效果類似於:

$ bgo echo --name watching
  app.echo.name | watching

其中,echo 子命令的完整的路徑為 app.echoapp 是隱含的字首,cmdr 使用這樣的隱含的字首來構築一個名字空間,而 Store.Wrap() 正是為了給一般路徑附上這樣的字首。

更新你的自動完成指令碼

在擴充了你的 aliases 之後,你需要更新自動完成指令碼來反應變化。是的,Aliases 們是完全融入 bgo 命令系統中的,因此重新生成一次自動完成指令碼,即可將 aliases 們納入到自動完成的提示列表中。

image-20220201014605480

一個示意圖如上。

小節

有了上面介紹的這些資訊,你將可以在不必修改 bgo 原始碼的情況下,自行擴充 bgo 了。

image-20220202111546956

你可以嘗試:

  • 新增 cov(coverage)命令,簡短快捷地做覆蓋測試
  • bench
  • 增加前置指令碼以便做資原始檔打包
  • 等等

在新版本中,分發包中已經包含了 coverage 命令定義,不妨對比一下。

或者直接瀏覽 repo 中的配置檔案定義 ci/etc/bgo/conf.d/80.aliases.yml

bgo 希望做的是將不斷重複的冗長的命令列縮短到一個或者兩個子命令的程度,讓每次工作在 6-8 擊鍵之內。這比你充分利用 zsh 的自動完成以及上下翻頁等功能還要有用得多。

具備 Aliases 融合能力後,現在說一句 bgo: 富於擴充套件性的 go 程式構建工具 大約勉強也能算作是名副其實了。

其實,我們尚未介紹由 cmdr 支援的 Extensions 特性,它允許你在特定的資料夾中存放一系列的資料夾和指令碼檔案,並將其融入既有的命令系統中,如同上面 Aliases 特性藉助於 YAML 配置檔案所做的那樣。

Cmdr 所提供的 Extensions,Aliases,以及 Addons 等外部擴充套件能力,一個主要的激發就來自於 git aliases,以及還在網際網路之前的一些 DOS 應用程式的特色。

親自復現出自己記憶中的那樣的效果,肯定是對一個 developer 的最好的獎賞,養在深閨也無所謂了,我已經得到了我要的褒獎。

題外話

我一直想要復刻一份 LIST 出來。只是一直沒有精力動手。

LIST.COM 是已故的 Vernon D. Buerg 所開發的 DOS shareware。這個工具是我做反向 TWAY 的時候的有力工具之一,恩,它倒不是親自做反向的,只是一個檔案列表器而已。

關於 bgo 的配置檔案

支援多種格式

同樣是源自 cmdr 提供的支援,bgo 能夠自動識別 json,toml 和 yml(或 yaml)字尾。

也就是說,在 一個工作目錄中,存在 .bgo.yml 或者 .bgo.toml 都是可以的。儘管我們的示例中總是使用 yaml 向你講解如何編寫,但將其改變為不同的檔案格式能夠一樣地生效。而 bgo 或者說 cmdr 則會自動載入它們。

配置資料夾

你已經注意到,我們在 $HOME/.bgo 下提供了 bgo.yml,並且其中的子目錄 conf.d 中提供了 80.aliases.yml。

按照 cmdr 的約定,一個配置檔案目錄中一定要有同名(即 bgo)的配置檔案,至於字尾應該是 .json.toml.yml.yaml 中的一個。cmdr 的配置檔案被分為三種型別:primary,secondary 以及 alternative。

對於 bgo 來說, $HOME/.bgo 是 primary 配置檔案組的一個可能的位置,bgo 和 cmdr 會自動搜尋若干預定義的位置(包括 /usr/local/etc/bgo 以及 $HOME/.bgo)來試圖載入 primary 配置檔案,然後將其 conf.d 作為監視資料夾,並載入其中的任何 .json.toml.yml.yaml 。

所以,混用不同的配置檔案格式也無所謂。

conf.d 自動配置資料夾

在主配置檔案的目錄裡,conf.d 子目錄是被監視的,這裡面的任何配置檔案都能夠被自動過載。當然,對於 bgo 來說自動過載毫無意義。

但是你可以在這個資料夾裡面新增一系列的配置檔案,例如 alias-001.yml, alias-002.yml。這種結構對於 ci 操作或者說 devops 操作會是很方便的,你無需絞盡腦汁去編排指令碼想一個 yaml 中新增一大段 yaml 片段,還要保證它們的嵌入位置適當,縮排層次適當。直接新增一個yml好了。

輔助配置檔案

至於當前工作目錄下的 .bgo.yml,是作為 Alternative/Secondary 配置檔案組的身份被載入的。

按照 cmdr 的約定,如果 .bgo.yml 被作為 Alternative 配置檔案載入,則這個配置檔案不含有子資料夾監視,並且可以開啟自動配置檔案回寫功能。不過這個功能在 bgo 中並沒有開啟,因為回寫功能會抹去配置檔案中的註釋部分,這可能往往並不是你所想要的。

之所以身份不定,是因此 cmdr 支援同時從 Primary/Seconary/Alternative 三個位置載入三組配置併合併到一起。儘管我們沒有專門說明,bgo 在這裡留有很多擴充的可能性。

bgo init 時改用不同格式

使用下面的語法,可以建立不同的配置檔案格式:

bgo init --output=.bgo.yml
bgo init --output=.bgo.yaml
bgo init --output=.bgo.json
bgo init --output=.bgo.toml

輸出檔名的字尾名決定了初始化操作將掃描結果儲存為那一種配置檔案格式。

後記

bgo 目前存在的問題:

  • 沒有 Windows 系統下的有力測試,因此不太確定配置檔案的載入位置是否能被有效識別。
  • 配置檔案中的 bash shell 可能會在 windows 中改為 powershell 還是 cmd?我不太知道,或許需要少許調整才能工作。

    • FEEL FREE TO ISSUE ME

image-20220202111728058

上次說到,這次是突然動念,直接就做的。然後找空去看了看 goxc,哎唷我去

看了,人家乾脆都停更了。

頓時覺得前途喵喵啊。

為什麼我覺得 go build 交叉編譯並沒有那麼 simple 呢,或者說麻煩的很吧。唉,不管了,反正 bgo 就是這麼個工具了。

REFs

?

相關文章