mirror of
https://git.sr.ht/~phw/scotty
synced 2025-04-18 11:09:29 +02:00
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.
This commit is contained in:
parent
c21715d36b
commit
9449a29fb1
9 changed files with 29 additions and 51 deletions
|
@ -46,8 +46,8 @@ var serviceAddCmd = &cobra.Command{
|
||||||
Label: i18n.Tr("Service name"),
|
Label: i18n.Tr("Service name"),
|
||||||
Default: backend,
|
Default: backend,
|
||||||
Validate: func(s string) error {
|
Validate: func(s string) error {
|
||||||
srv, _ := config.GetService(s)
|
_, err := config.GetService(s)
|
||||||
if srv != nil {
|
if err == nil {
|
||||||
return errors.New(i18n.Tr("a service with this name already exists"))
|
return errors.New(i18n.Tr("a service with this name already exists"))
|
||||||
}
|
}
|
||||||
return config.ValidateKey(s)
|
return config.ValidateKey(s)
|
||||||
|
|
|
@ -17,7 +17,6 @@ Scotty. If not, see <https://www.gnu.org/licenses/>.
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -42,11 +41,8 @@ var serviceAuthCmd = &cobra.Command{
|
||||||
Authentication is always done per configured service. That means you can have
|
Authentication is always done per configured service. That means you can have
|
||||||
multiple services using the same backend but different authentication.`,
|
multiple services using the same backend but different authentication.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
serviceConfig := cli.GetServiceConfigFromFlag(cmd, "service")
|
serviceConfig, err := cli.SelectService(cmd)
|
||||||
if serviceConfig == nil {
|
cobra.CheckErr(err)
|
||||||
err := errors.New(i18n.Tr("failed loading service configuration"))
|
|
||||||
cobra.CheckErr(err)
|
|
||||||
}
|
|
||||||
backend, err := backends.ResolveBackend[models.OAuth2Authenticator](serviceConfig)
|
backend, err := backends.ResolveBackend[models.OAuth2Authenticator](serviceConfig)
|
||||||
cobra.CheckErr(err)
|
cobra.CheckErr(err)
|
||||||
|
|
||||||
|
@ -97,7 +93,5 @@ multiple services using the same backend but different authentication.`,
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
serviceCmd.AddCommand(serviceAuthCmd)
|
serviceCmd.AddCommand(serviceAuthCmd)
|
||||||
|
serviceAuthCmd.Flags().StringP("service", "s", "", "service configuration")
|
||||||
serviceAuthCmd.Flags().StringP("service", "s", "", "service configuration (required)")
|
|
||||||
serviceAuthCmd.MarkFlagRequired("service")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ var serviceDeleteCmd = &cobra.Command{
|
||||||
Short: "Delete existing service configuration",
|
Short: "Delete existing service configuration",
|
||||||
Long: `Delete an existing service from the configuration file.`,
|
Long: `Delete an existing service from the configuration file.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
service, err := cli.SelectService()
|
service, err := cli.SelectService(cmd)
|
||||||
cobra.CheckErr(err)
|
cobra.CheckErr(err)
|
||||||
|
|
||||||
// Prompt for deletion
|
// Prompt for deletion
|
||||||
|
@ -58,14 +58,5 @@ var serviceDeleteCmd = &cobra.Command{
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
serviceCmd.AddCommand(serviceDeleteCmd)
|
serviceCmd.AddCommand(serviceDeleteCmd)
|
||||||
|
serviceDeleteCmd.Flags().StringP("service", "s", "", "service configuration")
|
||||||
// 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")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ var serviceEditCmd = &cobra.Command{
|
||||||
Short: "Edit existing service configuration",
|
Short: "Edit existing service configuration",
|
||||||
Long: `Edit an existing service in the configuration file.`,
|
Long: `Edit an existing service in the configuration file.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
service, err := cli.SelectService()
|
service, err := cli.SelectService(cmd)
|
||||||
cobra.CheckErr(err)
|
cobra.CheckErr(err)
|
||||||
|
|
||||||
// Select backend
|
// Select backend
|
||||||
|
@ -55,14 +55,5 @@ var serviceEditCmd = &cobra.Command{
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
serviceCmd.AddCommand(serviceEditCmd)
|
serviceCmd.AddCommand(serviceEditCmd)
|
||||||
|
serviceEditCmd.Flags().StringP("service", "s", "", "service configuration")
|
||||||
// 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")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,12 +63,8 @@ func (l BackendList) Swap(i, j int) {
|
||||||
|
|
||||||
type Capability = string
|
type Capability = string
|
||||||
|
|
||||||
func ResolveBackend[T interface{}](config *config.ServiceConfig) (T, error) {
|
func ResolveBackend[T interface{}](config config.ServiceConfig) (T, error) {
|
||||||
var result T
|
var result T
|
||||||
if config == nil {
|
|
||||||
err := fmt.Errorf("config must not be nil")
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
backend, err := backendWithConfig(config)
|
backend, err := backendWithConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
|
@ -120,12 +116,12 @@ var knownBackends = map[string]func() models.Backend{
|
||||||
"subsonic": func() models.Backend { return &subsonic.SubsonicApiBackend{} },
|
"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)
|
backend, err := BackendByName(config.Backend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return backend.FromConfig(config), nil
|
return backend.FromConfig(&config), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ImplementsInterface[T interface{}](backend *models.Backend) (bool, string) {
|
func ImplementsInterface[T interface{}](backend *models.Backend) (bool, string) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ func TestResolveBackend(t *testing.T) {
|
||||||
c := viper.New()
|
c := viper.New()
|
||||||
c.Set("backend", "dump")
|
c.Set("backend", "dump")
|
||||||
service := config.NewServiceConfig("test", c)
|
service := config.NewServiceConfig("test", c)
|
||||||
backend, err := backends.ResolveBackend[models.ListensImport](&service)
|
backend, err := backends.ResolveBackend[models.ListensImport](service)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.IsType(t, &dump.DumpBackend{}, backend)
|
assert.IsType(t, &dump.DumpBackend{}, backend)
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ func TestResolveBackendUnknown(t *testing.T) {
|
||||||
c := viper.New()
|
c := viper.New()
|
||||||
c.Set("backend", "foo")
|
c.Set("backend", "foo")
|
||||||
service := config.NewServiceConfig("test", c)
|
service := config.NewServiceConfig("test", c)
|
||||||
_, err := backends.ResolveBackend[models.ListensImport](&service)
|
_, err := backends.ResolveBackend[models.ListensImport](service)
|
||||||
assert.EqualError(t, err, "unknown backend \"foo\"")
|
assert.EqualError(t, err, "unknown backend \"foo\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ func TestResolveBackendInvalidInterface(t *testing.T) {
|
||||||
c := viper.New()
|
c := viper.New()
|
||||||
c.Set("backend", "dump")
|
c.Set("backend", "dump")
|
||||||
service := config.NewServiceConfig("test", c)
|
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")
|
assert.EqualError(t, err, "backend dump does not implement ListensExport")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,9 @@ import (
|
||||||
"go.uploadedlobster.com/scotty/internal/config"
|
"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()
|
name := cmd.Flag(flagName).Value.String()
|
||||||
config, err := config.GetService(name)
|
return config.GetService(name)
|
||||||
cobra.CheckErr(err)
|
|
||||||
return config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInt64FromFlag(cmd *cobra.Command, flagName string) (result int64) {
|
func getInt64FromFlag(cmd *cobra.Command, flagName string) (result int64) {
|
||||||
|
|
|
@ -21,12 +21,20 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"github.com/manifoldco/promptui"
|
"github.com/manifoldco/promptui"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
"go.uploadedlobster.com/scotty/internal/backends"
|
"go.uploadedlobster.com/scotty/internal/backends"
|
||||||
"go.uploadedlobster.com/scotty/internal/config"
|
"go.uploadedlobster.com/scotty/internal/config"
|
||||||
"go.uploadedlobster.com/scotty/internal/i18n"
|
"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()
|
services := config.AllServicesAsList()
|
||||||
if len(services) == 0 {
|
if len(services) == 0 {
|
||||||
err := errors.New(i18n.Tr("no existing service configurations"))
|
err := errors.New(i18n.Tr("no existing service configurations"))
|
||||||
|
|
|
@ -116,13 +116,13 @@ func AllServicesAsList() ServiceList {
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetService(name string) (*ServiceConfig, error) {
|
func GetService(name string) (ServiceConfig, error) {
|
||||||
key := "service." + name
|
key := "service." + name
|
||||||
config := viper.Sub(key)
|
config := viper.Sub(key)
|
||||||
if config != nil {
|
if config != nil {
|
||||||
service := NewServiceConfig(name, config)
|
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))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue