summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/cli/cli.go164
-rw-r--r--internal/cli/cmd_create_client_key.go47
-rw-r--r--internal/cli/cmd_daemon.go43
-rw-r--r--internal/cli/cmd_import.go38
-rw-r--r--internal/cli/cmd_query.go35
-rw-r--r--internal/cli/cmd_report_from_files.go38
-rw-r--r--internal/cli/cmd_tests.go7
7 files changed, 208 insertions, 164 deletions
diff --git a/internal/cli/cli.go b/internal/cli/cli.go
index 3c686db..e791512 100644
--- a/internal/cli/cli.go
+++ b/internal/cli/cli.go
@@ -1,24 +1,12 @@
package cli
import (
- "context"
- "errors"
- "flag"
"fmt"
- "os"
- "os/signal"
- "syscall"
- "codeberg.org/snonux/goprecords/internal/authkeys"
- "codeberg.org/snonux/goprecords/internal/daemon"
- "codeberg.org/snonux/goprecords/internal/goprecords"
- "codeberg.org/snonux/goprecords/internal/storage"
"codeberg.org/snonux/goprecords/internal/version"
)
-// Execute parses command‑line arguments and runs the appropriate sub‑command.
func Execute(args []string) error {
- // Handle version flag early.
if len(args) > 0 && (args[0] == "-version" || args[0] == "--version") {
fmt.Println(version.Tag)
return nil
@@ -33,7 +21,6 @@ func Execute(args []string) error {
return runDaemon(args[1:])
}
- // No subcommand – treat args as flags for a direct report from files.
if len(args) == 0 {
return runReportFromFiles(nil)
}
@@ -49,154 +36,3 @@ func Execute(args []string) error {
return runReportFromFiles(args)
}
}
-
-func runImport(args []string) error {
- fs := flag.NewFlagSet("import", flag.ExitOnError)
- statsDir := fs.String("stats-dir", "", "Directory containing .records files (required)")
- dbPath := fs.String("db", "goprecords.db", "SQLite database path")
- if err := fs.Parse(args); err != nil {
- return err
- }
- if *statsDir == "" {
- fmt.Fprintln(os.Stderr, "import: missing required flag: -stats-dir")
- fs.Usage()
- return fmt.Errorf("missing -stats-dir")
- }
- ctx := context.Background()
- db, err := storage.Open(ctx, *dbPath)
- if err != nil {
- return fmt.Errorf("open db: %w", err)
- }
- defer db.Close()
- if err := storage.CreateSchema(ctx, db); err != nil {
- return fmt.Errorf("schema: %w", err)
- }
- if err := storage.ImportFromDir(ctx, db, *statsDir); err != nil {
- return fmt.Errorf("import: %w", err)
- }
- fmt.Fprintf(os.Stderr, "imported %s into %s\n", *statsDir, *dbPath)
- return nil
-}
-
-func runQuery(args []string) error {
- fs := flag.NewFlagSet("query", flag.ExitOnError)
- dbPath := fs.String("db", "goprecords.db", "SQLite database path")
- rf := goprecords.RegisterReportFlags(fs)
- if err := fs.Parse(args); err != nil {
- return err
- }
- ctx := context.Background()
- db, err := storage.Open(ctx, *dbPath)
- if err != nil {
- return fmt.Errorf("open db: %w", err)
- }
- defer db.Close()
- aggregates, err := goprecords.LoadAggregates(ctx, db)
- if err != nil {
- return fmt.Errorf("load: %w", err)
- }
- cfg, err := rf.Parse()
- if err != nil {
- return err
- }
- return goprecords.WriteReports(os.Stdout, aggregates, cfg)
-}
-
-func runReportFromFiles(args []string) error {
- if args == nil {
- args = []string{}
- }
- fs := flag.NewFlagSet("goprecords", flag.ExitOnError)
- statsDir := fs.String("stats-dir", "", "The uptimed raw record input dir (required)")
- rf := goprecords.RegisterReportFlags(fs)
- if err := fs.Parse(args); err != nil {
- return err
- }
- if *statsDir == "" {
- fmt.Fprintln(os.Stderr, "missing required flag: -stats-dir")
- fs.Usage()
- return fmt.Errorf("missing -stats-dir")
- }
- cfg, err := rf.Parse()
- if err != nil {
- return err
- }
- ctx := context.Background()
- aggr := goprecords.NewAggregator(*statsDir)
- aggregates, err := aggr.Aggregate(ctx)
- if err != nil {
- return err
- }
- return goprecords.WriteReports(os.Stdout, aggregates, cfg)
-}
-
-func runTests() error {
- return goprecords.RunIntegrationTests("./fixtures")
-}
-
-func defaultListenFromEnv() string {
- if s := os.Getenv("GOPRECORDS_LISTEN"); s != "" {
- return s
- }
- return ":8080"
-}
-
-func runDaemon(args []string) error {
- fs := flag.NewFlagSet("daemon", flag.ExitOnError)
- fs.SetOutput(os.Stdout)
- statsDir := fs.String("stats-dir", os.Getenv("GOPRECORDS_STATS_DIR"), "Uptimed stats directory (required; env GOPRECORDS_STATS_DIR)")
- listen := fs.String("listen", defaultListenFromEnv(), "TCP listen address (env GOPRECORDS_LISTEN, default :8080)")
- authDB := fs.String("auth-db", "", "SQLite file for upload API keys (default: <stats-dir>/goprecords-auth.db)")
- if err := fs.Parse(args); err != nil {
- return err
- }
- if *statsDir == "" {
- fmt.Fprintln(os.Stdout, "daemon: missing required flag: -stats-dir (or GOPRECORDS_STATS_DIR)")
- fs.Usage()
- return fmt.Errorf("missing -stats-dir")
- }
- ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
- defer stop()
- err := daemon.Run(ctx, daemon.Config{StatsDir: *statsDir, Addr: *listen, AuthDB: *authDB})
- if err != nil && !errors.Is(err, context.Canceled) {
- return err
- }
- return nil
-}
-
-func runCreateClientKey(hostname string, args []string) error {
- if hostname == "" {
- return fmt.Errorf("create-client-key: hostname required")
- }
- fs := flag.NewFlagSet("create-client-key", flag.ExitOnError)
- fs.SetOutput(os.Stderr)
- statsDir := fs.String("stats-dir", "", "Uptimed stats directory (sets default auth-db path)")
- authDB := fs.String("auth-db", "", "SQLite file for upload API keys (default: <stats-dir>/goprecords-auth.db)")
- if err := fs.Parse(args); err != nil {
- return err
- }
- authPath := *authDB
- if authPath == "" {
- if *statsDir == "" {
- fmt.Fprintln(os.Stderr, "create-client-key: need -stats-dir or -auth-db")
- fs.Usage()
- return fmt.Errorf("missing -stats-dir or -auth-db")
- }
- authPath = authkeys.DefaultPath(*statsDir)
- }
- ctx := context.Background()
- store, err := authkeys.OpenStore(ctx, authPath)
- if err != nil {
- return fmt.Errorf("open auth db: %w", err)
- }
- defer store.Close()
- if err := store.EnsureSchema(ctx); err != nil {
- return fmt.Errorf("schema: %w", err)
- }
- token, err := store.CreateKey(ctx, hostname)
- if err != nil {
- return fmt.Errorf("create key: %w", err)
- }
- fmt.Println(token)
- return nil
-}
diff --git a/internal/cli/cmd_create_client_key.go b/internal/cli/cmd_create_client_key.go
new file mode 100644
index 0000000..d5caf28
--- /dev/null
+++ b/internal/cli/cmd_create_client_key.go
@@ -0,0 +1,47 @@
+package cli
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+
+ "codeberg.org/snonux/goprecords/internal/authkeys"
+)
+
+func runCreateClientKey(hostname string, args []string) error {
+ if hostname == "" {
+ return fmt.Errorf("create-client-key: hostname required")
+ }
+ fs := flag.NewFlagSet("create-client-key", flag.ExitOnError)
+ fs.SetOutput(os.Stderr)
+ statsDir := fs.String("stats-dir", "", "Uptimed stats directory (sets default auth-db path)")
+ authDB := fs.String("auth-db", "", "SQLite file for upload API keys (default: <stats-dir>/goprecords-auth.db)")
+ if err := fs.Parse(args); err != nil {
+ return err
+ }
+ authPath := *authDB
+ if authPath == "" {
+ if *statsDir == "" {
+ fmt.Fprintln(os.Stderr, "create-client-key: need -stats-dir or -auth-db")
+ fs.Usage()
+ return fmt.Errorf("missing -stats-dir or -auth-db")
+ }
+ authPath = authkeys.DefaultPath(*statsDir)
+ }
+ ctx := context.Background()
+ store, err := authkeys.OpenStore(ctx, authPath)
+ if err != nil {
+ return fmt.Errorf("open auth db: %w", err)
+ }
+ defer store.Close()
+ if err := store.EnsureSchema(ctx); err != nil {
+ return fmt.Errorf("schema: %w", err)
+ }
+ token, err := store.CreateKey(ctx, hostname)
+ if err != nil {
+ return fmt.Errorf("create key: %w", err)
+ }
+ fmt.Println(token)
+ return nil
+}
diff --git a/internal/cli/cmd_daemon.go b/internal/cli/cmd_daemon.go
new file mode 100644
index 0000000..2bd74a8
--- /dev/null
+++ b/internal/cli/cmd_daemon.go
@@ -0,0 +1,43 @@
+package cli
+
+import (
+ "context"
+ "errors"
+ "flag"
+ "fmt"
+ "os"
+ "os/signal"
+ "syscall"
+
+ "codeberg.org/snonux/goprecords/internal/daemon"
+)
+
+func defaultListenFromEnv() string {
+ if s := os.Getenv("GOPRECORDS_LISTEN"); s != "" {
+ return s
+ }
+ return ":8080"
+}
+
+func runDaemon(args []string) error {
+ fs := flag.NewFlagSet("daemon", flag.ExitOnError)
+ fs.SetOutput(os.Stdout)
+ statsDir := fs.String("stats-dir", os.Getenv("GOPRECORDS_STATS_DIR"), "Uptimed stats directory (required; env GOPRECORDS_STATS_DIR)")
+ listen := fs.String("listen", defaultListenFromEnv(), "TCP listen address (env GOPRECORDS_LISTEN, default :8080)")
+ authDB := fs.String("auth-db", "", "SQLite file for upload API keys (default: <stats-dir>/goprecords-auth.db)")
+ if err := fs.Parse(args); err != nil {
+ return err
+ }
+ if *statsDir == "" {
+ fmt.Fprintln(os.Stdout, "daemon: missing required flag: -stats-dir (or GOPRECORDS_STATS_DIR)")
+ fs.Usage()
+ return fmt.Errorf("missing -stats-dir")
+ }
+ ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
+ defer stop()
+ err := daemon.Run(ctx, daemon.Config{StatsDir: *statsDir, Addr: *listen, AuthDB: *authDB})
+ if err != nil && !errors.Is(err, context.Canceled) {
+ return err
+ }
+ return nil
+}
diff --git a/internal/cli/cmd_import.go b/internal/cli/cmd_import.go
new file mode 100644
index 0000000..f3ecad5
--- /dev/null
+++ b/internal/cli/cmd_import.go
@@ -0,0 +1,38 @@
+package cli
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+
+ "codeberg.org/snonux/goprecords/internal/storage"
+)
+
+func runImport(args []string) error {
+ fs := flag.NewFlagSet("import", flag.ExitOnError)
+ statsDir := fs.String("stats-dir", "", "Directory containing .records files (required)")
+ dbPath := fs.String("db", "goprecords.db", "SQLite database path")
+ if err := fs.Parse(args); err != nil {
+ return err
+ }
+ if *statsDir == "" {
+ fmt.Fprintln(os.Stderr, "import: missing required flag: -stats-dir")
+ fs.Usage()
+ return fmt.Errorf("missing -stats-dir")
+ }
+ ctx := context.Background()
+ db, err := storage.Open(ctx, *dbPath)
+ if err != nil {
+ return fmt.Errorf("open db: %w", err)
+ }
+ defer db.Close()
+ if err := storage.CreateSchema(ctx, db); err != nil {
+ return fmt.Errorf("schema: %w", err)
+ }
+ if err := storage.ImportFromDir(ctx, db, *statsDir); err != nil {
+ return fmt.Errorf("import: %w", err)
+ }
+ fmt.Fprintf(os.Stderr, "imported %s into %s\n", *statsDir, *dbPath)
+ return nil
+}
diff --git a/internal/cli/cmd_query.go b/internal/cli/cmd_query.go
new file mode 100644
index 0000000..a22aeb4
--- /dev/null
+++ b/internal/cli/cmd_query.go
@@ -0,0 +1,35 @@
+package cli
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+
+ "codeberg.org/snonux/goprecords/internal/goprecords"
+ "codeberg.org/snonux/goprecords/internal/storage"
+)
+
+func runQuery(args []string) error {
+ fs := flag.NewFlagSet("query", flag.ExitOnError)
+ dbPath := fs.String("db", "goprecords.db", "SQLite database path")
+ rf := goprecords.RegisterReportFlags(fs)
+ if err := fs.Parse(args); err != nil {
+ return err
+ }
+ ctx := context.Background()
+ db, err := storage.Open(ctx, *dbPath)
+ if err != nil {
+ return fmt.Errorf("open db: %w", err)
+ }
+ defer db.Close()
+ aggregates, err := goprecords.LoadAggregates(ctx, db)
+ if err != nil {
+ return fmt.Errorf("load: %w", err)
+ }
+ cfg, err := rf.Parse()
+ if err != nil {
+ return err
+ }
+ return goprecords.WriteReports(os.Stdout, aggregates, cfg)
+}
diff --git a/internal/cli/cmd_report_from_files.go b/internal/cli/cmd_report_from_files.go
new file mode 100644
index 0000000..ca2bb8c
--- /dev/null
+++ b/internal/cli/cmd_report_from_files.go
@@ -0,0 +1,38 @@
+package cli
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+
+ "codeberg.org/snonux/goprecords/internal/goprecords"
+)
+
+func runReportFromFiles(args []string) error {
+ if args == nil {
+ args = []string{}
+ }
+ fs := flag.NewFlagSet("goprecords", flag.ExitOnError)
+ statsDir := fs.String("stats-dir", "", "The uptimed raw record input dir (required)")
+ rf := goprecords.RegisterReportFlags(fs)
+ if err := fs.Parse(args); err != nil {
+ return err
+ }
+ if *statsDir == "" {
+ fmt.Fprintln(os.Stderr, "missing required flag: -stats-dir")
+ fs.Usage()
+ return fmt.Errorf("missing -stats-dir")
+ }
+ cfg, err := rf.Parse()
+ if err != nil {
+ return err
+ }
+ ctx := context.Background()
+ aggr := goprecords.NewAggregator(*statsDir)
+ aggregates, err := aggr.Aggregate(ctx)
+ if err != nil {
+ return err
+ }
+ return goprecords.WriteReports(os.Stdout, aggregates, cfg)
+}
diff --git a/internal/cli/cmd_tests.go b/internal/cli/cmd_tests.go
new file mode 100644
index 0000000..643b515
--- /dev/null
+++ b/internal/cli/cmd_tests.go
@@ -0,0 +1,7 @@
+package cli
+
+import "codeberg.org/snonux/goprecords/internal/goprecords"
+
+func runTests() error {
+ return goprecords.RunIntegrationTests("./fixtures")
+}