Автоматическое создание версий приложений

Можно ли автоматически увеличивать номер младшей версии каждый раз, когда скомпилировано приложение Go?

Я хотел бы установить номер версии внутри моей программы с секцией автоинкремента:

$ myapp -version
MyApp version 0.5.132

Будучи 0.5 установленным номером версии и 132 значением, которое автоматически увеличивается при каждом компиляции двоичного файла.

Возможно ли это в Go?

Ответ 1

В компоновщике Go (ссылка на инструмент go) есть возможность установить значение неинициализированной строковой переменной:

-X importpath.name=value
  Set the value of the string variable in importpath named name to

значение. Обратите внимание, что до Go 1.5 эта опция принимала два отдельных аргумента. Теперь требуется один аргумент, разделенный на первый знак =.

Как часть вашего процесса сборки, вы можете установить строковую переменную версии, используя это. Вы можете передать это через инструмент go, используя -ldflags. Например, дан следующий исходный файл:

package main

import "fmt"

var xyz string

func main() {
    fmt.Println(xyz)
}

Затем:

$ go run -ldflags "-X main.xyz=abc" main.go
abc

Чтобы установить main.minversion на дату и время сборки при сборке:

go build -ldflags "-X main.minversion='date -u +.%Y%m%d.%H%M%S'" service.go

Если вы скомпилируете без инициализации main.minversion таким образом, он будет содержать пустую строку.

Ответ 2

У меня возникли проблемы с использованием параметра -ldflags при создании моего смешанного проекта приложения и библиотеки в командной строке, поэтому я решил использовать целевой файл Makefile для создания исходного файла Go, содержащего мою версию приложения и дату сборки:

BUILD_DATE := `date +%Y-%m-%d\ %H:%M`
VERSIONFILE := cmd/myapp/version.go

gensrc:
    rm -f $(VERSIONFILE)
    @echo "package main" > $(VERSIONFILE)
    @echo "const (" >> $(VERSIONFILE)
    @echo "  VERSION = \"1.0\"" >> $(VERSIONFILE)
    @echo "  BUILD_DATE = \"$(BUILD_DATE)\"" >> $(VERSIONFILE)
    @echo ")" >> $(VERSIONFILE)

В моем методе init() я делаю это:

flag.Usage = func() {
    fmt.Fprintf(os.Stderr, "%s version %s\n", os.Args[0], VERSION)
    fmt.Fprintf(os.Stderr, "built %s\n", BUILD_DATE)
    fmt.Fprintln(os.Stderr, "usage:")
    flag.PrintDefaults()
}

Если бы вы хотели получить атомарно увеличивающийся номер сборки вместо даты сборки, вам, вероятно, понадобится создать локальный файл, содержащий последний номер сборки. Ваш Makefile будет читать содержимое файла в переменной, увеличивать его, вставлять в файл version.go вместо даты и записывать новый номер сборки обратно в файл.

Ответ 3

Кроме того, я хотел бы разместить небольшой пример того, как использовать git и makefile:

--- Makefile ----

# This how we want to name the binary output
BINARY=gomake

# These are the values we want to pass for VERSION and BUILD
# git tag 1.0.1
# git commit -am "One more change after the tags"
VERSION=`git describe --tags`
BUILD=`date +%FT%T%z`

# Setup the -ldflags option for go build here, interpolate the variable values
LDFLAGS_f1=-ldflags "-w -s -X main.Version=${VERSION} -X main.Build=${BUILD} -X main.Entry=f1"
LDFLAGS_f2=-ldflags "-w -s -X main.Version=${VERSION} -X main.Build=${BUILD} -X main.Entry=f2"

# Builds the project
build:
    go build ${LDFLAGS_f1} -o ${BINARY}_f1
    go build ${LDFLAGS_f2} -o ${BINARY}_f2

# Installs our project: copies binaries
install:
    go install ${LDFLAGS_f1}

# Cleans our project: deletes binaries
clean:
    if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi

.PHONY: clean install

Файл make создаст два исполняемых файла. Один из них выполняет функцию один, другой будет выполнять функцию 2 в качестве основной записи:

package main

import (
        "fmt"
)

