Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ability to set bookmarks DB location in config with CLI #4

Merged
merged 1 commit into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions cli/cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"errors"
"fmt"
"time"

Expand Down Expand Up @@ -66,6 +67,7 @@ type ConfigCmd struct {
// DBConfigCmd is a CLI command to manage the bookmarks database location config.
type DBConfigCmd struct {
Get GetDBConfigCmd `cmd:"" help:"Get the location of the bookmarks database from the configuration."`
Set SetDBConfigCmd `cmd:"" help:"Set the location of the bookmarks database in the configuration."`
}

// Run add a bookmark.
Expand Down Expand Up @@ -627,22 +629,48 @@ type GetDBConfigCmd struct {
func (r *GetDBConfigCmd) Run(ctx *Context) error {
start := time.Now()

dbPath, err := lib.GetDBPathConfig()
config, err := lib.GetConfig()

if err != nil {
if err != nil && !errors.Is(err, lib.ErrConfigMissing) {
formatError(ctx.Writer, ctx.Formatter, err)
ctx.ReturnCode(1)
return nil
}

elapsed := time.Since(start)

formatConfigResult(ctx.Writer, ctx.Formatter, dbPath)
formatConfigResult(ctx.Writer, ctx.Formatter, config.DB)
formatSuccess(ctx.Writer, ctx.Formatter, fmt.Sprintf("Retreived in %s", elapsed))

return nil
}

// SetDBConfigCmd is a CLI command to set the location of the bookmarks database in the config.
type SetDBConfigCmd struct {
DB string `arg:"" name:"db" help:"Location of the bookmarks database."`
}

// Run set the location of the bookmarks database in the config.
func (r *SetDBConfigCmd) Run(ctx *Context) error {
start := time.Now()

err := lib.UpdateConfig(func(config *lib.Config) {
config.DB = r.DB
})

if err != nil && !errors.Is(err, lib.ErrConfigMissing) {
formatError(ctx.Writer, ctx.Formatter, err)
ctx.ReturnCode(1)
return nil
}

elapsed := time.Since(start)

formatSuccess(ctx.Writer, ctx.Formatter, fmt.Sprintf("Set in %s", elapsed))

return nil
}

// RootCmdFactory creates a new RootCmd.
func RootCmdFactory() RootCmd {
var cmd RootCmd
Expand Down
96 changes: 75 additions & 21 deletions lib/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ import (

"github.com/knadh/koanf/parsers/toml"
"github.com/knadh/koanf/providers/file"
"github.com/knadh/koanf/providers/structs"
"github.com/knadh/koanf/v2"
)

const configFilename = "armaria.toml"
const databaseFilename = "bookmarks.db"

// Config is the unmarshalled Config.
type Config struct {
DB string `koanf:"db"`
}

// mkDirAllFn creates a directory if it doesn't already exist.
type mkDirAllFn func(path string, perm os.FileMode) error

Expand All @@ -24,40 +30,88 @@ type userHomeFn func() (string, error)
// joinFn joins path segments together.
type joinFn func(elem ...string) string

// GetDBPathConfig gets the path to the bookmarks database from the config file.
func GetDBPathConfig() (string, error) {
config, err := getConfig(runtime.GOOS, os.UserHomeDir, filepath.Join)
if err != nil && !errors.Is(err, ErrConfigMissing) {
return "", err
}
// updateConfigFn is a callback to update the current config
type updateConfigFn func(config *Config)

if errors.Is(err, ErrConfigMissing) {
return "", nil
} else {
return config.String("db"), nil
}
}

// getConfig parses the config file.
// GetConfig gets the current config.
// If the sentinerl error ErrConfigMissing then it doesn't exist.
func getConfig(goos string, userHome userHomeFn, join joinFn) (*koanf.Koanf, error) {
configPath, err := getConfigPath(goos, userHome, join)
func GetConfig() (Config, error) {
config := Config{}

configPath, err := getConfigPath(runtime.GOOS, os.UserHomeDir, filepath.Join)
if err != nil {
return nil, err
return config, err
}

var config = koanf.New(".")
if err := config.Load(file.Provider(configPath), toml.Parser()); err != nil {
var k = koanf.New(".")
if err := k.Load(file.Provider(configPath), toml.Parser()); err != nil {
if strings.Contains(err.Error(), "no such file or directory") {
return nil, ErrConfigMissing
return config, ErrConfigMissing
} else {
return nil, err
return config, err
}
}

err = k.Unmarshal("", &config)
if err != nil {
return config, err
}

return config, nil
}

// UpdateConfig updates the current config.
// It will be created if it hasn't already been created.
func UpdateConfig(update updateConfigFn) error {
config, err := GetConfig()
if err != nil && !errors.Is(err, ErrConfigMissing) {
return err
}

if errors.Is(err, ErrConfigMissing) {
folder, err := getFolderPath(runtime.GOOS, os.UserHomeDir, filepath.Join)
if err != nil {
return err
}

err = os.MkdirAll(folder, os.ModePerm)
if err != nil {
return err
}
}

update(&config)

var k = koanf.New(".")
err = k.Load(structs.Provider(config, "koanf"), nil)
if err != nil {
return err
}

buffer, err := k.Marshal(toml.Parser())
if err != nil {
return err
}

configPath, err := getConfigPath(runtime.GOOS, os.UserHomeDir, filepath.Join)
if err != nil {
return err
}

handle, err := os.Create(configPath)
if err != nil {
return err
}
defer handle.Close()

_, err = handle.Write(buffer)
if err != nil {
return err
}

return nil
}

// getDatabasePath gets the path to the bookmarks database.
// The path will be (in order of precedence):
// 1) The inputted path
Expand Down
4 changes: 3 additions & 1 deletion lib/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@ go 1.20
require (
github.com/blockloop/scan/v2 v2.5.0
github.com/google/uuid v1.4.0
github.com/knadh/koanf/parsers/toml v0.1.0
github.com/knadh/koanf/providers/file v0.1.0
github.com/knadh/koanf/v2 v2.0.1
github.com/mattn/go-sqlite3 v1.14.18
github.com/nullism/bqb v1.7.1
github.com/pressly/goose/v3 v3.15.1
github.com/samber/lo v1.38.1
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0
github.com/knadh/koanf/parsers/toml v0.1.0
github.com/knadh/koanf/providers/structs v0.1.0
)

require (
github.com/fatih/structs v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/knadh/koanf/maps v0.1.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions lib/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ github.com/blockloop/scan/v2 v2.5.0 h1:/yNcCwftYn3wf5BJsJFO9E9P48l45wThdUnM3WcDF
github.com/blockloop/scan/v2 v2.5.0/go.mod h1:OFYyMocUdRW3DUWehPI/fSsnpNMUNiyUaYXRMY5NMIY=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
Expand All @@ -13,6 +15,8 @@ github.com/knadh/koanf/parsers/toml v0.1.0 h1:S2hLqS4TgWZYj4/7mI5m1CQQcWurxUz6OD
github.com/knadh/koanf/parsers/toml v0.1.0/go.mod h1:yUprhq6eo3GbyVXFFMdbfZSo928ksS+uo0FFqNMnO18=
github.com/knadh/koanf/providers/file v0.1.0 h1:fs6U7nrV58d3CFAFh8VTde8TM262ObYf3ODrc//Lp+c=
github.com/knadh/koanf/providers/file v0.1.0/go.mod h1:rjJ/nHQl64iYCtAW2QQnF0eSmDEX/YZ/eNFj5yR6BvA=
github.com/knadh/koanf/providers/structs v0.1.0 h1:wJRteCNn1qvLtE5h8KQBvLJovidSdntfdyIbbCzEyE0=
github.com/knadh/koanf/providers/structs v0.1.0/go.mod h1:sw2YZ3txUcqA3Z27gPlmmBzWn1h8Nt9O6EP/91MkcWE=
github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g=
github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
Expand Down
7 changes: 4 additions & 3 deletions lib/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package lib
import (
"database/sql"
"embed"
"errors"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -130,12 +131,12 @@ type connectDBFn func(inputPath NullString) (*sql.DB, error)

// connectDB returns a connection to the bookmarks database.
func connectDB(inputPath NullString) (*sql.DB, error) {
configPath, err := GetDBPathConfig()
if err != nil {
config, err := GetConfig()
if err != nil && !errors.Is(err, ErrConfigMissing) {
return nil, err
}

dbLocation, err := getDatabasePath(inputPath, configPath, runtime.GOOS, os.MkdirAll, os.UserHomeDir, filepath.Join)
dbLocation, err := getDatabasePath(inputPath, config.DB, runtime.GOOS, os.MkdirAll, os.UserHomeDir, filepath.Join)
if err != nil {
return nil, fmt.Errorf("%w: %w", ErrUnexpected, err)
}
Expand Down
Loading