Artifact 2bfe24d03e0c9beaded88f7410852578b5c9da094d80e3742a6a91e9d2c94404:
- File
cli/version.go
— part of check-in
[6273a0750d]
at
2026-07-22 23:03:24
on branch trunk
— fix: correct go.mod module path to go-libfossil (#76) (#117)
* fix: correct go.mod module path to go-libfossil (#76)
The module directive still declared github.com/danmestas/libfossil after the repository was renamed to go-libfossil. pkg.go.dev/godoc scraping matches the declared module path against its hosting path, so the stale path broke SDK doc generation.
Rename the module path across all four in-repo modules (root, the two db/driver submodules, observer/otel, and docs/site) and every internal import, plus the release workflow, the doc-generation script, and the docs.
No tag has been published under the go-libfossil path yet, so the cross-module requires cannot resolve from the proxy. Add replace directives pointing the in-repo requires at their local directories so GOWORK=off builds and the CI matrix resolve without a published version. These replaces are ignored by downstream consumers and can be dropped once new-path tags are cut.
* Guard releases against replace directives; regenerate SDK docs
The go-libfossil rename bridges the in-repo modules with `replace` directives. Go refuses a main module that carries them, so a tag cut while they are present breaks `go install .../cmd/libfossil@<tag>` and every `@version` fetch of the driver submodules. Add a Release workflow step that fails the job before anything is published if any tracked go.mod still contains a replace directive, so the bridge is a CI-enforced TODO rather than a silent landmine. The step comment records what unblocks a release: re-tag the submodules with the corrected module paths, bump the root requires, then drop the replace blocks.
Regenerate the SDK reference docs. The previous pass only substituted URLs over the pre-existing generated files, leaving stale signatures (Repo.Timeline was still documented as taking LogOpts rather than TimelineOpts). Note that gomarkdoc must be run outside a git worktree — inside one it silently strips every source link.
Also reword the README rename note, which read as though the import path had not changed, and re-sort the ncruces require block. (user: [email protected], size: 4298) [annotate] [blame] [check-ins using]
package cli import ( "fmt" "runtime" "runtime/debug" "strings" "unicode" ) // buildVersion overrides the module version reported by Version, for // release builds where runtime/debug.ReadBuildInfo cannot report anything // more meaningful than "(devel)" -- e.g. a plain `go build` invocation on // the main module outside of a `go install pkg@version` or a git checkout. // When set, it is used verbatim as the version field: a release build // script is expected to bake in whatever it considers the canonical // identifier (tag, commit, or both), so Version does not also append a // separately-detected commit on top of it. Set at build time: // // go build -ldflags "-X github.com/danmestas/go-libfossil/cli.buildVersion=v0.6.3" ./cmd/libfossil var buildVersion = "" // init rejects a malformed buildVersion at program startup, before any // command runs -- not just when someone happens to run `version`. A // whitespace-containing override is a build-time operator mistake (a // broken -ldflags invocation), not a runtime condition: sanitizing it // would silently mangle the operator's intent, and falling back to // runtime/debug info would report a version that is confidently wrong. // Both hide the mistake in the one field whose entire job is to be // trustworthy for the benchmark harness that stamps it into every // emitted record. Failing the whole binary immediately surfaces the bad // build the first time it runs, rather than shipping a corrupted // identifier that only breaks downstream when someone parses it. func init() { assertValidBuildVersion(buildVersion) } // assertValidBuildVersion panics if v would break Version()'s single-line, // four-field contract. Empty is valid -- it means no -ldflags override was // supplied and Version falls back to runtime/debug.ReadBuildInfo. func assertValidBuildVersion(v string) { if v == "" { return } if strings.ContainsFunc(v, unicode.IsSpace) { panic(fmt.Sprintf("cli: buildVersion (set via -ldflags -X) must not contain whitespace, got %q", v)) } } // VersionCmd prints a single-line, stable, machine-parseable build // identifier and exits 0. type VersionCmd struct{} // Run prints Version() and always succeeds: there is nothing about the // local environment that can make reporting the build identifier fail. func (c *VersionCmd) Run() error { fmt.Println(Version()) return nil } // Version returns a single-line build identifier for this binary: the // module version (or a build-time override), the Go toolchain version, // and the platform. The shape is fixed at four whitespace-separated // fields -- "libfossil <version> <go version> <os>/<arch>" -- regardless // of which fields carried real data, so a caller can rely on // strings.Fields(Version()) unconditionally. This is the same string // both `libfossil version` and `libfossil --version` print. func Version() string { return fmt.Sprintf("libfossil %s %s %s/%s", moduleVersion(), runtime.Version(), runtime.GOOS, runtime.GOARCH) } // moduleVersion resolves the version field: the ldflags override when // present, otherwise whatever runtime/debug.ReadBuildInfo can report. func moduleVersion() string { if buildVersion != "" { return buildVersion } return versionFromBuildInfo() } // versionFromBuildInfo derives a version identifier from the running // binary's embedded build info: the module version when the toolchain // recorded one, else the literal "(devel)" fallback -- never empty. // // Main.Version alone is used verbatim, with no separate vcs.revision // composition: empirically (verified against go1.26 with `go build .` // inside this repo's own checkout), Main.Version is only ever the // uninformative literal "(devel)" in exactly the cases where VCS // stamping produced nothing at all -- -buildvcs=false, or no VCS // checkout present -- and in both, bi.Settings carries no vcs.revision // either. Whenever a VCS revision *is* available, Go has already folded // it into Main.Version as a pseudo-version (e.g. // "v0.6.4-20260719231612-e972f9ffa769+dirty"), so a fallback loop over // vcs.revision would either never fire or double-report the same commit. func versionFromBuildInfo() string { bi, ok := debug.ReadBuildInfo() if !ok || bi.Main.Version == "" { return "(devel)" } return bi.Main.Version }