使用 Go 語言在 MacOS 建立一個自定義的命令列工具

singee發表於2020-01-05

使用 MacOS 做開發的朋友都知道,我們一般會使用 Homebrew 做軟體包管理,經常會用到 brew install [soft] 來安裝各種各樣的命令列軟體。今天通過一個百科查詢的命令列工具(tellme)示例,我們來學習一下如何使用 Go 語言開發自己的命令列軟體。

我們需要用到 cobra 這個 Go 模組來做命令列工具開發,這個開源庫其實是對 Go 官方庫 flag 的一個封裝,可以簡化獲取引數的操作。

建立命令列專案

  • 開啟 Go Module
export GO111MODULE=on
  • 安裝 cobra 工具
go get -u github.com/spf13/cobra/cobra
  • 建立命令列專案
# 建立專案目錄
mkdir -p /data/idoubi/tellme && cd /data/idoubi/tellme

# 定義模組
go mod init github.com/idoubi/tellme

# 初始化命令列專案
cobra init --pkg-name github.com/idoubi/tellme
  • 檢測執行
go run main.go -h

執行完上述操作後,如果控制檯輸出了幫助資訊,證明我們的命令列專案建立成功了。

新建子命令

  • 新建子命令
cobra add baike
  • 編寫業務邏輯

在生成的子命令檔案 /data/idoubi/tellme/cmd/baike.go 中編寫子命令需要實現的業務邏輯。

package cmd

import (
    "fmt"
    "os"
    "os/exec"
    "runtime"

    "github.com/spf13/cobra"
)

var (
    platform string
)

var openCmds = map[string]string{
    "windows": "cmd /c start",
    "darwin":  "open",
    "linux":   "xdg-open",
}

var baikeCmd = &cobra.Command{
    Use:     "baike",
    Aliases: []string{"bk", "wk", "wiki"},
    Short:   "find things in baike site",
    Args:    cobra.ExactArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
        err := findInBaike(args[0], platform)
        if err != nil {
            fmt.Println(err)
            os.Exit(1)
        }
    },
}

func init() {
    rootCmd.AddCommand(baikeCmd)
    baikeCmd.Flags().StringVarP(&platform, "platform", "p", "baidu", "platform to find things")
}

// 百科查詢
func findInBaike(keyword, platform string) error {
    var link string
    // 百度百科搜尋
    if platform == "baidu" || platform == "bd" {
        link = fmt.Sprintf("https://baike.baidu.com/item/%s", keyword)
    }
    // 互動百科搜尋
    if platform == "hudong" || platform == "baike" || platform == "hd" {
        link = fmt.Sprintf("http://www.baike.com/wiki/%s", keyword)
    }
    // 維基百科搜尋
    if platform == "wikipedia" || platform == "wiki" || platform == "wp" {
        link = fmt.Sprintf("https://zh.wikipedia.org/wiki/%s", keyword)
    }
    if link == "" {
        return fmt.Errorf("invalid platform")
    }
    goos := runtime.GOOS
    opencmd := "open"
    opencmd, ok := openCmds[goos]
    if !ok {
        return fmt.Errorf("can not open link in %s", goos)
    }
    if err := exec.Command(opencmd, link).Start(); err != nil {
        return err
    }

    return nil
}

命令測試

  • 專案中執行

在命令列專案目錄下,通過 go run 可以直接執行,檢視輸出結果。

# 在百度百科檢視資訊
go run main.go baike 周杰倫

# 在維基百科檢視資訊
go run main.go bk -p wp 周杰倫

上述的 baike 是我們建立的子命令,bk 是子命令別名,-p 是子命令標識,用於指定百科平臺。周杰倫 是接收的引數。

  • 編譯執行

在命令列專案目錄下,通過 go build 可以將專案編譯成一個二進位制檔案,通過 ./tellme 可以直接執行二進位制檔案檢視輸出。

# 編譯
go build -o tellme

# 執行
./tellme -h
  • 交叉編譯

除了在 MacOS 中使用外,我們還希望能在 linux 和 windows 系統中使用我們的命令列工具。這種情況下我們需要用到交叉編譯。

# 下載交叉編譯工具
go get -u github.com/mitchellh/gox

# 編譯成指定平臺的可執行檔案
gox -osarch "windows/amd64 linux/amd64 darwin/amd64"
  • 全域性執行

編譯完成後,我們可以建立一個軟連線,讓命令列工具可以在任何路徑下全域性執行。

# 建立軟連線
ln -s /data/idoubi/tellme/tellme_darwin_amd64 /usr/local/bin/tm

# 全域性執行
tm -h

上傳到 Github

經過上述的幾個步驟,我們已經完成了一個簡單的命令列工具的編寫與測試工作,接下來需要把軟體釋出出去讓所有人使用。

# 推送程式碼到github
cd /data/idoubi/tellme
go init
git add .
git commit -m "a cli tool used in macos"
git push origin master

