From 04478cbbd13e7364fb11eb5fd4c6416bd15e5af2 Mon Sep 17 00:00:00 2001 From: Matt Low Date: Sat, 4 Nov 2023 19:58:48 +0000 Subject: [PATCH] Refactor store and config handling - Moved global `store` and `config` variables to cli.go - Add Fatal() function for outputting an error and exiting --- pkg/cli/cli.go | 14 ++++++++++++++ pkg/cli/cmd.go | 27 ++++++++------------------- pkg/cli/config.go | 14 +++++++------- pkg/cli/store.go | 15 +++++++-------- pkg/cli/util.go | 11 ++++++----- 5 files changed, 42 insertions(+), 39 deletions(-) create mode 100644 pkg/cli/cli.go diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go new file mode 100644 index 0000000..9e7fa26 --- /dev/null +++ b/pkg/cli/cli.go @@ -0,0 +1,14 @@ +package cli + +import ( + "fmt" + "os" +) + +var config = InitializeConfig() +var store = InitializeStore() + +func Fatal(format string, args ...any) { + fmt.Fprintf(os.Stderr, format, args...) + os.Exit(1) +} diff --git a/pkg/cli/cmd.go b/pkg/cli/cmd.go index 1d9e874..0b98deb 100644 --- a/pkg/cli/cmd.go +++ b/pkg/cli/cmd.go @@ -7,22 +7,11 @@ import ( "github.com/spf13/cobra" ) -var config = LoadConfig() -var store, storeError = InitializeStore() - -func checkStore() { - if storeError != nil { - fmt.Fprintf(os.Stderr, "Error establishing connection to store: %v\n", storeError) - os.Exit(1) - } -} - var rootCmd = &cobra.Command{ Use: "lm", Short: "Interact with Large Language Models", Long: `lm is a CLI tool to interact with OpenAI's GPT 3.5 and GPT 4.`, Run: func(cmd *cobra.Command, args []string) { - checkStore() // execute `lm ls` by default }, } @@ -83,13 +72,13 @@ var newCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { messageContents, err := InputFromEditor("# What would you like to say?", "message.*.md") if err != nil { - fmt.Fprintf(os.Stderr, "Error receiving message input: %v\n", err) - os.Exit(1) + Fatal("Failed to get input: %v\n", err) + return } if messageContents == "" { - fmt.Fprintf(os.Stderr, "No message was provided.\n") - os.Exit(1) + Fatal("No message was provided.\n") + return } fmt.Printf("> %s\n", messageContents) @@ -103,8 +92,8 @@ var newCmd = &cobra.Command{ err = CreateChatCompletionStream("You are a helpful assistant.", messages, os.Stdout) if err != nil { - fmt.Fprintf(os.Stderr, "An error occured: %v\n", err) - os.Exit(1) + Fatal("%v\n", err) + return } fmt.Println() @@ -125,8 +114,8 @@ var promptCmd = &cobra.Command{ err := CreateChatCompletionStream("You are a helpful assistant.", messages, os.Stdout) if err != nil { - fmt.Fprintf(os.Stderr, "An error occured: %v\n", err) - os.Exit(1) + Fatal("%v\n", err) + return } fmt.Println() diff --git a/pkg/cli/config.go b/pkg/cli/config.go index 21c3ca7..fb9e5b8 100644 --- a/pkg/cli/config.go +++ b/pkg/cli/config.go @@ -29,7 +29,7 @@ func getConfigDir() string { return configDir } -func LoadConfig() *Config { +func InitializeConfig() *Config { configFile := filepath.Join(getConfigDir(), "config.yaml") configBytes, err := os.ReadFile(configFile) @@ -40,8 +40,8 @@ func LoadConfig() *Config { file, err := os.Create(configFile) if err != nil { - fmt.Fprintf(os.Stderr, "Could not open config file for writing: %v", err) - os.Exit(1) + Fatal("Could not open config file for writing: %v", err) + return nil } fmt.Printf("Writing default configuration to: %s\n", configFile) @@ -50,12 +50,12 @@ func LoadConfig() *Config { _, err = file.Write(bytes) if err != nil { - fmt.Fprintf(os.Stderr, "Could not save default configuratoin: %v", err) - os.Exit(1) + Fatal("Could not save default configuratoin: %v", err) + return nil } } else if err != nil { - fmt.Fprintf(os.Stderr, "Could not read config file: %v", err) - os.Exit(1) + Fatal("Could not read config file: %v", err) + return nil } config := &Config{} diff --git a/pkg/cli/store.go b/pkg/cli/store.go index 500da1e..038c2e6 100644 --- a/pkg/cli/store.go +++ b/pkg/cli/store.go @@ -44,11 +44,12 @@ func getDataDir() string { return dataDir } -func InitializeStore() (*Store, error) { +func InitializeStore() *Store { databaseFile := filepath.Join(getDataDir(), "conversations.db") db, err := gorm.Open(sqlite.Open(databaseFile), &gorm.Config{}) if err != nil { - return nil, err + Fatal("Error establishing connection to store: %v\n", err) + return nil } models := []any{ @@ -59,15 +60,13 @@ func InitializeStore() (*Store, error) { for _, x := range(models) { err := db.AutoMigrate(x) if err != nil { - return nil, err + Fatal("Could not perform database migrations: %v\n", err) + return nil } } - _sqids, _ := sqids.New(sqids.Options{ - MinLength: 4, - }) - - return &Store{db: db, sqids: _sqids}, nil + _sqids, _ := sqids.New(sqids.Options{MinLength: 4}) + return &Store{db, _sqids} } func (s *Store) SaveConversation(conversation *Conversation) error { diff --git a/pkg/cli/util.go b/pkg/cli/util.go index 641449b..34b3de3 100644 --- a/pkg/cli/util.go +++ b/pkg/cli/util.go @@ -5,11 +5,12 @@ import ( "os/exec" ) -// InputFromEditor retrieves user input by opening an editor on a temporary -// file. Once the editor closes, the contents of the temporary file are -// returned. If the contents exactly match the placeholder (no edits to the -// file were made), then an empty string is returned. -// Example patten: message.*.md +// InputFromEditor retrieves user input by opening an editor (one specified by +// $EDITOR or 'vim' if $EDITOR is not set) on a temporary file. Once the editor +// closes, the contents of the file are read and the file is deleted. If the +// contents of the file exactly match the value of placeholder (no edits to the +// file were made), then an empty string is returned. Otherwise, the contents +// are returned. Example patten: message.*.md func InputFromEditor(placeholder string, pattern string) (string, error) { msgFile, _ := os.CreateTemp("/tmp", pattern) defer os.Remove(msgFile.Name())