var (

        Version string
        Build   string
        Entry   string

        funcs = map[string]func() {
                "f1":functionOne,"f2":functionTwo,
        }

)

func functionOne() {
    fmt.Println("This is function one")
}

func functionTwo() {
    fmt.Println("This is function two")
}

func main() {

        fmt.Println("Version: ", Version)
        fmt.Println("Build Time: ", Build)

    funcs[Entry]()

}

Затем просто запустите:

make

Вы получите:

[email protected]:~/projects/go/gomake/3/gomake$ ls -al
total 2020
drwxrwxr-x 3 mab mab    4096 Sep  7 22:41 .
drwxrwxr-x 3 mab mab    4096 Aug 16 10:00 ..
drwxrwxr-x 8 mab mab    4096 Aug 17 16:40 .git
-rwxrwxr-x 1 mab mab 1023488 Sep  7 22:41 gomake_f1
-rwxrwxr-x 1 mab mab 1023488 Sep  7 22:41 gomake_f2
-rw-rw-r-- 1 mab mab     399 Aug 16 10:21 main.go
-rw-rw-r-- 1 mab mab     810 Sep  7 22:41 Makefile
[email protected]:~/projects/go/gomake/3/gomake$ ./gomake_f1
Version:  1.0.1-1-gfb51187
Build Time:  2016-09-07T22:41:38+0200
This is function one
[email protected]:~/projects/go/gomake/3/gomake$ ./gomake_f2
Version:  1.0.1-1-gfb51187
Build Time:  2016-09-07T22:41:39+0200
This is function two

Ответ 4

Используйте ldflags для установки переменных в пакете main:

С файлом main.go:

package main

import "fmt"

var (
    version string
    build   string
)

func main() {
    fmt.Println("version=", version)
    fmt.Println("build=", build)
}

Затем запустите:

go run \
  -ldflags "-X main.version=1.0.0 -X main.build=12082019" \ 
  main.go

Сложение:

go build -o mybinary \
  -ldflags "-X main.version=1.0.0 -X 'main.build=$(date)'" \ 
  main.go

Используйте ldflags, чтобы установить переменную в пакете non- main:

С файлом config.go:

package config

import "fmt"

var (
    Version string
)

func LogVersion() {
    fmt.Println("version=", Version)
}

Вам также понадобится файл main.go:

package main

import (
    "fmt"
    "github.com/user/repo/config"
}

func main() {
    config.LogVersion()
}

Сначала создайте свой двоичный файл:

go build -o mybinary main.go 

Найдите полный путь к имени переменной, которую вы хотите установить:

go tool nm <path_to_binary> | grep Version

Запустите и соберите двоичный файл снова, но с помощью ldflags:

go run \
  -ldflags "-X github.com/user/repo/config.Version=1.0.0" \
  main.go --version       


go build -o mybinary \
  -ldflags "-X github.com/user/repo/config.Version=1.0.0" \
  main.go     

Вдохновленный https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable


Также, если вы используете goreleaser, прочитайте это https://goreleaser.com/#using-the-main-version:

Мудрый GoReleaser по умолчанию устанавливает три флага ld:

main.version: текущий тег Git
main.commit: текущий git commit SHA
main.date: дата в соответствии с RFC3339


Если вы хотите увидеть это в действии: https://github.com/hoto/fuzzy-repo-finder/blob/master/pkg/config/config.go

Ответ 5

использовать multi -ldflags:

$ go build -ldflags "-X name1=value1 -X name2=value2" -o path/to/output

Ответ 6

В ОС Windows с учетом программы ниже

package main

import "fmt"

var (
    version string
    date    string
)

func main() {
    fmt.Printf("version=%s, date=%s", version, date)
}

Вы можете создать с помощью

go build -ldflags "-X main.version=0.0.1 -X main.date=%date:~10,4%-%date:~4,2%-%date:~7,2%T%time:~0,2%:%time:~3,2%:%time:~6,2%"

Формат даты предполагает, что ваша среда echo %date% равна Fri 07/22/2016 и echo %time% равна 16:21:52.88

Тогда вывод будет: version=0.0.1, date=2016-07-22T16:21:52