# 釋出一個版本
git tag -a v0.1.0 -m "first version"
git push origin --tags

上傳到 Github 完成後,我們可以在專案的 release 頁面看到這個專案的版本資訊和原始碼下載檔案 github.com/idoubi/tell… ,我們可以編輯釋出資訊,上傳交叉編譯後得到的各個平臺的二進位制檔案,方便不同平臺的使用者在這裡直接下載二進位制檔案來使用我們的軟體。

建立 Homebrew 軟體

對於 MacOS 使用者,一般都是使用 Homebrew 來安裝和管理各種軟體,我們希望把自己開發的命令列軟體釋出到 Homebrew,讓使用者可以方便的使用 brew install tellme 來安裝。

  • 建立 Homebrew 軟體

我們可以在 Github 上覆制軟體原始碼包下載地址,在 MacOS 通過 brew create [source] 建立 Homebrew 軟體包。

brew create https://github.com/idoubi/tellme/archive/v0.1.0.tar.gz

執行上述命令完成後,會在 /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/ 目錄生成一個 tellme.rb 檔案,即我們的 Homebrew 軟體定義檔案,在此檔案中定義了我們的軟體在 MacOS 中要怎麼安裝。

  • 編輯軟體定義檔案

因為我們這個命令列軟體是用 Go 語言編寫的,在 Homebrew 軟體定義檔案中,我們可以指定軟體的安裝依賴於 go:build,並且定義好 install 方式。

class Tellme < Formula
  desc "a cli tool to get information."
  homepage "https://github.com/idoubi/tellme"
  url "https://github.com/idoubi/tellme/archive/v0.1.0.tar.gz"
  sha256 "b0c14c0e9f02e065917262a7c0d16e205097cc4d10c01e03ad93b4cd737cf81d"

  depends_on "go" => :build

  def install
    system "go", "build", "-o", bin/"tellme"
  end

  test do
    system "false"
  end
end
  • 通過可執行檔案建立 Homebrew 軟體

上面看到的是通過 Go 原始碼編譯的方式定義 Homebrew 軟體的安裝方式,我們還可以通過下載可執行二進位制的方式定義 Homebrew 軟體包的安裝,比如通過交叉編譯生成可執行檔案。

基於可執行檔案建立 Homebrew 軟體包:

brew create https://github.com/idoubi/tellme/releases/download/v0.1.0/tellme_darwin_amd64.tar.gz

編輯 Homebrew 軟體包的定義檔案 tellme.rb:

class Tellme < Formula
  desc "a cli tool to get information"
  homepage ""
  url "https://github.com/idoubi/tellme/releases/download/v0.1.0/tellme_darwin_amd64.tar.gz"
  sha256 "164787b02050faef0d5776ca86d27d15b26fe28493f95ba2e705ba2e30026c94"

  def install
    bin.install "tellme_darwin_amd64" => "tellme"
  end

  test do
    system "false"
  end
end
  • 安裝 Homebrew 軟體

建立完 Homebrew 軟體後,我們通過 brew install tellme 就可以基於本地生成的 /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/tellme.rb 檔案來安裝我們的命令列軟體了。

如果安裝報錯了,可以通過 brew edit tellme 繼續編輯 Homebrew 軟體定義檔案。

釋出 Homebrew 軟體

經過上面的步驟,我們建立了一個在 MacOS 通過 Homebrew 安裝的軟體,接下來我們需要把這個軟體釋出出去,讓使用者能夠通過簡單的 brew 命令直接安裝使用。

  • 釋出到 Github 倉庫
# 建立軟體倉庫
mkdir -p /data/idoubi/homebrew-tools && cd /data/idoubi/homebrew-tools

# 複製軟體定義檔案到倉庫目錄
cp /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/tellme.rb /data/idoubi/homebrew-tools/

# 推送到 Github 倉庫
git init
git remote add origin https://github.com/idoubi/homebrew-tools.git
git add .
git commit -m "a homebrew soft named tellme"
git push origin master
  • 安裝軟體

軟體定義檔案推送到 Github 倉庫後,可以刪除本地的 /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/tellme.rb 檔案。

任何人可以通過下面兩行命令在自己的 MacOS 系統中使用我們開發的命令列軟體。

# 連線軟體倉庫
brew tap idoubi/tools
# 從軟體倉庫安裝軟體
brew install tellme

總結

前面的內容簡單介紹瞭如何使用 Go 語言來建立一個在 MacOS 使用的命令列軟體,需要開發者熟悉 MacOS 中 Homebrew 軟體包管理工具的使用以及 Go 語言。後面我們可以展開更多的想象,在我們的命令列工具中新增查天氣、搜歌詞、翻譯、時間型別轉換等各種特性功能。

  • 原始碼

命令列軟體原始碼:tellme

Homebrew 倉庫:homebrew-tools

參考

轉載來源

本文章釋出於 https://idoubi.cc/posts/create-a-cli-tool-... ,在轉載過程中僅對於格式有一定的修改

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章