Compare commits

..

4 Commits

Author SHA1 Message Date
3ce3335695 Use cobra to turn linkctl into a proper cli
Most commands are currently placeholders but version and db init work
2025-05-09 03:34:13 +02:00
078a949dc4 SQUASHME update db error names 2025-05-09 02:54:24 +02:00
9f28796e8a Add version package and update the makefile
The makefile will grab the version info from git and pass it to the
linker so that version information based on tags, commits and commit
times is available in the code.
2025-05-09 02:45:01 +02:00
6998a0fa0a Add basic database interaction 2025-05-09 02:44:55 +02:00
6 changed files with 247 additions and 14 deletions

27
cmd/linkctl/config.go Normal file
View File

@@ -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")
}

48
cmd/linkctl/db.go Normal file
View File

@@ -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")
}

View File

@@ -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)
}
}

10
go.mod
View File

@@ -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
)

10
go.sum
View File

@@ -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=

View File

@@ -24,9 +24,10 @@ type DB struct {
}
var (
ErrDatabaseNotInitialized = errors.New("database not initialized")
ErrDatabaseSchemaOutdated = errors.New("database schema needs updating")
ErrDatabaseSchemaUnsupported = errors.New("database schema is too new for the server")
ErrNotInitialized = errors.New("database not initialized")
ErrAlreadyInitialized = errors.New("database already initialized")
ErrSchemaOutdated = errors.New("database schema needs updating")
ErrSchemaUnsupported = errors.New("database schema is too new for the server")
ErrMigrationFailed = errors.New("migration failed")
)
@@ -65,7 +66,7 @@ func (db *DB) Close() error {
func (db *DB) Initialize(schemaPath string) error {
err := db.CheckInitialized()
if err == nil {
return nil
return ErrAlreadyInitialized
}
currentSchema := filepath.Join(schemaPath, "current.sql")
@@ -91,7 +92,7 @@ func (db *DB) CheckInitialized() error {
}
if count == 0 {
return ErrDatabaseNotInitialized
return ErrNotInitialized
}
return nil
}
@@ -127,9 +128,9 @@ func (db *DB) CheckSchemaVersion() error {
return err
}
if version_ < version.SchemaVersion {
return ErrDatabaseSchemaOutdated
return ErrSchemaOutdated
} else if version_ > version.SchemaVersion {
return ErrDatabaseSchemaUnsupported
return ErrSchemaUnsupported
}
return nil
}