Automatyczne tworzenie wersji aplikacji

193

Czy możliwe jest automatyczne zwiększenie mniejszego numeru wersji przy każdej kompilacji aplikacji Go?

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

$ myapp -version
MyApp version 0.5.132

Będąc 0,5, ustawiłem numer wersji I, a 132 wartość, która zwiększa się automatycznie przy każdej kompilacji pliku binarnego.

Czy jest to możliwe w Go?

Sebastián Grignoli
źródło

Odpowiedzi:

337

Linker Go ( link do narzędzia go ) ma opcję ustawienia wartości niezainicjowanej zmiennej łańcuchowej:

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

wartość. Zauważ, że przed wersją Go 1.5 ta opcja miała dwa osobne argumenty. Teraz zajmuje jeden argument podzielony na pierwszy znak =.

W ramach procesu kompilacji można przy użyciu tej zmiennej ustawić ciąg znaków wersji. Możesz to przekazać za pomocą gonarzędzia -ldflags. Na przykład biorąc pod uwagę następujący plik źródłowy:

package main

import "fmt"

var xyz string

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

Następnie:

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

Aby ustawić main.minversiondatę i godzinę kompilacji podczas budowania:

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

Jeśli kompilujesz bez inicjowania main.minversionw ten sposób, będzie zawierać pusty ciąg.

axw
źródło
4
Czy ta wartość zostanie zapisana w pliku binarnym, jeśli użyję go bouildzamiast niej go run?
Sebastián Grignoli,
6
go build -ldflags "-X main.minversion `date -u +.%Y%m%d%.H%M%S`" service.go
Sebastián Grignoli,
4
goxc robi to za Ciebie :) domyślnie kompiluje się z -ldflags „-Xmain.VERSION xxx -Xmain.BUILD_DATE CurrentDateInISO8601”, ale możesz skonfigurować te nazwy zmiennych, jeśli chcesz. Zobacz github.com/laher/goxc ... (zrzeczenie się: napisałem goxc)
laher
7
przykład roboczy z nową składnią 1.5 do dodawania zmiennej go build -ldflags "-X 'main.buildtime=$(date -u '+%Y-%m-%d %H:%M:%S')'"
buildtime
26
zauważ, że wymagana jest pełna nazwa pakietu. go build -ldflags "-X pkg.version=123"nie będzie działać podczas go build -ldflags "-X path/to/pkg.version=123"pracy zgodnie z oczekiwaniami. mam nadzieję, że to pomoże.
csyangchen
27

Dodatkowo chciałbym zamieścić mały przykład użycia 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ę pierwszą, drugi przyjmuje funkcję drugą jako wpis główny:

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

Dostaniesz:

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
Maciej A. Bednarz
źródło
5
Lub prościej: po prostu ustaw dwa główne w dwóch różnych katalogach. To rozwiązanie wydaje się być poważnie przepracowane.
dolmen
26

Miałem problem z użyciem tego -ldflagsparametru podczas budowania mieszanej aplikacji wiersza polecenia i projektu biblioteki, więc skończyłem na celu 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 init()metodzie 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 chciałbyś zwiększyć liczbę atomów zamiast daty kompilacji, prawdopodobnie będziesz musiał utworzyć plik lokalny zawierający ostatni numer kompilacji. Twój Makefile odczyta zawartość pliku do zmiennej, zwiększy ją, wstawi do version.gopliku zamiast daty i zapisze nowy numer kompilacji z powrotem do pliku.

pegli
źródło
2
Niezłe rozwiązanie. Mimo to myślę, że znalazłem przyczynę problemów z -ldflags. Jeśli plik zawierający zmienną aktualizowaną przez -X nie zostanie zmieniony, kompilacja nie zostanie uruchomiona i masz starą wersję w pliku binarnym. Moim rozwiązaniem było dotknięcie małego pliku zawierającego tylko zmienną resetowaną przez -ldflags „-X ...”
Wojciech Kaczmarek
20

Służy ldflagsdo ustawiania zmiennych w mainpakiecie:

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 uruchomić:

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, ldflagsaby ustawić zmienną w non-mainpakiecie:

Z plikiem config.go:

package config

import "fmt"

var (
    Version string
)

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

Będziesz także potrzebował pliku 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 przez https://github.com/golang/go/wiki/GcToolchainTricks#inclusion-build-information-in-the-executable


Również jeśli używasz, goreleaserprzeczytaj tę https://goreleaser.com/#using-the-main-version :

Domyślnie mądry GoReleaser ustawia trzy flagi ldflag:

main.version: bieżący tag Git
main.commit: bieżący zatwierdzenie SHA
main.date: Data zgodnie z RFC3339


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

Andrzej Rehmann
źródło
12

używać wielu -ldflags:

$ go build -ldflags "-X name1=value1 -X name2=value2" -o path/to/output
Kimia Zhu
źródło
12

W systemie operacyjnym Windows, biorąc pod uwagę poniższy program

package main

import "fmt"

var (
    version string
    date    string
)

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

Możesz budować za pomocą

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%jest Fri 07/22/2016i echo %time%jest16:21:52.88

Następnie dane wyjściowe będą: version=0.0.1, date=2016-07-22T16:21:52

Ostati
źródło