From 9449a29fb16b80b4933d9ec2d92ebbf61d95db8f Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Sat, 9 Dec 2023 22:59:33 +0100 Subject: [PATCH] service auth, edit and delete now all support --service flag If a service name is given, this will be used. If not the user is prompted to select one. --- cmd/service_add.go | 4 ++-- cmd/service_auth.go | 12 +++--------- cmd/service_delete.go | 13 ++----------- cmd/service_edit.go | 13 ++----------- internal/backends/backends.go | 10 +++------- internal/backends/backends_test.go | 6 +++--- internal/cli/common.go | 6 ++---- internal/cli/services.go | 10 +++++++++- internal/config/services.go | 6 +++--- 9 files changed, 29 insertions(+), 51 deletions(-) diff --git a/cmd/service_add.go b/cmd/service_add.go index 64c905b..634a511 100644 --- a/cmd/service_add.go +++ b/cmd/service_add.go @@ -46,8 +46,8 @@ var serviceAddCmd = &cobra.Command{ Label: i18n.Tr("Service name"), Default: backend, Validate: func(s string) error { - srv, _ := config.GetService(s) - if srv != nil { + _, err := config.GetService(s) + if err == nil { return errors.New(i18n.Tr("a service with this name already exists")) } return config.ValidateKey(s) diff --git a/cmd/service_auth.go b/cmd/service_auth.go index 12da9dd..91125ad 100644 --- a/cmd/service_auth.go +++ b/cmd/service_auth.go @@ -17,7 +17,6 @@ Scotty. If not, see . package cmd import ( - "errors" "fmt" "os" @@ -42,11 +41,8 @@ var serviceAuthCmd = &cobra.Command{ Authentication is always done per configured service. That means you can have multiple services using the same backend but different authentication.`, Run: func(cmd *cobra.Command, args []string) { - serviceConfig := cli.GetServiceConfigFromFlag(cmd, "service") - if serviceConfig == nil { - err := errors.New(i18n.Tr("failed loading service configuration")) - cobra.CheckErr(err) - } + serviceConfig, err := cli.SelectService(cmd) + cobra.CheckErr(err) backend, err := backends.ResolveBackend[models.OAuth2Authenticator](serviceConfig) cobra.CheckErr(err) @@ -97,7 +93,5 @@ multiple services using the same backend but different authentication.`, func init() { serviceCmd.AddCommand(serviceAuthCmd) - - serviceAuthCmd.Flags().StringP("service", "s", "", "service configuration (required)") - serviceAuthCmd.MarkFlagRequired("service") + serviceAuthCmd.Flags().StringP("service", "s", "", "service configuration") } diff --git a/cmd/service_delete.go b/cmd/service_delete.go index 1d5c0ba..3a2738d 100644 --- a/cmd/service_delete.go +++ b/cmd/service_delete.go @@ -34,7 +34,7 @@ var serviceDeleteCmd = &cobra.Command{ Short: "Delete existing service configuration", Long: `Delete an existing service from the configuration file.`, Run: func(cmd *cobra.Command, args []string) { - service, err := cli.SelectService() + service, err := cli.SelectService(cmd) cobra.CheckErr(err) // Prompt for deletion @@ -58,14 +58,5 @@ var serviceDeleteCmd = &cobra.Command{ func init() { serviceCmd.AddCommand(serviceDeleteCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // serviceDeleteCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // serviceDeleteCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + serviceDeleteCmd.Flags().StringP("service", "s", "", "service configuration") } diff --git a/cmd/service_edit.go b/cmd/service_edit.go index 873fe76..abd790b 100644 --- a/cmd/service_edit.go +++ b/cmd/service_edit.go @@ -34,7 +34,7 @@ var serviceEditCmd = &cobra.Command{ Short: "Edit existing service configuration", Long: `Edit an existing service in the configuration file.`, Run: func(cmd *cobra.Command, args []string) { - service, err := cli.SelectService() + service, err := cli.SelectService(cmd) cobra.CheckErr(err) // Select backend @@ -55,14 +55,5 @@ var serviceEditCmd = &cobra.Command{ func init() { serviceCmd.AddCommand(serviceEditCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // serviceEditCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // serviceEditCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + serviceEditCmd.Flags().StringP("service", "s", "", "service configuration") } diff --git a/internal/backends/backends.go b/internal/backends/backends.go index a970cf5..f257f3d 100644 --- a/internal/backends/backends.go +++ b/internal/backends/backends.go @@ -63,12 +63,8 @@ func (l BackendList) Swap(i, j int) { type Capability = string -func ResolveBackend[T interface{}](config *config.ServiceConfig) (T, error) { +func ResolveBackend[T interface{}](config config.ServiceConfig) (T, error) { var result T - if config == nil { - err := fmt.Errorf("config must not be nil") - return result, err - } backend, err := backendWithConfig(config) if err != nil { return result, err @@ -120,12 +116,12 @@ var knownBackends = map[string]func() models.Backend{ "subsonic": func() models.Backend { return &subsonic.SubsonicApiBackend{} }, } -func backendWithConfig(config *config.ServiceConfig) (models.Backend, error) { +func backendWithConfig(config config.ServiceConfig) (models.Backend, error) { backend, err := BackendByName(config.Backend) if err != nil { return nil, err } - return backend.FromConfig(config), nil + return backend.FromConfig(&config), nil } func ImplementsInterface[T interface{}](backend *models.Backend) (bool, string) { diff --git a/internal/backends/backends_test.go b/internal/backends/backends_test.go index 0e57616..ee71e6e 100644 --- a/internal/backends/backends_test.go +++ b/internal/backends/backends_test.go @@ -42,7 +42,7 @@ func TestResolveBackend(t *testing.T) { c := viper.New() c.Set("backend", "dump") service := config.NewServiceConfig("test", c) - backend, err := backends.ResolveBackend[models.ListensImport](&service) + backend, err := backends.ResolveBackend[models.ListensImport](service) assert.NoError(t, err) assert.IsType(t, &dump.DumpBackend{}, backend) } @@ -51,7 +51,7 @@ func TestResolveBackendUnknown(t *testing.T) { c := viper.New() c.Set("backend", "foo") service := config.NewServiceConfig("test", c) - _, err := backends.ResolveBackend[models.ListensImport](&service) + _, err := backends.ResolveBackend[models.ListensImport](service) assert.EqualError(t, err, "unknown backend \"foo\"") } @@ -59,7 +59,7 @@ func TestResolveBackendInvalidInterface(t *testing.T) { c := viper.New() c.Set("backend", "dump") service := config.NewServiceConfig("test", c) - _, err := backends.ResolveBackend[models.ListensExport](&service) + _, err := backends.ResolveBackend[models.ListensExport](service) assert.EqualError(t, err, "backend dump does not implement ListensExport") } diff --git a/internal/cli/common.go b/internal/cli/common.go index 52b2360..6c8786a 100644 --- a/internal/cli/common.go +++ b/internal/cli/common.go @@ -20,11 +20,9 @@ import ( "go.uploadedlobster.com/scotty/internal/config" ) -func GetServiceConfigFromFlag(cmd *cobra.Command, flagName string) *config.ServiceConfig { +func GetServiceConfigFromFlag(cmd *cobra.Command, flagName string) (config.ServiceConfig, error) { name := cmd.Flag(flagName).Value.String() - config, err := config.GetService(name) - cobra.CheckErr(err) - return config + return config.GetService(name) } func getInt64FromFlag(cmd *cobra.Command, flagName string) (result int64) { diff --git a/internal/cli/services.go b/internal/cli/services.go index a8bd813..df27833 100644 --- a/internal/cli/services.go +++ b/internal/cli/services.go @@ -21,12 +21,20 @@ import ( "slices" "github.com/manifoldco/promptui" + "github.com/spf13/cobra" "go.uploadedlobster.com/scotty/internal/backends" "go.uploadedlobster.com/scotty/internal/config" "go.uploadedlobster.com/scotty/internal/i18n" ) -func SelectService() (config.ServiceConfig, error) { +func SelectService(cmd *cobra.Command) (config.ServiceConfig, error) { + // First try to load service from command line flag + service, err := GetServiceConfigFromFlag(cmd, "service") + if err == nil { + return service, nil + } + + // Prompt the user to select a service services := config.AllServicesAsList() if len(services) == 0 { err := errors.New(i18n.Tr("no existing service configurations")) diff --git a/internal/config/services.go b/internal/config/services.go index 2895cb2..783adc4 100644 --- a/internal/config/services.go +++ b/internal/config/services.go @@ -116,13 +116,13 @@ func AllServicesAsList() ServiceList { return list } -func GetService(name string) (*ServiceConfig, error) { +func GetService(name string) (ServiceConfig, error) { key := "service." + name config := viper.Sub(key) if config != nil { service := NewServiceConfig(name, config) - return &service, nil + return service, nil } - return nil, fmt.Errorf(i18n.Tr("no service configuration \"%v\"", name)) + return ServiceConfig{}, fmt.Errorf(i18n.Tr("no service configuration \"%v\"", name)) }