detached 3e5b69a

feat(cli): add neferbar version, set at build time

commit
3e5b69ac53d9341f7622020a5641182369a42de4
author
brice · · 2026-10-08 08:14 UTC
parent
9c553cf
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +50 -0
M cmd/neferbar/main.go +27 -0
@@ -6,6 +6,7 @@ import (
66 "errors"
77 "flag"
88 "fmt"
9+ "io"
910 "log/slog"
1011 "net"
1112 "net/http"
@@ -13,6 +14,8 @@ import (
1314 "os"
1415 "os/signal"
1516 "runtime"
17+ "runtime/debug"
18+ "strings"
1619 "syscall"
1720 "time"
1821
@@ -20,7 +23,31 @@ import (
2023 "github.com/bnema/neferbar/internal/config"
2124 )
2225
26+// version is set at build time: -ldflags "-X main.version=1.2.3".
27+var version = "dev"
28+
29+// printVersion implements "neferbar version". A binary built without the
30+// ldflag reports its module version instead, as with go install pkg@v1.2.3.
31+func printVersion(args []string, stdout io.Writer) error {
32+ if len(args) > 0 {
33+ return fmt.Errorf("unexpected argument %q", args[0])
34+ }
35+ v := version
36+ if info, ok := debug.ReadBuildInfo(); v == "dev" && ok && info.Main.Version != "" && info.Main.Version != "(devel)" {
37+ v = strings.TrimPrefix(info.Main.Version, "v")
38+ }
39+ _, err := fmt.Fprintln(stdout, v)
40+ return err
41+}
42+
2343 func main() {
44+ if len(os.Args) > 1 && os.Args[1] == "version" {
45+ if err := printVersion(os.Args[2:], os.Stdout); err != nil {
46+ fmt.Fprintf(os.Stderr, "neferbar version: %v\n", err)
47+ os.Exit(2)
48+ }
49+ return
50+ }
2451 if len(os.Args) > 1 && os.Args[1] == "app" {
2552 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
2653 err := runApp(ctx, os.Args[2:], os.Getenv("NEFERBAR_DISPLAY"))
@@ -6,6 +6,7 @@ import (
6 "errors"6 "errors"
7 "flag"7 "flag"
8 "fmt"8 "fmt"
9+ "io"
9 "log/slog"10 "log/slog"
10 "net"11 "net"
11 "net/http"12 "net/http"
@@ -13,6 +14,8 @@ import (
13 "os"14 "os"
14 "os/signal"15 "os/signal"
15 "runtime"16 "runtime"
17+ "runtime/debug"
18+ "strings"
16 "syscall"19 "syscall"
17 "time"20 "time"
18 21
@@ -20,7 +23,31 @@ import (
20 "github.com/bnema/neferbar/internal/config"23 "github.com/bnema/neferbar/internal/config"
21 )24 )
22 25
26+// version is set at build time: -ldflags "-X main.version=1.2.3".
27+var version = "dev"
28+
29+// printVersion implements "neferbar version". A binary built without the
30+// ldflag reports its module version instead, as with go install pkg@v1.2.3.
31+func printVersion(args []string, stdout io.Writer) error {
32+ if len(args) > 0 {
33+ return fmt.Errorf("unexpected argument %q", args[0])
34+ }
35+ v := version
36+ if info, ok := debug.ReadBuildInfo(); v == "dev" && ok && info.Main.Version != "" && info.Main.Version != "(devel)" {
37+ v = strings.TrimPrefix(info.Main.Version, "v")
38+ }
39+ _, err := fmt.Fprintln(stdout, v)
40+ return err
41+}
42+
23 func main() {43 func main() {
44+ if len(os.Args) > 1 && os.Args[1] == "version" {
45+ if err := printVersion(os.Args[2:], os.Stdout); err != nil {
46+ fmt.Fprintf(os.Stderr, "neferbar version: %v\n", err)
47+ os.Exit(2)
48+ }
49+ return
50+ }
24 if len(os.Args) > 1 && os.Args[1] == "app" {51 if len(os.Args) > 1 && os.Args[1] == "app" {
25 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)52 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
26 err := runApp(ctx, os.Args[2:], os.Getenv("NEFERBAR_DISPLAY"))53 err := runApp(ctx, os.Args[2:], os.Getenv("NEFERBAR_DISPLAY"))
A cmd/neferbar/main_test.go +23 -0
@@ -0,0 +1,23 @@
1+package main
2+
3+import (
4+ "bytes"
5+ "testing"
6+)
7+
8+func TestPrintVersion(t *testing.T) {
9+ old := version
10+ t.Cleanup(func() { version = old })
11+ version = "1.2.3"
12+
13+ var out bytes.Buffer
14+ if err := printVersion(nil, &out); err != nil {
15+ t.Fatal(err)
16+ }
17+ if got := out.String(); got != "1.2.3\n" {
18+ t.Fatalf("got %q, want %q", got, "1.2.3\n")
19+ }
20+ if err := printVersion([]string{"extra"}, &out); err == nil {
21+ t.Fatal("extra argument accepted")
22+ }
23+}
@@ -0,0 +1,23 @@
1+package main
2+
3+import (
4+ "bytes"
5+ "testing"
6+)
7+
8+func TestPrintVersion(t *testing.T) {
9+ old := version
10+ t.Cleanup(func() { version = old })
11+ version = "1.2.3"
12+
13+ var out bytes.Buffer
14+ if err := printVersion(nil, &out); err != nil {
15+ t.Fatal(err)
16+ }
17+ if got := out.String(); got != "1.2.3\n" {
18+ t.Fatalf("got %q, want %q", got, "1.2.3\n")
19+ }
20+ if err := printVersion([]string{"extra"}, &out); err == nil {
21+ t.Fatal("extra argument accepted")
22+ }
23+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 5

Tags 4

↑↓ moveenter openesc close