在 Golang 的二进制文件中嵌入版本信息 #golang

在之前的文章中,我们使用了 Golang 和 Line Notify 来创建了一个检查 API 证书过期日期的功能。但是这次我们将添加版本号到已创建的二进制文件中。

简要描述

我打算写下粗略调查的结果和想做的事情。

    • Golang でビルドしたバイナリはデフォルトでバージョンが埋め込まれるわけではない

「main.go」などに変数を用意してビルド時などに埋め込む必要がある
ビルド時のオプションで変数に値を設定可能
「flag」パッケージを利用して、オプションの処理を実装する必要がある

バージョンはバージョン番号とリビジョンに分けて管理

バージョンは git の最新のタグを利用(v1.0.0 なイメージ)
リビジョンは git の最新のタグのショートリビジョンを利用(e5a4228なイメージ)

源代码

package main

import (
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "strings"
    "time"
)

var version = "unknown"
var revision = "unknown"

func main() {
    var endpoint = flag.String("endpoint", "", "check target Endpoint URL")
    var lineToken = flag.String("token", "", "LINE notify token")
    var showVersion = false
    flag.BoolVar(&showVersion, "v", false, "show application version")
    flag.BoolVar(&showVersion, "version", false, "show application version")
    flag.Parse()

    if showVersion {
        fmt.Println("version(", version+"."+revision, ")")
    } else {
        var apiResult = getAPI(*endpoint)
        var result = postLINE(*lineToken, apiResult)

        fmt.Printf("LINE Post result [%t]\n", result)
    }
}

func getAPI(endpoint string) string {
    if endpoint == "" {
        log.Println("not endpoint")
        return "not endpoint"
    }

    var result = ""
    resp, err := http.Get(endpoint)
    if err != nil {
        result = fmt.Sprintf("NG\n%s", err)
    } else {
        defer resp.Body.Close()
        expire := "-"
        if len(resp.TLS.PeerCertificates) > 0 {
            expireUTCTime := resp.TLS.PeerCertificates[0].NotAfter
            expireJSTTime := expireUTCTime.In(time.FixedZone("Asia/Tokyo", 9*60*60))
            expire = expireJSTTime.Format("06/01/02 15:04")
        }
        result = fmt.Sprintf("OK (expire=%s)\n%s", expire, endpoint)
    }

    return result
}

func postLINE(token string, message string) bool {
    if token == "" {
        log.Println("not token")
        return false
    } else if message == "" {
        log.Println("not text")
        return false
    }

    data := url.Values{"message": {message}}
    r, _ := http.NewRequest("POST", "https://notify-api.line.me/api/notify", strings.NewReader(data.Encode()))
    r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
    resp, err := http.DefaultClient.Do(r)
    if err != nil {
        log.Println(err)
        return false
    }
    defer resp.Body.Close()
    _, err = ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Println(err)
        return false
    }

    return true
}

通过git命令获取最新标签的短版本和哈希值。

获取最新的标签

$ git describe --tags --abbrev=0
v1.0.0

获取哈希值的简短版本

$ git rev-parse --short HEAD
e5a4228

在构建时嵌入版本和修订号

通过在构建go文件时使用ldflags选项,可以为go文件中定义的变量设置值。

建筑

$ GOOS=darwin GOARCH=amd64 go build -ldflags "-X main.version=$(git describe --tags --abbrev=0) -X main.revision=$(git rev-parse --short HEAD)"

版本检查

$ ./apichecker -v
version( v1.0.0.e5a4228 )

总结

如果长期使用命令行工具,就会不知道正在使用的是哪个版本的二进制文件,所以我觉得应该养成一个必须嵌入版本的习惯。
不过,由于经常使用,所以我认为将其作为标准功能实现会更方便。

附录

    ソースコード
bannerAds