summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-22 17:06:26 +0200
committerPaul Buetow <paul@buetow.org>2026-02-22 17:06:26 +0200
commit8b627f383e68ce2b71832d26e86f621239271ad0 (patch)
treeff343555a378b1e093985ca5445db0a999b3f03e
parent8480d1b1b074729ebfe43cc2fcb400910880627f (diff)
Update main.go and cli API for signal-cancellable context (task 352/main)
main.go: set up signal.NotifyContext(SIGINT, SIGTERM) so long-running operations (fzf, external editors) terminate gracefully on interrupts. Call cli.New(ctx) explicitly and pass the context to c.Run(ctx, argv), matching the task spec and allowing the context to flow through all store/git/crypto operations. cli: expose New(ctx) and Run(ctx, argv) as the public API; remove the package-level Run() helper that created its own context.Background(). Verified: mage build produces ./bin/geheim; PIN=test ./bin/geheim version prints "> geheim v0.4.0". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--cmd/geheim/main.go22
-rw-r--r--internal/cli/cli.go25
2 files changed, 32 insertions, 15 deletions
diff --git a/cmd/geheim/main.go b/cmd/geheim/main.go
index 4032f53..4c432e8 100644
--- a/cmd/geheim/main.go
+++ b/cmd/geheim/main.go
@@ -1,13 +1,29 @@
-// main is the entry point for the geheim binary.
-// It delegates all logic to the cli package and exits with the returned code.
+// main is the thin entry point for the geheim binary.
+// It sets up a signal-cancellable context, initialises the CLI, and exits
+// with the code returned by Run. All command logic lives in internal/cli.
package main
import (
+ "context"
+ "fmt"
"os"
+ "os/signal"
+ "syscall"
"codeberg.org/snonux/geheim/internal/cli"
)
func main() {
- os.Exit(cli.Run())
+ // Cancel the context on SIGINT or SIGTERM so that long-running operations
+ // (fzf, external editors) terminate gracefully rather than being killed hard.
+ ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
+ defer stop()
+
+ c, err := cli.New(ctx)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "FATAL %v\n", err)
+ os.Exit(3)
+ }
+
+ os.Exit(c.Run(ctx, os.Args[1:]))
}
diff --git a/internal/cli/cli.go b/internal/cli/cli.go
index 040d58b..7d59b94 100644
--- a/internal/cli/cli.go
+++ b/internal/cli/cli.go
@@ -59,20 +59,21 @@ type CLI struct {
lastResult string // most recent search result description
}
-// Run is the package-level entry point called by cmd/geheim/main.go.
-// It creates a CLI, then either dispatches a single command from os.Args
-// or enters the interactive shell loop, and returns an exit code.
-func Run() int {
- ctx := context.Background()
+// New initialises all runtime dependencies (config, PIN, cipher, store, git,
+// clipboard, shell) and returns a ready-to-use CLI. cmd/geheim/main.go calls
+// New with a signal-cancellable context so that long-running operations (fzf,
+// external editors) are interrupted cleanly on SIGINT/SIGTERM.
+func New(ctx context.Context) (*CLI, error) {
+ return newCLI(ctx)
+}
- c, err := newCLI(ctx)
- if err != nil {
- fatal(err.Error()) // fatal calls os.Exit(3) and does not return
- return 3 //nolint:govet // unreachable; present for compiler flow analysis
- }
+// Run dispatches argv (typically os.Args[1:]) to the appropriate handler or
+// enters the interactive shell loop. Returns an exit code suitable for
+// os.Exit. The caller is responsible for calling sh.Close() when done;
+// cmd/geheim/main.go does this via defer.
+func (c *CLI) Run(ctx context.Context, argv []string) int {
defer c.sh.Close()
-
- return c.run(ctx, os.Args[1:])
+ return c.run(ctx, argv)
}
// newCLI initialises all dependencies: config, PIN, cipher, store, git,