Автоматическое создание версий приложений
Можно ли автоматически увеличивать номер младшей версии каждый раз, когда скомпилировано приложение 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