Files
vaultik/cmd/vaultik/main.go
T
clawbot d4637c3994 Stamp Docker image version from the host; flush profiles on error exit (closes #75)
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
2026-09-21 07:43:52 +00:00

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