Skip to content

Commit

Permalink
feat(cli): Implement --watch flag
Browse files Browse the repository at this point in the history
  • Loading branch information
irvinlim committed Jan 27, 2023
1 parent 1efeecb commit 9cc3904
Show file tree
Hide file tree
Showing 12 changed files with 371 additions and 206 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/imdario/mergo v0.3.12
github.com/jedib0t/go-pretty/v6 v6.3.1
github.com/kr/text v0.2.0
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
github.com/mitchellh/go-testing-interface v1.0.0
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/mitchellh/mapstructure v1.4.3
Expand Down Expand Up @@ -63,7 +64,6 @@ require (
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
Expand Down
28 changes: 22 additions & 6 deletions pkg/cli/cmd/cmd_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,34 @@ import (
"github.com/furiko-io/furiko/pkg/cli/streams"
)

type GetCommand struct {
streams *streams.Streams
}

func NewGetCommand(streams *streams.Streams) *cobra.Command {
c := &GetCommand{
streams: streams,
}

cmd := &cobra.Command{
Use: "get",
Short: "Get one or more resources by name.",
}

// Add common flags
c.AddSubcommand(cmd, NewGetJobCommand(streams))
c.AddSubcommand(cmd, NewGetJobConfigCommand(streams))

return cmd
}

// AddSubcommand will register subcommand flags and add it to the parent command.
func (c *GetCommand) AddSubcommand(cmd, subCommand *cobra.Command) {
c.RegisterFlags(subCommand)
cmd.AddCommand(subCommand)
}

// RegisterFlags will register flags for the given subcommand.
func (c *GetCommand) RegisterFlags(cmd *cobra.Command) {
cmd.PersistentFlags().StringP("output", "o", string(printer.OutputFormatPretty),
fmt.Sprintf("Output format. One of: %v", strings.Join(printer.GetAllOutputFormatStrings(), "|")))

Expand All @@ -41,9 +62,4 @@ func NewGetCommand(streams *streams.Streams) *cobra.Command {
}); err != nil {
Fatal(err, DefaultErrorExitCode)
}

cmd.AddCommand(NewGetJobCommand(streams))
cmd.AddCommand(NewGetJobConfigCommand(streams))

return cmd
}
18 changes: 12 additions & 6 deletions pkg/cli/cmd/cmd_get_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ var (

type GetJobCommand struct {
streams *streams.Streams

output printer.OutputFormat
}

func NewGetJobCommand(streams *streams.Streams) *cobra.Command {
Expand All @@ -62,23 +64,27 @@ func NewGetJobCommand(streams *streams.Streams) *cobra.Command {
PreRunE: PrerunWithKubeconfig,
Args: cobra.MinimumNArgs(1),
ValidArgsFunction: MakeCobraCompletionFunc((&CompletionHelper{}).ListJobs()),
RunE: c.Run,
RunE: RunAllE(
c.Complete,
c.Run,
),
}

return cmd
}

func (c *GetJobCommand) Complete(cmd *cobra.Command, args []string) error {
c.output = GetOutputFormat(cmd)
return nil
}

func (c *GetJobCommand) Run(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
client := ctrlContext.Clientsets().Furiko().ExecutionV1alpha1()
namespace, err := GetNamespace(cmd)
if err != nil {
return err
}
output, err := GetOutputFormat(cmd)
if err != nil {
return err
}

if len(args) == 0 {
return errors.New("at least one name is required")
Expand All @@ -94,7 +100,7 @@ func (c *GetJobCommand) Run(cmd *cobra.Command, args []string) error {
jobs = append(jobs, job)
}

return c.PrintJobs(output, jobs)
return c.PrintJobs(c.output, jobs)
}

func (c *GetJobCommand) PrintJobs(output printer.OutputFormat, jobs []*execution.Job) error {
Expand Down
18 changes: 12 additions & 6 deletions pkg/cli/cmd/cmd_get_jobconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ var (

type GetJobConfigCommand struct {
streams *streams.Streams

output printer.OutputFormat
}

func NewGetJobConfigCommand(streams *streams.Streams) *cobra.Command {
Expand All @@ -65,23 +67,27 @@ func NewGetJobConfigCommand(streams *streams.Streams) *cobra.Command {
PreRunE: PrerunWithKubeconfig,
Args: cobra.MinimumNArgs(1),
ValidArgsFunction: MakeCobraCompletionFunc((&CompletionHelper{}).ListJobConfigs()),
RunE: c.Run,
RunE: RunAllE(
c.Complete,
c.Run,
),
}

return cmd
}

func (c *GetJobConfigCommand) Complete(cmd *cobra.Command, args []string) error {
c.output = GetOutputFormat(cmd)
return nil
}

func (c *GetJobConfigCommand) Run(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
client := ctrlContext.Clientsets().Furiko().ExecutionV1alpha1()
namespace, err := GetNamespace(cmd)
if err != nil {
return err
}
output, err := GetOutputFormat(cmd)
if err != nil {
return err
}

if len(args) == 0 {
return errors.New("at least one name is required")
Expand All @@ -96,7 +102,7 @@ func (c *GetJobConfigCommand) Run(cmd *cobra.Command, args []string) error {
jobConfigs = append(jobConfigs, jobConfig)
}

return c.PrintJobConfigs(ctx, cmd, output, jobConfigs)
return c.PrintJobConfigs(ctx, cmd, c.output, jobConfigs)
}

func (c *GetJobConfigCommand) PrintJobConfigs(
Expand Down
34 changes: 26 additions & 8 deletions pkg/cli/cmd/cmd_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,44 @@ import (
"github.com/furiko-io/furiko/pkg/cli/streams"
)

type ListCommand struct {
streams *streams.Streams
}

func NewListCommand(streams *streams.Streams) *cobra.Command {
c := &ListCommand{
streams: streams,
}

cmd := &cobra.Command{
Use: "list",
Short: "List all resources by kind.",
}

// Add common flags
cmd.PersistentFlags().StringP("output", "o", string(printer.OutputFormatPretty),
c.AddSubcommand(cmd, NewListJobCommand(streams))
c.AddSubcommand(cmd, NewListJobConfigCommand(streams))

return cmd
}

// AddSubcommand will register subcommand flags and add it to the parent command.
func (c *ListCommand) AddSubcommand(cmd, subCommand *cobra.Command) {
c.RegisterFlags(subCommand)
cmd.AddCommand(subCommand)
}

// RegisterFlags will register flags for the given subcommand.
func (c *ListCommand) RegisterFlags(cmd *cobra.Command) {
cmd.Flags().StringP("output", "o", string(printer.OutputFormatPretty),
fmt.Sprintf("Output format. One of: %v", strings.Join(printer.GetAllOutputFormatStrings(), "|")))
cmd.PersistentFlags().Bool("no-headers", false,
cmd.Flags().Bool("no-headers", false,
"When using the default or custom-column output format, don't print headers (default print headers).")
cmd.Flags().BoolP("watch", "w", false,
"After listing the requested object(s), watch for changes and print them to the standard output.")

if err := RegisterFlagCompletions(cmd, []FlagCompletion{
{FlagName: "output", CompletionFunc: (&CompletionHelper{}).FromSlice(printer.AllOutputFormats)},
}); err != nil {
Fatal(err, DefaultErrorExitCode)
}

cmd.AddCommand(NewListJobCommand(streams))
cmd.AddCommand(NewListJobConfigCommand(streams))

return cmd
}
72 changes: 55 additions & 17 deletions pkg/cli/cmd/cmd_list_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"

execution "github.com/furiko-io/furiko/apis/execution/v1alpha1"
"github.com/furiko-io/furiko/pkg/cli/formatter"
Expand All @@ -44,7 +45,9 @@ var (
type ListJobCommand struct {
streams *streams.Streams
jobConfig string
output printer.OutputFormat
noHeaders bool
watch bool
}

func NewListJobCommand(streams *streams.Streams) *cobra.Command {
Expand All @@ -59,7 +62,10 @@ func NewListJobCommand(streams *streams.Streams) *cobra.Command {
Example: ListJobExample,
PreRunE: PrerunWithKubeconfig,
Args: cobra.ExactArgs(0),
RunE: c.Run,
RunE: RunAllE(
c.Complete,
c.Run,
),
}

cmd.Flags().StringVar(&c.jobConfig, "for", "", "Return only jobs for the given job config.")
Expand All @@ -73,21 +79,20 @@ func NewListJobCommand(streams *streams.Streams) *cobra.Command {
return cmd
}

func (c *ListJobCommand) Complete(cmd *cobra.Command, args []string) error {
c.output = GetOutputFormat(cmd)
c.noHeaders = GetFlagBool(cmd, "no-headers")
c.watch = GetFlagBool(cmd, "watch")
return nil
}

func (c *ListJobCommand) Run(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
client := ctrlContext.Clientsets().Furiko().ExecutionV1alpha1()
namespace, err := GetNamespace(cmd)
if err != nil {
return err
}
output, err := GetOutputFormat(cmd)
if err != nil {
return err
}
c.noHeaders, err = GetNoHeaders(cmd)
if err != nil {
return err
}

// Filter to specific JobConfig.
var options metav1.ListOptions
Expand All @@ -108,18 +113,42 @@ func (c *ListJobCommand) Run(cmd *cobra.Command, args []string) error {
return errors.Wrapf(err, "cannot list jobs")
}

if len(jobList.Items) == 0 {
if len(jobList.Items) == 0 && !c.watch {
c.streams.Printf("No jobs found in %v namespace.\n", namespace)
return nil
}

return c.PrintJobs(output, jobList)
p := printer.NewTablePrinter(c.streams.Out)

if len(jobList.Items) > 0 {
if err := c.PrintJobs(p, jobList); err != nil {
return nil
}
}

if c.watch {
watchOptions := *options.DeepCopy()
watchOptions.ResourceVersion = jobList.ResourceVersion
watch, err := client.Jobs(namespace).Watch(ctx, watchOptions)
if err != nil {
return errors.Wrapf(err, "cannot watch jobs")
}

return WatchAndPrint(ctx, watch, func(obj runtime.Object) (bool, error) {
if job, ok := obj.(*execution.Job); ok {
return true, c.PrintJob(p, job)
}
return false, nil
})
}

return nil
}

func (c *ListJobCommand) PrintJobs(output printer.OutputFormat, jobList *execution.JobList) error {
func (c *ListJobCommand) PrintJobs(p *printer.TablePrinter, jobList *execution.JobList) error {
// Handle pretty print as a special case.
if output == printer.OutputFormatPretty {
c.prettyPrint(jobList.Items)
if c.output == printer.OutputFormatPretty {
c.prettyPrint(p, jobList.Items)
return nil
}

Expand All @@ -130,7 +159,17 @@ func (c *ListJobCommand) PrintJobs(output printer.OutputFormat, jobList *executi
items = append(items, &job)
}

return printer.PrintObjects(execution.GVKJob, output, c.streams.Out, items)
return printer.PrintObjects(execution.GVKJob, c.output, c.streams.Out, items)
}

func (c *ListJobCommand) PrintJob(p *printer.TablePrinter, job *execution.Job) error {
// Handle pretty print as a special case.
if c.output == printer.OutputFormatPretty {
c.prettyPrint(p, []execution.Job{*job})
return nil
}

return printer.PrintObject(execution.GVKJob, c.output, c.streams.Out, job)
}

func (c *ListJobCommand) makeJobHeader() []string {
Expand All @@ -143,8 +182,7 @@ func (c *ListJobCommand) makeJobHeader() []string {
}
}

func (c *ListJobCommand) prettyPrint(jobs []execution.Job) {
p := printer.NewTablePrinter(c.streams.Out)
func (c *ListJobCommand) prettyPrint(p *printer.TablePrinter, jobs []execution.Job) {
var headers []string
if !c.noHeaders {
headers = c.makeJobHeader()
Expand Down
Loading

0 comments on commit 9cc3904

Please sign in to comment.