From f7c72626eeedf03c0ae9a4054925a0ad63c8c917 Mon Sep 17 00:00:00 2001 From: omicron Date: Fri, 9 May 2025 03:34:13 +0200 Subject: [PATCH] Use cobra to turn linkctl into a proper cli Most commands are currently placeholders but version and db init work --- cmd/linkctl/config.go | 27 ++++++++ cmd/linkctl/db.go | 48 ++++++++++++++ cmd/linkctl/main.go | 149 ++++++++++++++++++++++++++++++++++++++++-- go.mod | 10 ++- go.sum | 10 +++ 5 files changed, 238 insertions(+), 6 deletions(-) create mode 100644 cmd/linkctl/config.go create mode 100644 cmd/linkctl/db.go diff --git a/cmd/linkctl/config.go b/cmd/linkctl/config.go new file mode 100644 index 0000000..49b0723 --- /dev/null +++ b/cmd/linkctl/config.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func configPreRun(cmd *cobra.Command, args []string) error { + return setupDb() +} + +func configPostRun(cmd *cobra.Command, args []string) error { + return cleanupDb() +} + +func configSetHandler(cmd *cobra.Command, args []string) { + fmt.Println("Not implemented") +} + +func configGetHandler(cmd *cobra.Command, args []string) { + fmt.Println("Not implemented") +} + +func configListHandler(cmd *cobra.Command, args []string) { + fmt.Println("Not implemented") +} diff --git a/cmd/linkctl/db.go b/cmd/linkctl/db.go new file mode 100644 index 0000000..058ddc2 --- /dev/null +++ b/cmd/linkctl/db.go @@ -0,0 +1,48 @@ +package main + +import ( + "fmt" + + "git.omicron.one/omicron/linkshare/internal/database" + "git.omicron.one/omicron/linkshare/internal/util" + "git.omicron.one/omicron/linkshare/internal/version" + "github.com/spf13/cobra" +) + +func openDB() (*database.DB, error) { + paths, err := util.FindDirectories(dbPath) + if err != nil { + return nil, err + } + return database.Open(paths.DatabaseFile) +} + +func dbPreRun(cmd *cobra.Command, args []string) error { + return setupDb() +} + +func dbPostRun(cmd *cobra.Command, args []string) error { + return cleanupDb() +} + +func dbInitHandler(cmd *cobra.Command, args []string) { + err := db.Initialize(paths.SchemaDir) + if err == database.ErrAlreadyInitialized { + fmt.Printf("Database %q is already initialized\n", dbPath) + return + } + if err == nil { + fmt.Printf("Initialized database %q with schema version %d\n", dbPath, version.SchemaVersion) + return + } + + fmt.Printf("Failed to initialize database %q: %v\n", dbPath, err) +} + +func dbBackupHandler(cmd *cobra.Command, args []string) { + fmt.Println("Not implemented") +} + +func dbUpdateHandler(cmd *cobra.Command, args []string) { + fmt.Println("Not implemented") +} diff --git a/cmd/linkctl/main.go b/cmd/linkctl/main.go index 51ebf77..92a2745 100644 --- a/cmd/linkctl/main.go +++ b/cmd/linkctl/main.go @@ -2,17 +2,156 @@ package main import ( "fmt" + "os" + "git.omicron.one/omicron/linkshare/internal/database" "git.omicron.one/omicron/linkshare/internal/util" + "git.omicron.one/omicron/linkshare/internal/version" + "github.com/spf13/cobra" ) -func main() { - paths, err := util.FindDirectories("") +var ( + dbPath string + verbosity int +) + +var ( + paths *util.AppPaths + db *database.DB +) + +func exitIfError(err error) { if err != nil { fmt.Println(err) + os.Exit(1) + } +} + +func setupPaths() error { + if paths != nil { + return nil + } + paths_, err := util.FindDirectories(dbPath) + if err != nil { + return err + } + paths = paths_ + return nil +} + +func setupDb() error { + if db != nil { + return nil + } + err := setupPaths() + if err != nil { + return nil } - fmt.Println("Paths:") - fmt.Println(" Schema:", paths.SchemaDir) - fmt.Println(" Database:", paths.DatabaseFile) + db_, err := database.Open(dbPath) + if err != nil { + return nil + } + db = db_ + return nil +} + +func cleanupDb() error { + if db != nil { + err := db.Close() + if err != nil { + return err + } + } + return nil +} + +func main() { + rootCmd := &cobra.Command{ + Use: "linkctl", + Short: "LinkShare CLI tool", + Long: `Command line tool to manage your self-hosted LinkShare service.`, + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + } + rootCmd.CompletionOptions.DisableDefaultCmd = true + + rootCmd.PersistentFlags().StringVarP(&dbPath, "db", "d", "", "Database file path") + rootCmd.PersistentFlags().CountVarP(&verbosity, "verbose", "v", "Increase verbosity level") + + configCmd := &cobra.Command{ + Use: "config", + Short: "Configuration commands", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + PersistentPreRunE: configPreRun, + PersistentPostRunE: configPostRun, + } + + configSetCmd := &cobra.Command{ + Use: "set", + Short: "Set a configuration value", + Run: configSetHandler, + } + + configGetCmd := &cobra.Command{ + Use: "get", + Short: "Get a configuration value", + Run: configGetHandler, + } + + configListCmd := &cobra.Command{ + Use: "list", + Short: "List all configuration values", + Run: configListHandler, + } + + configCmd.AddCommand(configSetCmd, configGetCmd, configListCmd) + + dbCmd := &cobra.Command{ + Use: "db", + Short: "Database commands", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + PersistentPreRunE: dbPreRun, + PersistentPostRunE: dbPostRun, + } + + dbInitCmd := &cobra.Command{ + Use: "init", + Short: "Initialize the database", + Run: dbInitHandler, + } + + dbBackupCmd := &cobra.Command{ + Use: "backup", + Short: "Backup the database", + Run: dbBackupHandler, + } + + dbUpdateCmd := &cobra.Command{ + Use: "update", + Short: "Update the database schema", + Run: dbUpdateHandler, + } + + dbCmd.AddCommand(dbInitCmd, dbBackupCmd, dbUpdateCmd) + + versionCmd := &cobra.Command{ + Use: "version", + Short: "Display version information", + Run: func(cmd *cobra.Command, args []string) { + version.Print() + }, + } + + rootCmd.AddCommand(configCmd, dbCmd, versionCmd) + + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } } diff --git a/go.mod b/go.mod index fa4115e..95d2876 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,12 @@ module git.omicron.one/omicron/linkshare go 1.24 -require github.com/mattn/go-sqlite3 v1.14.28 +require ( + github.com/mattn/go-sqlite3 v1.14.28 + github.com/spf13/cobra v1.9.1 +) + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/pflag v1.0.6 // indirect +) diff --git a/go.sum b/go.sum index 42e5bac..3089b82 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,12 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=