script/docker now computes the version (via script/version), commit and build date on the host and passes them as build args; the Dockerfile no longer runs git, which always returned "unknown" because the build context excludes .git. A dirty tree is reflected through script/version's -dirty suffix. main now exits via os.Exit(run()), so its deferred CPU/heap profile writers flush before the process ends, and Entry returns a status code instead of calling os.Exit. Each command ran its operation in an fx goroutine that called os.Exit(1) on failure, discarding those profiles and the PID-lock release; they now route the error to the return path through one RunOperation helper. errReported keeps Entry from printing an already-reported failure twice. Model: opus-4-8
61 lines
1.6 KiB
Go
61 lines
1.6 KiB
Go
// Package main is the vaultik command-line entry point.
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
"runtime"
|
|
"runtime/pprof"
|
|
|
|
"sneak.berlin/go/vaultik/internal/cli"
|
|
)
|
|
|
|
func main() {
|
|
os.Exit(run())
|
|
}
|
|
|
|
// run sets up optional profiling, runs the CLI, and returns the process
|
|
// exit code. os.Exit lives in main so it fires only after run's deferred
|
|
// profile writers have flushed. cli.Entry returns a status code rather
|
|
// than calling os.Exit itself: an os.Exit from inside it would skip
|
|
// these defers and truncate the profile of a failing command -- exactly
|
|
// the command one most often wants to profile.
|
|
func run() int {
|
|
// CPU profiling: set VAULTIK_CPUPROFILE=/path/to/cpu.prof
|
|
if cpuProfile := os.Getenv("VAULTIK_CPUPROFILE"); cpuProfile != "" {
|
|
f, err := os.Create(cpuProfile) //nolint:gosec // G304: operator-set path
|
|
if err != nil {
|
|
panic("could not create CPU profile: " + err.Error())
|
|
}
|
|
|
|
defer func() { _ = f.Close() }()
|
|
|
|
err = pprof.StartCPUProfile(f)
|
|
if err != nil {
|
|
panic("could not start CPU profile: " + err.Error())
|
|
}
|
|
|
|
defer pprof.StopCPUProfile()
|
|
}
|
|
|
|
// Memory profiling: set VAULTIK_MEMPROFILE=/path/to/mem.prof
|
|
if memProfile := os.Getenv("VAULTIK_MEMPROFILE"); memProfile != "" {
|
|
defer func() {
|
|
f, err := os.Create(memProfile) //nolint:gosec // G304: operator-set path
|
|
if err != nil {
|
|
panic("could not create memory profile: " + err.Error())
|
|
}
|
|
|
|
defer func() { _ = f.Close() }()
|
|
|
|
runtime.GC() // get up-to-date statistics
|
|
|
|
err = pprof.WriteHeapProfile(f)
|
|
if err != nil {
|
|
panic("could not write memory profile: " + err.Error())
|
|
}
|
|
}()
|
|
}
|
|
|
|
return cli.Entry()
|
|
}
|