Wersja automatycznego budowania aplikacji

Czy możliwe jest automatyczne zwiększanie podrzędnego numeru wersji za każdym razem, gdy aplikacja Go jest kompilowana?

Chciałbym ustawić numer wersji w moim programie, z sekcją autoincrementing:

$ myapp -version
MyApp version 0.5.132

Jest 0.5 numerem wersji, który ustawiłem, a 132 wartością, która zwiększa się automatycznie za każdym razem, gdy plik binarny jest kompilowany.

Czy to możliwe w Go?
 203
go
Author: Flimzy, 2012-07-06

7 answers

Go linker (go tool link) ma możliwość ustawienia wartości niezainicjalizowanej zmiennej łańcuchowej:

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

Wartość. Zauważ, że przed Go 1.5 ta opcja przyjmowała dwa oddzielne argumenty. Teraz wymaga podziału jednego argumentu na pierwszy znak=.

Jako część procesu budowania, możesz ustawić zmienną ciągu wersji używając tego. Możesz to przekazać za pomocą narzędzia go za pomocą narzędzia -ldflags. Na przykład, biorąc pod uwagę następujące źródło plik:

package main

import "fmt"

var xyz string

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

Potem:

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

Aby ustawić main.minversion na datę i godzinę budowy:

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

Jeśli skompilujesz bez inicjalizacji main.minversion w ten sposób, będzie on zawierał pusty łańcuch znaków.

 350
Author: axw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-28 20:10:03

Dodatkowo chciałbym zamieścić mały przykład jak używać git i 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

Plik make utworzy dwa pliki wykonywalne. Jeden wykonuje funkcję jeden, drugi przyjmuje funkcję drugą jako wejście główne:

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]()

}

Następnie po prostu uruchom:

make

Otrzymasz:

mab@h2470988:~/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
mab@h2470988:~/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
mab@h2470988:~/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
 28
Author: Maciej A. Bednarz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-07 20:48:42

Miałem problemy z użyciem parametru -ldflags podczas budowania mieszanej aplikacji wiersza poleceń i projektu biblioteki, więc skończyło się na użyciu pliku docelowego Makefile do wygenerowania pliku źródłowego go zawierającego wersję mojej aplikacji i datę kompilacji:

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)

W mojej metodzie init() robię to:

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()
}

Jeśli jednak chcesz zwiększyć liczbę kompilacji atomicznie zamiast daty kompilacji, prawdopodobnie będziesz musiał utworzyć plik lokalny, który zawierał ostatni numer kompilacji. Twój plik Makefile odczytałby plik zawartość do zmiennej, zwiększ ją, Wstaw ją do pliku version.go zamiast daty i zapisz nowy numer kompilacji z powrotem do pliku.

 26
Author: pegli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-28 20:26:32

Użyj ldflags aby ustawić zmienne w main pakiecie:

Z plikiem main.go:

package main

import "fmt"

var (
    version string
    build   string
)

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

Następnie uruchom:

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

Budowa:

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

Użyj ldflags aby ustawić zmienną w pakiecie non-main:

Z plikiem config.go:

package config

import "fmt"

var (
    Version string
)

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

Potrzebny będzie również plik main.go:

package main

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

func main() {
    config.LogVersion()
}

Najpierw Zbuduj swój plik binarny:

go build -o mybinary main.go 

Znajdź pełną ścieżkę nazwy zmiennej, którą chcesz ustawić:

go tool nm <path_to_binary> | grep Version

Uruchom i zbuduj plik binarny ponownie, ale z 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     

Zainspirowany https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable


Również jeśli używasz goreleaser to przeczytaj to https://goreleaser.com/environment/#using-the-mainversion :

Default wise GoReleaser ustawia trzy ldflags:

Main.version: Current Git tag
main.commit: bieżący git commit SHA
main.Data: Data według RFC3339


Jeśli chcesz zobaczyć to w akcji: https://github.com/hoto/fuzzy-repo-finder/blob/master/pkg/config/config.go

 26
Author: Andrzej Rehmann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-13 09:04:31

Aby użyć multi -ldflags:

$ go build -ldflags "-X name1=value1 -X name2=value2" -o path/to/output
 12
Author: Kimia Zhu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-18 02:29:38

W systemie operacyjnym Windows podany poniżej program

package main

import "fmt"

var (
    version string
    date    string
)

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

Możesz budować używając

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%"

Format daty zakłada, że Twoje środowisko echo %date% to Fri 07/22/2016, a echo %time% to 16:21:52.88

Następnie wyjście będzie: version=0.0.1, date=2016-07-22T16:21:52

 12
Author: Ostati,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-22 20:28:31

Bazując na innych odpowiedziach, w ostatnich wersjach go można również napisać buildid do sekcji ELF - choć nie jest to tak łatwe do odczytania z poziomu programu.

Piszę tę samą wartość do obu, używając czegoś takiego jak:

BuildInfo:= "BUILD #x, branch @ rev built yymmdd hh:mm:ss"
// note the nested quotes "''" required to get a string with 
// spaces passed correctly to the underlying tool
ldFl := fmt.Sprintf("-X 'main.buildId=%s' -s -w '-buildid=%s'", BuildInfo, BuildInfo)
args := []string{
    "build",
    "-ldflags", ldFl,
    "-trimpath",
    "-gcflags", "-dwarf=false",
}
buildpath:="path/to/my/cmd"
args=append(args,buildpath)
buildCmd:=exec.Command("go", args...)

Używam tego z mage, narzędziem do budowania napisanym w go. Nie potrzebujesz dodatkowych FLAG powyżej, ale wybrałem te, aby usunąć jak najwięcej informacji z plików binarnych wydania.

(off topic: Mage wymaga nieco więcej praca z góry niż coś w rodzaju Make, ale jest o wiele łatwiejsze do rozszerzenia/utrzymania niż system budowania oparty na make-plus nie musisz przełączać mentalnych biegów między go a inną składnią.)

 0
Author: Mark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-15 00:13:23