[fix] Testing fixes

- sqlite error handling and wrapping
- more responsive commands
- database updates
This commit is contained in:
jake 2025-06-19 17:23:17 -04:00
parent 0d7fbffaf6
commit 7ff43c82c2
15 changed files with 112 additions and 40 deletions

View File

@ -16,6 +16,7 @@ var addCmd = &cobra.Command{
Use: "add", Use: "add",
Example: "mctl command add", Example: "mctl command add",
Short: "Saves a new command to the database", Short: "Saves a new command to the database",
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
@ -40,7 +41,13 @@ var addCmd = &cobra.Command{
cobra.CheckErr(err) cobra.CheckErr(err)
err = db.SaveCmd(cfgname, cfgcmd) err = db.SaveCmd(cfgname, cfgcmd)
if err.Error() == ErrInit {
fmt.Println(ErrInitRsp)
return
}
cobra.CheckErr(err) cobra.CheckErr(err)
fmt.Println("Command saved")
}, },
} }

View File

@ -7,6 +7,11 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
const (
ErrInit = "sqlite3: SQL logic error: no such table: commands"
ErrInitRsp = "The 'init' command must be run before mctl can be used"
)
// CommandCmd is such a cool name lol // CommandCmd is such a cool name lol
var CommandCmd = &cobra.Command{ var CommandCmd = &cobra.Command{
Use: "command", Use: "command",

View File

@ -15,15 +15,20 @@ var deleteCmd = &cobra.Command{
Use: "delete", Use: "delete",
Example: "mctl command delete <name>", Example: "mctl command delete <name>",
Short: "Deletes a command from the database", Short: "Deletes a command from the database",
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
db, err := database.New() db, err := database.New()
cobra.CheckErr(err) cobra.CheckErr(err)
defer db.Close() defer db.Close()
err = db.DeleteCmd(args[0]) err = db.DeleteCmd(args[0])
if err.Error() == ErrInit {
fmt.Println(ErrInitRsp)
return
}
cobra.CheckErr(err) cobra.CheckErr(err)
fmt.Println("Command deleted!") fmt.Println("Command deleted")
}, },
PreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 { if len(args) == 0 {

View File

@ -22,6 +22,7 @@ var runCmd = &cobra.Command{
Example: "mctl command run -s <server> <command> args...", Example: "mctl command run -s <server> <command> args...",
Short: "Runs a saved command on a server", Short: "Runs a saved command on a server",
Long: `Runs the named command with the provided args on the default/active server unless -s is specified`, Long: `Runs the named command with the provided args on the default/active server unless -s is specified`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cname := args[0] cname := args[0]
@ -32,6 +33,10 @@ var runCmd = &cobra.Command{
defer db.Close() defer db.Close()
crun, err := db.GetCmd(cname) crun, err := db.GetCmd(cname)
if err.Error() == ErrInit {
fmt.Println(ErrInitRsp)
return nil
}
if err != nil { if err != nil {
return err return err
} }

View File

@ -14,12 +14,17 @@ var viewCmd = &cobra.Command{
Use: "view", Use: "view",
Example: "mctl command view", Example: "mctl command view",
Short: "view all saved commands", Short: "view all saved commands",
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
db, err := database.New() db, err := database.New()
cobra.CheckErr(err) cobra.CheckErr(err)
defer db.Close() defer db.Close()
ts, err := db.GetAllCmds() ts, err := db.GetAllCmds()
if err.Error() == ErrInit {
fmt.Println(ErrInitRsp)
return
}
cobra.CheckErr(err) cobra.CheckErr(err)
for _, s := range ts { for _, s := range ts {

View File

@ -9,6 +9,7 @@ import (
"os" "os"
"strings" "strings"
"code.jakeyoungdev.com/jake/mctl/cmd/command"
"code.jakeyoungdev.com/jake/mctl/database" "code.jakeyoungdev.com/jake/mctl/database"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -19,6 +20,7 @@ var destroyCmd = &cobra.Command{
Short: "clears all configuration", Short: "clears all configuration",
Long: `clear all data and drop database tables, this will delete all previously saved data and the 'inti' command Long: `clear all data and drop database tables, this will delete all previously saved data and the 'inti' command
must be run again before use`, must be run again before use`,
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
fmt.Printf("Are you sure you want to destroy your config? (yes|no): ") fmt.Printf("Are you sure you want to destroy your config? (yes|no): ")
@ -29,6 +31,10 @@ var destroyCmd = &cobra.Command{
defer db.Close() defer db.Close()
err = db.Destroy() err = db.Destroy()
if err.Error() == command.ErrInit {
fmt.Println(command.ErrInitRsp)
return
}
cobra.CheckErr(err) cobra.CheckErr(err)
fmt.Println("Configuration is cleared, the 'init' command must be run again.") fmt.Println("Configuration is cleared, the 'init' command must be run again.")

View File

@ -12,6 +12,7 @@ var initCmd = &cobra.Command{
Use: "init", Use: "init",
Example: "mctl init", Example: "mctl init",
Short: "initializes the database tables, must be run before mctl can be used", Short: "initializes the database tables, must be run before mctl can be used",
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
db, err := database.New() db, err := database.New()
cobra.CheckErr(err) cobra.CheckErr(err)

View File

@ -9,7 +9,6 @@ import (
"os" "os"
"code.jakeyoungdev.com/jake/mctl/client" "code.jakeyoungdev.com/jake/mctl/client"
"code.jakeyoungdev.com/jake/mctl/database"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -26,10 +25,6 @@ var loginCmd = &cobra.Command{
Long: `Login to default server and enter command loop. The default server Long: `Login to default server and enter command loop. The default server
is used unless the server flag is set`, is used unless the server flag is set`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
db, err := database.New()
cobra.CheckErr(err)
defer db.Close()
cli, err := client.New(server) cli, err := client.New(server)
cobra.CheckErr(err) cobra.CheckErr(err)
defer cli.Close() defer cli.Close()

View File

@ -15,12 +15,17 @@ var activeCmd = &cobra.Command{
Use: "active", Use: "active",
Example: "mctl server active <server>", Example: "mctl server active <server>",
Short: "sets the active server to run commands on", Short: "sets the active server to run commands on",
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
db, err := database.New() db, err := database.New()
cobra.CheckErr(err) cobra.CheckErr(err)
defer db.Close() defer db.Close()
err = db.SetActiveServer(args[0]) err = db.SetActiveServer(args[0])
if err.Error() == ErrInit {
fmt.Println(ErrInitRsp)
return
}
cobra.CheckErr(err) cobra.CheckErr(err)
fmt.Println("Active server updated") fmt.Println("Active server updated")

View File

@ -21,6 +21,7 @@ var addCmd = &cobra.Command{
Example: "mctl server add", Example: "mctl server add",
Short: "Saves a new server configuration", Short: "Saves a new server configuration",
Long: `Saves server address, alias, port, and password to the database.`, Long: `Saves server address, alias, port, and password to the database.`,
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
@ -62,6 +63,10 @@ var addCmd = &cobra.Command{
Port: fp, Port: fp,
Password: base64.StdEncoding.EncodeToString(ps), Password: base64.StdEncoding.EncodeToString(ps),
}) })
if err.Error() == ErrInit {
fmt.Println(ErrInitRsp)
return
}
cobra.CheckErr(err) cobra.CheckErr(err)
fmt.Println("Server saved") fmt.Println("Server saved")

View File

@ -5,6 +5,7 @@ package server
import ( import (
"errors" "errors"
"fmt"
"code.jakeyoungdev.com/jake/mctl/database" "code.jakeyoungdev.com/jake/mctl/database"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -14,13 +15,20 @@ var deleteCmd = &cobra.Command{
Use: "delete", Use: "delete",
Example: "mctl server delete <server>", Example: "mctl server delete <server>",
Short: "deletes a server from the database", Short: "deletes a server from the database",
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
db, err := database.New() db, err := database.New()
cobra.CheckErr(err) cobra.CheckErr(err)
defer db.Close() defer db.Close()
err = db.DeleteServer(args[0]) err = db.DeleteServer(args[0])
if err.Error() == ErrInit {
fmt.Println(ErrInitRsp)
return
}
cobra.CheckErr(err) cobra.CheckErr(err)
fmt.Println("Server deleted")
}, },
PreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 { if len(args) == 0 {

View File

@ -7,6 +7,11 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
const (
ErrInit = "sqlite3: SQL logic error: no such table: servers"
ErrInitRsp = "The 'init' command must be run before mctl can be used"
)
var ServerCmd = &cobra.Command{ var ServerCmd = &cobra.Command{
Use: "server", Use: "server",
Example: "mctl server <subcommand>", Example: "mctl server <subcommand>",

View File

@ -18,6 +18,7 @@ var updateCmd = &cobra.Command{
Use: "update", Use: "update",
Example: "mctl server update <name>", Example: "mctl server update <name>",
Short: "updates a saved servers password in the database", Short: "updates a saved servers password in the database",
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
//read in password using term to keep it secure/hidden from bash history //read in password using term to keep it secure/hidden from bash history
fmt.Printf("Password: ") fmt.Printf("Password: ")
@ -29,6 +30,10 @@ var updateCmd = &cobra.Command{
defer db.Close() defer db.Close()
err = db.UpdateServer(args[0], base64.StdEncoding.EncodeToString(ps)) err = db.UpdateServer(args[0], base64.StdEncoding.EncodeToString(ps))
if err.Error() == ErrInit {
fmt.Println(ErrInitRsp)
return
}
cobra.CheckErr(err) cobra.CheckErr(err)
fmt.Printf("%s password updated!", args[0]) fmt.Printf("%s password updated!", args[0])

View File

@ -14,12 +14,17 @@ var viewCmd = &cobra.Command{
Use: "view", Use: "view",
Example: "mctl server view", Example: "mctl server view",
Short: "view all saved servers", Short: "view all saved servers",
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
db, err := database.New() db, err := database.New()
cobra.CheckErr(err) cobra.CheckErr(err)
defer db.Close() defer db.Close()
ts, err := db.GetAllServers() ts, err := db.GetAllServers()
if err.Error() == ErrInit {
fmt.Println(ErrInitRsp)
return
}
cobra.CheckErr(err) cobra.CheckErr(err)
for _, s := range ts { for _, s := range ts {

View File

@ -2,6 +2,8 @@ package database
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"os" "os"
"time" "time"
@ -13,8 +15,7 @@ import (
) )
/* /*
all sqlx methods for CRUD functionalities of commands and servers. All database methods should use the internal all sqlx methods for CRUD functionalities of commands and servers.
methods query, exec, queryrow -- these wrapper functions handle timeouts and other configuration
*/ */
const ( const (
@ -123,6 +124,9 @@ func (d *database) GetCmd(name string) (string, error) {
ctx, cl := d.timeout() ctx, cl := d.timeout()
defer cl() defer cl()
err := d.QueryRowxContext(ctx, query, name).Scan(&cmd) err := d.QueryRowxContext(ctx, query, name).Scan(&cmd)
if errors.Is(err, sql.ErrNoRows) {
return "", errors.New("Command not found")
}
if err != nil { if err != nil {
return "", err return "", err
} }
@ -222,6 +226,9 @@ func (d *database) GetServer(name string) (model.Server, error) {
defer cancel() defer cancel()
var s model.Server var s model.Server
err := d.QueryRowxContext(ctx, query, name).StructScan(&s) err := d.QueryRowxContext(ctx, query, name).StructScan(&s)
if errors.Is(err, sql.ErrNoRows) {
return model.Server{}, errors.New("Server not found")
}
if err != nil { if err != nil {
return model.Server{}, err return model.Server{}, err
} }
@ -246,6 +253,9 @@ func (d *database) GetActiveServer() (model.Server, error) {
defer cancel() defer cancel()
var s model.Server var s model.Server
err := d.QueryRowxContext(ctx, query).StructScan(&s) err := d.QueryRowxContext(ctx, query).StructScan(&s)
if errors.Is(err, sql.ErrNoRows) {
return s, errors.New("No active server set")
}
return s, err return s, err
} }