From ee629ef3f4a6829620a20aadeae369c1f6c7986c Mon Sep 17 00:00:00 2001 From: Ranganath Gunawardane Date: Thu, 23 Jul 2026 17:09:59 +1000 Subject: [PATCH 1/4] feat(service): add -v version flag to print version and OS/arch info --- make.go | 33 +++++++++++++++++++++++++++------ service/args.go | 2 ++ service/main.go | 22 ++++++++++++++++++---- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/make.go b/make.go index f5e3647..60addc9 100755 --- a/make.go +++ b/make.go @@ -57,6 +57,7 @@ func usage() { func main() { goos := flag.String("goos", runtime.GOOS, "Specify target operating system for cross compilation") goarch := flag.String("goarch", runtime.GOARCH, "Specify target architecture for cross compilation") + versionFlag := flag.String("version", "", "Specify version string to inject into binaries") flag.Parse() _ = os.Setenv("GOOS", *goos) @@ -74,9 +75,11 @@ func main() { action = flag.Arg(0) } + ver := resolveVersion(*versionFlag) + switch action { case "all": - buildAll() + buildAll(ver) case "test": testAll() default: @@ -84,19 +87,37 @@ func main() { } } -func buildAll() { +// resolveVersion resolves the build version string using the following priority order: +// 1. Explicit CLI flag (e.g. go run make.go -version 1.8.0). +// 2. CI environment variables (SILVER_VERSION or SILVER_RELEASE_TAG). +// 3. Fallback "dev" for unflagged local development builds. +func resolveVersion(flagVersion string) string { + if flagVersion != "" { + return strings.TrimPrefix(flagVersion, "v") + } + if v := os.Getenv("SILVER_VERSION"); v != "" { + return strings.TrimPrefix(v, "v") + } + if tag := os.Getenv("SILVER_RELEASE_TAG"); tag != "" { + return strings.TrimPrefix(tag, "v") + } + return "dev" +} + +func buildAll(ver string) { makeDir(buildOutputDir) goos := os.Getenv("GOOS") goarch := os.Getenv("GOARCH") + ldflags := fmt.Sprintf("-s -w -X main.Version=%s", ver) - fmt.Printf("Building binaries for %s/%s ...\n", goos, goarch) + fmt.Printf("Building binaries for %s/%s (version %s) ...\n", goos, goarch, ver) _ = runCmd("go", "build", "-ldflags", "-s -w", "-o", makeOutputPath(buildOutputDir, "updater"), rootNamespace+"/updater") - _ = runCmd("go", "build", "-ldflags", "-s -w", "-o", makeOutputPath(buildOutputDir, "service"), rootNamespace+"/service") + _ = runCmd("go", "build", "-ldflags", ldflags, "-o", makeOutputPath(buildOutputDir, "service"), rootNamespace+"/service") _ = runCmd("go", "build", "-ldflags", "", "-o", makeOutputPath(buildOutputDir, "jsonsig"), rootNamespace+"/lib/jsonsig/cmd") - _ = runCmd("go", "build", "-tags", "nohttp", "-ldflags", "-s -w", "-o", makeOutputPath(buildOutputDir, "service-no-http"), rootNamespace+"/service") + _ = runCmd("go", "build", "-tags", "nohttp", "-ldflags", ldflags, "-o", makeOutputPath(buildOutputDir, "service-no-http"), rootNamespace+"/service") if goos == "windows" { - _ = runCmd("go", "build", "-tags", "nohttp", "-ldflags", "-s -w -H=windowsgui", "-o", makeOutputPath(buildOutputDir, "service-no-window"), rootNamespace+"/service") + _ = runCmd("go", "build", "-tags", "nohttp", "-ldflags", ldflags+" -H=windowsgui", "-o", makeOutputPath(buildOutputDir, "service-no-window"), rootNamespace+"/service") _ = runCmd("go", "build", "-ldflags", "-s -w -H=windowsgui", "-o", makeOutputPath(buildOutputDir, "updater-no-window"), rootNamespace+"/updater") } diff --git a/service/args.go b/service/args.go index 522ef38..f09d837 100644 --- a/service/args.go +++ b/service/args.go @@ -29,6 +29,7 @@ var validArgs = []string{ "validate", "run", "command", + "version", } func isArgsValid(args []string) bool { @@ -51,6 +52,7 @@ var aliases = map[string]string{ "delete": "uninstall", "check": "validate", "test": "validate", + "v": "version", } func normalizeArgs(args []string) []string { diff --git a/service/main.go b/service/main.go index 88d7109..3418c0a 100644 --- a/service/main.go +++ b/service/main.go @@ -11,6 +11,7 @@ import ( "os" "path" "path/filepath" + "runtime" "strings" "sync" "time" @@ -42,8 +43,22 @@ func main() { os.Exit(run()) } +// Version represents the build version string, set at build time via -ldflags "-X main.Version=x.y.z". +var Version = "dev" + +func printVersion() { + fmt.Printf("silver version %s %s/%s\n", Version, runtime.GOOS, runtime.GOARCH) +} + func run() (exitCode int) { - err := os.Chdir(exeFolder()) + // Parse CLI args early to support diagnostic version flag (-v) without requiring a config file. + action, actionArgs, err := parse(os.Args) + if err == nil && action == "version" { + printVersion() + return 0 + } + + err = os.Chdir(exeFolder()) if err != nil { _, _ = fmt.Fprintf(os.Stderr, "ERROR: Unable to set working directory: %v\n", err) return 1 @@ -57,8 +72,6 @@ func run() (exitCode int) { _, _ = fmt.Fprintf(os.Stderr, "ERROR: Invalid config - %v\n", err) return 1 } - - action, actionArgs, err := parse(os.Args) if err != nil { printUsage(ctx.conf.ServiceDescription.DisplayName, ctx.conf.ServiceDescription.Description) return 1 @@ -155,7 +168,7 @@ func printUsage(svcDisplayName, svcDesc string) { serviceName()) fmt.Printf("%s\n\n", svcDesc) fmt.Printf("Usage:\n") - fmt.Printf("%s [install|uninstall|start|stop|command|validate|run|help] [command-name]\n", exeName()) + fmt.Printf("%s [install|uninstall|start|stop|command|validate|run|version|help] [command-name]\n", exeName()) fmt.Printf(" install - Install the service.\n") fmt.Printf(" uninstall - Remove/uninstall the service.\n") fmt.Printf(" start - Start an installed service.\n") @@ -163,6 +176,7 @@ func printUsage(svcDisplayName, svcDesc string) { fmt.Printf(" validate - Test the configuration file.\n") fmt.Printf(" run - Run service on in command-line mode.\n") fmt.Printf(" command - Run a command [command-name].\n") + fmt.Printf(" version - Display version and target OS/architecture (-v).\n") fmt.Printf(" help - This usage message.\n") } From 0e198c4db9fb76c89f8c4b1431a12d212de77fec Mon Sep 17 00:00:00 2001 From: Ranganath Gunawardane Date: Fri, 24 Jul 2026 20:28:19 +1000 Subject: [PATCH 2/4] fix (service): keep only the version subcommand --- service/args.go | 1 - service/main.go | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/service/args.go b/service/args.go index f09d837..90bf8de 100644 --- a/service/args.go +++ b/service/args.go @@ -52,7 +52,6 @@ var aliases = map[string]string{ "delete": "uninstall", "check": "validate", "test": "validate", - "v": "version", } func normalizeArgs(args []string) []string { diff --git a/service/main.go b/service/main.go index 3418c0a..c3a5e7f 100644 --- a/service/main.go +++ b/service/main.go @@ -51,7 +51,7 @@ func printVersion() { } func run() (exitCode int) { - // Parse CLI args early to support diagnostic version flag (-v) without requiring a config file. + // Parse CLI args early to support diagnostic version command without requiring a config file. action, actionArgs, err := parse(os.Args) if err == nil && action == "version" { printVersion() @@ -176,7 +176,7 @@ func printUsage(svcDisplayName, svcDesc string) { fmt.Printf(" validate - Test the configuration file.\n") fmt.Printf(" run - Run service on in command-line mode.\n") fmt.Printf(" command - Run a command [command-name].\n") - fmt.Printf(" version - Display version and target OS/architecture (-v).\n") + fmt.Printf(" version - Display version and target OS/architecture.\n") fmt.Printf(" help - This usage message.\n") } From 691237c0e70d6c808017afeb22f322c30d205cf3 Mon Sep 17 00:00:00 2001 From: Ranganath Gunawardane Date: Fri, 24 Jul 2026 20:44:03 +1000 Subject: [PATCH 3/4] fix(service): restore usage message for invalid actions --- service/main.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/service/main.go b/service/main.go index c3a5e7f..05085be 100644 --- a/service/main.go +++ b/service/main.go @@ -52,13 +52,13 @@ func printVersion() { func run() (exitCode int) { // Parse CLI args early to support diagnostic version command without requiring a config file. - action, actionArgs, err := parse(os.Args) - if err == nil && action == "version" { + action, actionArgs, parseErr := parse(os.Args) + if parseErr == nil && action == "version" { printVersion() return 0 } - err = os.Chdir(exeFolder()) + err := os.Chdir(exeFolder()) if err != nil { _, _ = fmt.Fprintf(os.Stderr, "ERROR: Unable to set working directory: %v\n", err) return 1 @@ -72,7 +72,7 @@ func run() (exitCode int) { _, _ = fmt.Fprintf(os.Stderr, "ERROR: Invalid config - %v\n", err) return 1 } - if err != nil { + if parseErr != nil { printUsage(ctx.conf.ServiceDescription.DisplayName, ctx.conf.ServiceDescription.Description) return 1 } From 2f281d5abb819bad2baa07e8e0b6b94ef56ae563 Mon Sep 17 00:00:00 2001 From: Ranganath Gunawardane Date: Fri, 24 Jul 2026 20:49:36 +1000 Subject: [PATCH 4/4] fix(make): drop env var fallbacks for version resolution --- make.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/make.go b/make.go index 60addc9..e435dc3 100755 --- a/make.go +++ b/make.go @@ -87,19 +87,12 @@ func main() { } } -// resolveVersion resolves the build version string using the following priority order: -// 1. Explicit CLI flag (e.g. go run make.go -version 1.8.0). -// 2. CI environment variables (SILVER_VERSION or SILVER_RELEASE_TAG). -// 3. Fallback "dev" for unflagged local development builds. +// resolveVersion resolves the build version string from the explicit CLI flag +// (e.g. go run make.go -version 1.8.0), falling back to "dev" for unflagged +// local development builds. func resolveVersion(flagVersion string) string { if flagVersion != "" { - return strings.TrimPrefix(flagVersion, "v") - } - if v := os.Getenv("SILVER_VERSION"); v != "" { - return strings.TrimPrefix(v, "v") - } - if tag := os.Getenv("SILVER_RELEASE_TAG"); tag != "" { - return strings.TrimPrefix(tag, "v") + return strings.TrimPrefix(flagVersion, "v") // Strip leading "v" so callers can pass git tag (e.g. v1.8.0) directly. } return "dev" }