From 2506a340d9f03a7c0290b4673bdb9f95a358e9cc Mon Sep 17 00:00:00 2001 From: jichangjun Date: Tue, 6 Dec 2022 19:41:40 +0800 Subject: [PATCH] init version project --- .gitignore | 7 +++ README.md | 18 +++++++ doc.go | 5 ++ examples/main.go | 11 +++++ go.mod | 3 ++ version.go | 119 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 163 insertions(+) create mode 100644 .gitignore create mode 100644 doc.go create mode 100644 examples/main.go create mode 100644 go.mod create mode 100644 version.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbcffce --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# Go Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# example binary +examples \ No newline at end of file diff --git a/README.md b/README.md index 4c7c31e..c2296e5 100644 --- a/README.md +++ b/README.md @@ -1 +1,19 @@ # version +# version +package version defines the utility information for versioning binary + +## Usage + +Import this package in your application: + +```go +import _ "github.com/qiniu/version" +``` + +Build it with: + +```shell +go build -ldflags "-X 'github.com/qiniu/version.BuildDate=$(date)'" . +``` + +Then run, it will output like: \ No newline at end of file diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..a188a01 --- /dev/null +++ b/doc.go @@ -0,0 +1,5 @@ +// package version defines the information for versioning binary +// usage: +// +// import _ "github.com/CarlJi/version" +package version diff --git a/examples/main.go b/examples/main.go new file mode 100644 index 0000000..6b3d94b --- /dev/null +++ b/examples/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "fmt" + + _ "github.com/qiniu/version" +) + +func main() { + fmt.Println("Hello World!") +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9512f96 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/qiniu/version + +go 1.19 diff --git a/version.go b/version.go new file mode 100644 index 0000000..44b7eef --- /dev/null +++ b/version.go @@ -0,0 +1,119 @@ +package version + +import ( + "fmt" + "os" + "runtime" + "runtime/debug" + "sync" +) + +const ( + unknownProperty = "N/A" +) + +// Information of versioning +var ( + // GoVersion is the version of the Go toolchain that built the binary(for example, "go1.19.2"). + GoVersion = unknownProperty + // GitCommit shows the revision identifier for the current commit or checkout. + GitCommit = unknownProperty + // GitCommitDate shows the time associated with GitCommit, in RFC3339 format + GitCommitDate = unknownProperty + // GitTreeState shows "dirty" indicating the source tree had local modifications, otherwise it is invisible. + GitTreeState = unknownProperty + // GitTag shows latest tag if injected by go -ldflags. otherwise it is invisible by default. + GitTag = unknownProperty + // BuildDate shows the built time for the associated binary + BuildDate = unknownProperty + // Platform composes with GOARCH and GOOS + Platform = unknownProperty + // Compiler shows the toolchain flag used (typically "gc") + Compiler = unknownProperty +) + +func init() { + // usages: version or --version + if len(os.Args) > 1 && (os.Args[1] == "version" || os.Args[1] == "--version") { + Version() + os.Exit(0) + } + + // TODO: expose version information via exporter as needed +} + +var once sync.Once + +// Version prints the information of versioning +func Version() { + once.Do(func() { + collectFromBuildInfo() + collectFromRuntime() + }) + + format := "%s:\t%s\n" + xprintf(format, "Go version", GoVersion) + xprintf(format, "Git commit", GitCommit) + xprintf(format, "Commit date", GitCommitDate) + + if GitTreeState != unknownProperty { + xprintf(format, "Git tree state", GitTreeState) + } + + xprintf(format, "Built date", BuildDate) + xprintf(format, "OS/Arch", Platform) + xprintf(format, "Compiler", Compiler) + + if GitTag != unknownProperty { + xprintf(format, "Git tag", GitTag) + } + +} + +// collectFromBuildInfo tries to set the build information embedded in the running binary via Go module. +// It doesn't override data if were already set by Go -ldflags. +func collectFromBuildInfo() { + info, ok := debug.ReadBuildInfo() + if !ok { + return + } + + for _, kv := range info.Settings { + switch kv.Key { + case "vcs.revision": + if GitCommit == unknownProperty && kv.Value != "" { + GitCommit = kv.Value + } + case "vcs.time": + if GitCommitDate == unknownProperty && kv.Value != "" { + GitCommitDate = kv.Value + } + + case "vcs.modified": + if GitTreeState == unknownProperty && kv.Value != "" { + GitTreeState = "dirty" + } + } + } +} + +// collectFromRuntime tries to set the build information embedded in the running binary via go runtime. +// It doesn't override data if were already set by Go -ldflags. +func collectFromRuntime() { + if GoVersion == unknownProperty { + GoVersion = runtime.Version() + } + + if Platform == unknownProperty { + Platform = fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) + } + + if Compiler == unknownProperty { + Compiler = runtime.Compiler + } +} + +// xprintf prints a message to standard output. +func xprintf(format string, args ...interface{}) { + fmt.Printf(format, args...) +}