Automatische Versionierung der Anwendung

193

Ist es möglich, eine kleinere Versionsnummer jedes Mal automatisch zu erhöhen, wenn eine Go-App kompiliert wird?

Ich möchte in meinem Programm eine Versionsnummer mit einem Abschnitt zur automatischen Inkrementierung festlegen:

$ myapp -version
MyApp version 0.5.132

Als 0,5 ist die von mir festgelegte Versionsnummer und 132 ein Wert, der sich bei jeder Kompilierung der Binärdatei automatisch erhöht.

Ist das in Go möglich?

Sebastián Grignoli
quelle

Antworten:

337

Der Go-Linker ( Go-Tool-Link ) bietet eine Option zum Festlegen des Werts einer nicht initialisierten Zeichenfolgenvariablen:

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

Wert. Beachten Sie, dass diese Option vor Go 1.5 zwei separate Argumente hatte. Jetzt wird ein Argument auf das erste = Zeichen aufgeteilt.

Als Teil Ihres Erstellungsprozesses können Sie damit eine Versionszeichenfolgenvariable festlegen. Sie können dies mit dem goTool durchlaufen -ldflags. Zum Beispiel bei folgender Quelldatei:

package main

import "fmt"

var xyz string

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

Dann:

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

Um main.minversiondas Erstellungsdatum und die Erstellungszeit beim Erstellen festzulegen:

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

Wenn Sie kompilieren, ohne main.minversionauf diese Weise zu initialisieren , enthält es die leere Zeichenfolge.

axw
quelle
4
Wird dieser Wert in der Binärdatei gespeichert, wenn ich ihn go bouildanstelle von verwende 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 erledigt dies für Sie :) Standardmäßig wird es mit -ldflags "-Xmain.VERSION xxx -Xmain.BUILD_DATE CurrentDateInISO8601" kompiliert, aber Sie können diese Variablennamen konfigurieren, wenn Sie möchten. Siehe github.com/laher/goxc ... (Haftungsausschluss: Ich schrieb goxc)
laher
7
Arbeitsbeispiel mit neuer 1.5-Syntax zum Hinzufügen der Buildtime-Variablengo build -ldflags "-X 'main.buildtime=$(date -u '+%Y-%m-%d %H:%M:%S')'"
xorpaul
26
Beachten Sie, dass der vollständige Paketname erforderlich ist. go build -ldflags "-X pkg.version=123"funktioniert nicht während der go build -ldflags "-X path/to/pkg.version=123"Arbeit wie erwartet. ich hoffe es hilft.
Csyangchen
27

Zusätzlich möchte ich ein kleines Beispiel für die Verwendung von Git und einem Makefile veröffentlichen:

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

Die make-Datei erstellt zwei ausführbare Dateien. Einer führt Funktion eins aus, der andere übernimmt Funktion zwei als Haupteintrag:

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

}

Dann laufen Sie einfach:

make

Sie erhalten:

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
quelle
5
Oder einfacher: Machen Sie einfach zwei Hauptverzeichnisse in zwei verschiedenen Verzeichnissen. Diese Lösung scheint ernsthaft überarbeitet zu sein.
Dolmen
26

-ldflagsBeim Erstellen meiner gemischten Befehlszeilen-App und meines Bibliotheksprojekts hatte ich Probleme mit der Verwendung des Parameters. Daher habe ich ein Makefile-Ziel verwendet, um eine Go-Quelldatei zu generieren, die die Version meiner App und das Erstellungsdatum enthält:

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)

In meiner init()Methode mache ich das:

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

Wenn Sie jedoch eine atomar ansteigende Build-Nummer anstelle eines Build-Datums wünschen, müssen Sie wahrscheinlich eine lokale Datei erstellen, die die letzte Build-Nummer enthält. Ihr Makefile liest den Dateiinhalt in eine Variable, erhöht ihn, fügt ihn version.goanstelle des Datums in die Datei ein und schreibt die neue Build-Nummer zurück in die Datei.

pegli
quelle
2
Schöne Lösung. Trotzdem denke ich, dass ich den Grund für die Probleme mit -ldflags gefunden habe. Wenn die Datei mit der von -X aktualisierten Variablen nicht berührt wird, wird die Kompilierung nicht ausgelöst und Sie haben eine alte Version in der Binärdatei. Meine Lösung bestand darin, eine kleine Datei zu berühren, die nur Variablen enthielt, die über -ldflags "-X ..." zurückgesetzt wurden
Wojciech Kaczmarek
20

Verwenden Sie ldflagsdiese Option , um Variablen im mainPaket festzulegen:

Mit Datei main.go:

package main

import "fmt"

var (
    version string
    build   string
)

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

Dann renne:

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

Bauen:

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

Verwenden Sie ldflagsdiese Option , um eine Variable in einem non-mainPaket festzulegen:

Mit Datei config.go:

package config

import "fmt"

var (
    Version string
)

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

Sie benötigen außerdem eine Datei main.go:

package main

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

func main() {
    config.LogVersion()
}

Erstellen Sie zuerst Ihre Binärdatei:

go build -o mybinary main.go 

Suchen Sie den vollständigen Pfad des Variablennamens, den Sie festlegen möchten:

go tool nm <path_to_binary> | grep Version

Führen Sie die Binärdatei aus und erstellen Sie sie erneut, jedoch mit 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     

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


Auch wenn Sie verwenden, goreleaserlesen Sie diese https://goreleaser.com/#using-the-main-version :

Standardmäßig setzt GoReleaser drei ldflags:

main.version: Aktuelles Git-Tag
main.commit: Aktuelles Git-Commit SHA
main.date: Datum gemäß RFC3339


Wenn Sie dies in Aktion sehen möchten: https://github.com/hoto/fuzzy-repo-finder/blob/master/pkg/config/config.go

Andrzej Rehmann
quelle
12

Multi verwenden -ldflags:

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

Unter Windows das unten stehende Programm

package main

import "fmt"

var (
    version string
    date    string
)

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

Sie können mit bauen

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

Das Datumsformat setzt voraus, dass Ihre Umgebung echo %date%ist Fri 07/22/2016und echo %time%ist16:21:52.88

Dann wird die Ausgabe sein: version=0.0.1, date=2016-07-22T16:21:52

Ostati
quelle