Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into update-deps-and-go
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerrit91 committed Sep 26, 2024
2 parents 8f4b626 + 25397a6 commit 294a01f
Show file tree
Hide file tree
Showing 9 changed files with 353 additions and 98 deletions.
82 changes: 60 additions & 22 deletions pkg/genericcli/cmds.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package genericcli

import (
"errors"
"fmt"
"io"
"strings"
Expand Down Expand Up @@ -47,7 +48,10 @@ func OnlyCmds(cmds ...DefaultCmd) map[DefaultCmd]bool {

// CmdsConfig provides the configuration for the default commands.
type CmdsConfig[C any, U any, R any] struct {
// GenericCLI is the generic CLI used by the cobra commands. this uses only single positional arguments. if you have multiple, use multi arg generic cli.
GenericCLI *GenericCLI[C, U, R]
// MultiArgGenericCLI is the generic CLI used by the cobra commands. this can use n positional arguments.
MultiArgGenericCLI *MultiArgGenericCLI[C, U, R]

// OnlyCmds defines which default commands to include from the generic cli. if empty, all default commands will be added.
OnlyCmds map[DefaultCmd]bool
Expand All @@ -61,6 +65,9 @@ type CmdsConfig[C any, U any, R any] struct {
// Aliases provides additional aliases for the root cmd.
Aliases []string

// Args defines how many arguments are being used for the entity's id and how they are named, this defaults to ["id"]
Args []string

// DescribePrinter is the printer that is used for describing the entity. It's a function because printers potentially get initialized later in the game.
DescribePrinter func() printers.Printer
// ListPrinter is the printer that is used for listing multiple entities. It's a function because printers potentially get initialized later in the game.
Expand Down Expand Up @@ -98,8 +105,14 @@ func NewCmds[C any, U any, R any](c *CmdsConfig[C, U, R], additionalCmds ...*cob
if len(c.OnlyCmds) == 0 {
c.OnlyCmds = allCmds()
}
if len(c.Args) == 0 {
c.Args = []string{"id"}
}
if c.GenericCLI != nil {
c.MultiArgGenericCLI = c.GenericCLI.multiCLI
}
if c.Sorter != nil {
c.GenericCLI = c.GenericCLI.WithSorter(c.Sorter)
c.MultiArgGenericCLI = c.MultiArgGenericCLI.WithSorter(c.Sorter)
}

Must(c.validate())
Expand All @@ -124,7 +137,7 @@ func NewCmds[C any, U any, R any](c *CmdsConfig[C, U, R], additionalCmds ...*cob
return err
}

return c.GenericCLI.ListAndPrint(c.ListPrinter(), sortKeys...)
return c.MultiArgGenericCLI.ListAndPrint(c.ListPrinter(), sortKeys...)
},
}

Expand All @@ -140,17 +153,22 @@ func NewCmds[C any, U any, R any](c *CmdsConfig[C, U, R], additionalCmds ...*cob
}

if _, ok := c.OnlyCmds[DescribeCmd]; ok {
use := "describe"
for _, arg := range c.Args {
use += fmt.Sprintf(" <%s>", arg)
}

cmd := &cobra.Command{
Use: "describe <id>",
Use: use,
Aliases: []string{"get"},
Short: fmt.Sprintf("describes the %s", c.Singular),
RunE: func(cmd *cobra.Command, args []string) error {
id, err := GetExactlyOneArg(args)
id, err := GetExactlyNArgs(len(c.Args), args)
if err != nil {
return err
}

return c.GenericCLI.DescribeAndPrint(id, c.DescribePrinter())
return c.MultiArgGenericCLI.DescribeAndPrint(c.DescribePrinter(), id...)
},
ValidArgsFunction: c.ValidArgsFn,
}
Expand All @@ -173,12 +191,12 @@ func NewCmds[C any, U any, R any](c *CmdsConfig[C, U, R], additionalCmds ...*cob
return err
}

return c.GenericCLI.CreateAndPrint(rq, c.DescribePrinter())
return c.MultiArgGenericCLI.CreateAndPrint(rq, c.DescribePrinter())
}

p := c.evalBulkFlags()

return c.GenericCLI.CreateFromFileAndPrint(viper.GetString("file"), p())
return c.MultiArgGenericCLI.CreateFromFileAndPrint(viper.GetString("file"), p())
},
}

Expand All @@ -192,8 +210,15 @@ func NewCmds[C any, U any, R any](c *CmdsConfig[C, U, R], additionalCmds ...*cob
}

if _, ok := c.OnlyCmds[UpdateCmd]; ok {
use := "update"
if c.UpdateRequestFromCLI != nil {
for _, arg := range c.Args {
use += fmt.Sprintf(" <%s>", arg)
}
}

cmd := &cobra.Command{
Use: "update",
Use: use,
Short: fmt.Sprintf("updates the %s", c.Singular),
RunE: func(cmd *cobra.Command, args []string) error {
if c.UpdateRequestFromCLI != nil && !viper.IsSet("file") {
Expand All @@ -202,12 +227,12 @@ func NewCmds[C any, U any, R any](c *CmdsConfig[C, U, R], additionalCmds ...*cob
return err
}

return c.GenericCLI.UpdateAndPrint(rq, c.DescribePrinter())
return c.MultiArgGenericCLI.UpdateAndPrint(rq, c.DescribePrinter())
}

p := c.evalBulkFlags()

return c.GenericCLI.UpdateFromFileAndPrint(viper.GetString("file"), p())
return c.MultiArgGenericCLI.UpdateFromFileAndPrint(viper.GetString("file"), p())
},
ValidArgsFunction: c.ValidArgsFn,
}
Expand All @@ -222,23 +247,28 @@ func NewCmds[C any, U any, R any](c *CmdsConfig[C, U, R], additionalCmds ...*cob
}

if _, ok := c.OnlyCmds[DeleteCmd]; ok {
use := "delete"
for _, arg := range c.Args {
use += fmt.Sprintf(" <%s>", arg)
}

cmd := &cobra.Command{
Use: "delete <id>",
Use: use,
Short: fmt.Sprintf("deletes the %s", c.Singular),
Aliases: []string{"destroy", "rm", "remove"},
RunE: func(cmd *cobra.Command, args []string) error {
if !viper.IsSet("file") {
id, err := GetExactlyOneArg(args)
id, err := GetExactlyNArgs(len(c.Args), args)
if err != nil {
return err
}

return c.GenericCLI.DeleteAndPrint(id, c.DescribePrinter())
return c.MultiArgGenericCLI.DeleteAndPrint(c.DescribePrinter(), id...)
}

p := c.evalBulkFlags()

return c.GenericCLI.DeleteFromFileAndPrint(viper.GetString("file"), p())
return c.MultiArgGenericCLI.DeleteFromFileAndPrint(viper.GetString("file"), p())
},
ValidArgsFunction: c.ValidArgsFn,
}
Expand All @@ -258,12 +288,12 @@ func NewCmds[C any, U any, R any](c *CmdsConfig[C, U, R], additionalCmds ...*cob
Short: fmt.Sprintf("applies one or more %s from a given file", c.Plural),
RunE: func(cmd *cobra.Command, args []string) error {
if !viper.GetBool("skip-security-prompts") {
c.GenericCLI = c.GenericCLI.WithBulkSecurityPrompt(c.In, c.Out)
c.MultiArgGenericCLI = c.MultiArgGenericCLI.WithBulkSecurityPrompt(c.In, c.Out)
}

p := c.evalBulkFlags()

return c.GenericCLI.ApplyFromFileAndPrint(viper.GetString("file"), p())
return c.MultiArgGenericCLI.ApplyFromFileAndPrint(viper.GetString("file"), p())
},
}

Expand All @@ -278,11 +308,16 @@ func NewCmds[C any, U any, R any](c *CmdsConfig[C, U, R], additionalCmds ...*cob
}

if _, ok := c.OnlyCmds[EditCmd]; ok {
use := "edit"
for _, arg := range c.Args {
use += fmt.Sprintf(" <%s>", arg)
}

cmd := &cobra.Command{
Use: "edit <id>",
Use: use,
Short: fmt.Sprintf("edit the %s through an editor and update", c.Singular),
RunE: func(cmd *cobra.Command, args []string) error {
return c.GenericCLI.EditAndPrint(args, c.DescribePrinter())
return c.MultiArgGenericCLI.EditAndPrint(len(c.Args), args, c.DescribePrinter())
},
ValidArgsFunction: c.ValidArgsFn,
}
Expand Down Expand Up @@ -345,7 +380,7 @@ func (c *CmdsConfig[C, U, R]) addFileFlags(cmd *cobra.Command) {
}

func (c *CmdsConfig[C, U, R]) validate() error {
if c.GenericCLI == nil {
if c.MultiArgGenericCLI == nil {
return fmt.Errorf("generic cli must not be nil, command: %s", c.Singular)
}
if c.DescribePrinter == nil {
Expand All @@ -369,23 +404,26 @@ func (c *CmdsConfig[C, U, R]) validate() error {
if c.Description == "" {
return fmt.Errorf("description must not be empty, command: %s", c.Singular)
}
if len(c.Args) < 1 {
return errors.New("at least one arg for id is required")
}

return nil
}

func (c *CmdsConfig[C, U, R]) evalBulkFlags() func() printers.Printer {
if !viper.GetBool("skip-security-prompts") {
c.GenericCLI = c.GenericCLI.WithBulkSecurityPrompt(c.In, c.Out)
c.MultiArgGenericCLI = c.MultiArgGenericCLI.WithBulkSecurityPrompt(c.In, c.Out)
}

if viper.GetBool("timestamps") {
c.GenericCLI = c.GenericCLI.WithTimestamps()
c.MultiArgGenericCLI = c.MultiArgGenericCLI.WithTimestamps()
}

p := c.DescribePrinter
if viper.GetBool("bulk-output") {
p = c.ListPrinter
c.GenericCLI = c.GenericCLI.WithBulkPrint()
c.MultiArgGenericCLI = c.MultiArgGenericCLI.WithBulkPrint()
}

return p
Expand Down
44 changes: 30 additions & 14 deletions pkg/genericcli/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/metal-stack/metal-lib/pkg/genericcli/printers"
"github.com/metal-stack/metal-lib/pkg/multisort"
"github.com/metal-stack/metal-lib/pkg/pointer"
)

func GetExactlyOneArg(args []string) (string, error) {
Expand All @@ -18,7 +19,22 @@ func GetExactlyOneArg(args []string) (string, error) {
}
}

func (a *GenericCLI[C, U, R]) List(sortKeys ...multisort.Key) ([]R, error) {
func GetExactlyNArgs(n int, args []string) ([]string, error) {
switch {
case n == 1:
arg, err := GetExactlyOneArg(args)
if err != nil {
return nil, err
}
return pointer.WrapInSlice(arg), nil
case len(args) == n:
return args, nil
default:
return nil, fmt.Errorf("%d positional args are required, %d were provided", n, len(args))
}
}

func (a *MultiArgGenericCLI[C, U, R]) List(sortKeys ...multisort.Key) ([]R, error) {
resp, err := a.crud.List()
if err != nil {
return nil, err
Expand All @@ -33,7 +49,7 @@ func (a *GenericCLI[C, U, R]) List(sortKeys ...multisort.Key) ([]R, error) {
return resp, nil
}

func (a *GenericCLI[C, U, R]) ListAndPrint(p printers.Printer, sortKeys ...multisort.Key) error {
func (a *MultiArgGenericCLI[C, U, R]) ListAndPrint(p printers.Printer, sortKeys ...multisort.Key) error {
resp, err := a.List(sortKeys...)
if err != nil {
return err
Expand All @@ -42,47 +58,47 @@ func (a *GenericCLI[C, U, R]) ListAndPrint(p printers.Printer, sortKeys ...multi
return p.Print(resp)
}

func (a *GenericCLI[C, U, R]) Describe(id string) (R, error) {
func (a *MultiArgGenericCLI[C, U, R]) Describe(id ...string) (R, error) {
var zero R

resp, err := a.crud.Get(id)
resp, err := a.crud.Get(id...)
if err != nil {
return zero, err
}

return resp, nil
}

func (a *GenericCLI[C, U, R]) DescribeAndPrint(id string, p printers.Printer) error {
resp, err := a.Describe(id)
func (a *MultiArgGenericCLI[C, U, R]) DescribeAndPrint(p printers.Printer, id ...string) error {
resp, err := a.Describe(id...)
if err != nil {
return err
}

return p.Print(resp)
}

func (a *GenericCLI[C, U, R]) Delete(id string) (R, error) {
func (a *MultiArgGenericCLI[C, U, R]) Delete(id ...string) (R, error) {
var zero R

resp, err := a.crud.Delete(id)
resp, err := a.crud.Delete(id...)
if err != nil {
return zero, err
}

return resp, nil
}

func (a *GenericCLI[C, U, R]) DeleteAndPrint(id string, p printers.Printer) error {
resp, err := a.Delete(id)
func (a *MultiArgGenericCLI[C, U, R]) DeleteAndPrint(p printers.Printer, id ...string) error {
resp, err := a.Delete(id...)
if err != nil {
return err
}

return p.Print(resp)
}

func (a *GenericCLI[C, U, R]) Create(rq C) (R, error) {
func (a *MultiArgGenericCLI[C, U, R]) Create(rq C) (R, error) {
var zero R

resp, err := a.crud.Create(rq)
Expand All @@ -93,7 +109,7 @@ func (a *GenericCLI[C, U, R]) Create(rq C) (R, error) {
return resp, nil
}

func (a *GenericCLI[C, U, R]) CreateAndPrint(rq C, p printers.Printer) error {
func (a *MultiArgGenericCLI[C, U, R]) CreateAndPrint(rq C, p printers.Printer) error {
resp, err := a.Create(rq)
if err != nil {
return err
Expand All @@ -102,7 +118,7 @@ func (a *GenericCLI[C, U, R]) CreateAndPrint(rq C, p printers.Printer) error {
return p.Print(resp)
}

func (a *GenericCLI[C, U, R]) Update(rq U) (R, error) {
func (a *MultiArgGenericCLI[C, U, R]) Update(rq U) (R, error) {
var zero R

resp, err := a.crud.Update(rq)
Expand All @@ -113,7 +129,7 @@ func (a *GenericCLI[C, U, R]) Update(rq U) (R, error) {
return resp, nil
}

func (a *GenericCLI[C, U, R]) UpdateAndPrint(rq U, p printers.Printer) error {
func (a *MultiArgGenericCLI[C, U, R]) UpdateAndPrint(rq U, p printers.Printer) error {
resp, err := a.Update(rq)
if err != nil {
return err
Expand Down
10 changes: 5 additions & 5 deletions pkg/genericcli/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
"sigs.k8s.io/yaml"
)

func (a *GenericCLI[C, U, R]) Edit(args []string) (R, error) {
func (a *MultiArgGenericCLI[C, U, R]) Edit(n int, args []string) (R, error) {
var zero R

id, err := GetExactlyOneArg(args)
id, err := GetExactlyNArgs(n, args)
if err != nil {
return zero, err
}
Expand All @@ -31,7 +31,7 @@ func (a *GenericCLI[C, U, R]) Edit(args []string) (R, error) {
_ = a.fs.Remove(tmpfile.Name())
}()

doc, err := a.crud.Get(id)
doc, err := a.crud.Get(id...)
if err != nil {
return zero, err
}
Expand Down Expand Up @@ -88,8 +88,8 @@ func (a *GenericCLI[C, U, R]) Edit(args []string) (R, error) {
return result, nil
}

func (a *GenericCLI[C, U, R]) EditAndPrint(args []string, p printers.Printer) error {
result, err := a.Edit(args)
func (a *MultiArgGenericCLI[C, U, R]) EditAndPrint(n int, args []string, p printers.Printer) error {
result, err := a.Edit(n, args)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 294a01f

Please sign in to comment.