From b9949b93a77300b2835ec1cef33845438e7cbdd0 Mon Sep 17 00:00:00 2001 From: "Md. Nure Alam Nahid" Date: Mon, 8 Apr 2024 13:49:20 +0100 Subject: [PATCH] Add watch for list commands (#758) --- pkg/cli/apps.go | 4 ++-- pkg/cli/balancers.go | 4 ++-- pkg/cli/builds.go | 4 ++-- pkg/cli/certs.go | 4 ++-- pkg/cli/cli.go | 11 ++++----- pkg/cli/env.go | 4 ++-- pkg/cli/helpers.go | 46 ++++++++++++++++++++++++++++++++++++++ pkg/cli/instances.go | 4 ++-- pkg/cli/ps.go | 8 +++---- pkg/cli/rack.go | 4 ++-- pkg/cli/racks.go | 3 ++- pkg/cli/registries.go | 4 ++-- pkg/cli/releases.go | 4 ++-- pkg/cli/resources.go | 8 +++---- pkg/cli/scale.go | 52 ++++++++++++++++++++++--------------------- pkg/cli/services.go | 4 ++-- 16 files changed, 109 insertions(+), 59 deletions(-) diff --git a/pkg/cli/apps.go b/pkg/cli/apps.go index 69dc0181c..dd8abe2db 100644 --- a/pkg/cli/apps.go +++ b/pkg/cli/apps.go @@ -19,8 +19,8 @@ import ( ) func init() { - register("apps", "list apps", Apps, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagRack}, + register("apps", "list apps", watch(Apps), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagRack, flagWatchInterval}, Validate: stdcli.Args(0), }) diff --git a/pkg/cli/balancers.go b/pkg/cli/balancers.go index cdeb62d50..7807a1562 100644 --- a/pkg/cli/balancers.go +++ b/pkg/cli/balancers.go @@ -6,8 +6,8 @@ import ( ) func init() { - register("balancers", "list balancers for an app", Balancers, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagApp, flagRack}, + register("balancers", "list balancers for an app", watch(Balancers), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagApp, flagRack, flagWatchInterval}, Validate: stdcli.Args(0), }) } diff --git a/pkg/cli/builds.go b/pkg/cli/builds.go index 5c4fccbb1..ed2eae1ee 100644 --- a/pkg/cli/builds.go +++ b/pkg/cli/builds.go @@ -26,8 +26,8 @@ func init() { Validate: stdcli.ArgsMax(1), }) - register("builds", "list builds", Builds, stdcli.CommandOptions{ - Flags: append(stdcli.OptionFlags(structs.BuildListOptions{}), flagRack, flagApp), + register("builds", "list builds", watch(Builds), stdcli.CommandOptions{ + Flags: append(stdcli.OptionFlags(structs.BuildListOptions{}), flagRack, flagApp, flagWatchInterval), Validate: stdcli.Args(0), }) diff --git a/pkg/cli/certs.go b/pkg/cli/certs.go index eac8d36de..15b36269e 100644 --- a/pkg/cli/certs.go +++ b/pkg/cli/certs.go @@ -15,8 +15,8 @@ import ( ) func init() { - register("certs", "list certificates", Certs, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagRack}, + register("certs", "list certificates", watch(Certs), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagRack, flagWatchInterval}, Validate: stdcli.Args(0), }) diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index fd70bd05c..6cadd41e6 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -19,11 +19,12 @@ var ( ) var ( - flagApp = stdcli.StringFlag("app", "a", "app name") - flagForce = stdcli.BoolFlag("force", "", "force version update") - flagId = stdcli.BoolFlag("id", "", "put logs on stderr, release id on stdout") - flagNoFollow = stdcli.BoolFlag("no-follow", "", "do not follow logs") - flagRack = stdcli.StringFlag("rack", "r", "rack name") + flagApp = stdcli.StringFlag("app", "a", "app name") + flagForce = stdcli.BoolFlag("force", "", "force version update") + flagId = stdcli.BoolFlag("id", "", "put logs on stderr, release id on stdout") + flagNoFollow = stdcli.BoolFlag("no-follow", "", "do not follow logs") + flagRack = stdcli.StringFlag("rack", "r", "rack name") + flagWatchInterval = stdcli.StringFlag("watch", "", "cmd watch/rerun interval in seconds") ) func New(name, version string) *Engine { diff --git a/pkg/cli/env.go b/pkg/cli/env.go index e5371ecb2..36457a438 100644 --- a/pkg/cli/env.go +++ b/pkg/cli/env.go @@ -19,8 +19,8 @@ import ( ) func init() { - register("env", "list env vars", Env, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagRack, flagApp}, + register("env", "list env vars", watch(Env), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagRack, flagApp, flagWatchInterval}, Validate: stdcli.Args(0), }) diff --git a/pkg/cli/helpers.go b/pkg/cli/helpers.go index ab6309b70..c593351e3 100644 --- a/pkg/cli/helpers.go +++ b/pkg/cli/helpers.go @@ -7,10 +7,14 @@ import ( "encoding/json" "fmt" "os" + "os/exec" + "os/signal" "path/filepath" "regexp" "runtime" + "strconv" "strings" + "syscall" "time" "github.com/convox/convox/pkg/common" @@ -142,6 +146,48 @@ func waitForResourceRunning(rack sdk.Interface, c *stdcli.Context, resource stri }) } +func clearScreen() { + switch runtime.GOOS { + case "windows": + cmd := exec.Command("cmd", "/c", "cls") //Windows example, its tested + cmd.Stdout = os.Stdout + cmd.Run() + default: + cmd := exec.Command("clear") //Linux example, its tested + cmd.Stdout = os.Stdout + cmd.Run() + } +} + +func watch(fn func(r sdk.Interface, c *stdcli.Context) error) func(sdk.Interface, *stdcli.Context) error { + return func(rr sdk.Interface, cc *stdcli.Context) error { + watchIntervalStr := cc.String("watch") + watchInterval, _ := strconv.Atoi(watchIntervalStr) + if watchInterval <= 0 { + return fn(rr, cc) + } + + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) + ticker := time.NewTicker(time.Second * time.Duration(watchInterval)) + for { + select { + case <-ch: + ticker.Stop() + return nil + case <-ticker.C: + clearScreen() + cc.Writef("Every %ds:\n\n", watchInterval) + err := fn(rr, cc) + if err != nil { + cc.Error(err) + } + } + } + return nil + } +} + func checkRackNameRegex(name string) error { if !regexp.MustCompile(`^[a-z0-9-]+$`).MatchString(name) { return fmt.Errorf("only lowercase alphanumeric characters and hyphen allowed and must not start with hyphen") diff --git a/pkg/cli/instances.go b/pkg/cli/instances.go index 229e9b979..0b5d29b62 100644 --- a/pkg/cli/instances.go +++ b/pkg/cli/instances.go @@ -20,8 +20,8 @@ var ( ) func init() { - register("instances", "list instances", Instances, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagRack}, + register("instances", "list instances", watch(Instances), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagRack, flagWatchInterval}, Validate: stdcli.Args(0), }) diff --git a/pkg/cli/ps.go b/pkg/cli/ps.go index 843da282a..9ed81b5d2 100644 --- a/pkg/cli/ps.go +++ b/pkg/cli/ps.go @@ -8,13 +8,13 @@ import ( ) func init() { - register("ps", "list app processes", Ps, stdcli.CommandOptions{ - Flags: append(stdcli.OptionFlags(structs.ProcessListOptions{}), flagApp, flagRack), + register("ps", "list app processes", watch(Ps), stdcli.CommandOptions{ + Flags: append(stdcli.OptionFlags(structs.ProcessListOptions{}), flagApp, flagRack, flagWatchInterval), Validate: stdcli.Args(0), }) - register("ps info", "get information about a process", PsInfo, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagApp, flagRack}, + register("ps info", "get information about a process", watch(PsInfo), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagApp, flagRack, flagWatchInterval}, Validate: stdcli.Args(1), }) diff --git a/pkg/cli/rack.go b/pkg/cli/rack.go index 269810a55..cadc393b5 100644 --- a/pkg/cli/rack.go +++ b/pkg/cli/rack.go @@ -20,8 +20,8 @@ import ( ) func init() { - register("rack", "get information about the rack", Rack, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagRack}, + register("rack", "get information about the rack", watch(Rack), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagRack, flagWatchInterval}, Validate: stdcli.Args(0), }) diff --git a/pkg/cli/racks.go b/pkg/cli/racks.go index 6fae2a5b5..d9119af67 100644 --- a/pkg/cli/racks.go +++ b/pkg/cli/racks.go @@ -7,7 +7,8 @@ import ( ) func init() { - registerWithoutProvider("racks", "list available racks", Racks, stdcli.CommandOptions{ + registerWithoutProvider("racks", "list available racks", watch(Racks), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagWatchInterval}, Validate: stdcli.Args(0), }) } diff --git a/pkg/cli/registries.go b/pkg/cli/registries.go index 46328f600..c434c2e3a 100644 --- a/pkg/cli/registries.go +++ b/pkg/cli/registries.go @@ -6,8 +6,8 @@ import ( ) func init() { - register("registries", "list private registries", Registries, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagRack}, + register("registries", "list private registries", watch(Registries), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagRack, flagWatchInterval}, Validate: stdcli.Args(0), }) diff --git a/pkg/cli/releases.go b/pkg/cli/releases.go index 34fc43993..40236be79 100644 --- a/pkg/cli/releases.go +++ b/pkg/cli/releases.go @@ -14,8 +14,8 @@ import ( ) func init() { - register("releases", "list releases for an app", Releases, stdcli.CommandOptions{ - Flags: append(stdcli.OptionFlags(structs.ReleaseListOptions{}), flagRack, flagApp), + register("releases", "list releases for an app", watch(Releases), stdcli.CommandOptions{ + Flags: append(stdcli.OptionFlags(structs.ReleaseListOptions{}), flagRack, flagApp, flagWatchInterval), Validate: stdcli.Args(0), }) diff --git a/pkg/cli/resources.go b/pkg/cli/resources.go index f829a08cc..e66a6d397 100644 --- a/pkg/cli/resources.go +++ b/pkg/cli/resources.go @@ -16,8 +16,8 @@ import ( ) func init() { - register("resources", "list resources", Resources, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagRack, flagApp}, + register("resources", "list resources", watch(Resources), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagRack, flagApp, flagWatchInterval}, Validate: stdcli.Args(0), }) @@ -69,8 +69,8 @@ func init() { Validate: stdcli.Args(1), }) - register("rack resources", "list resources", RackResources, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagRack}, + register("rack resources", "list resources", watch(RackResources), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagRack, flagWatchInterval}, Invisible: true, Validate: stdcli.Args(0), }) diff --git a/pkg/cli/scale.go b/pkg/cli/scale.go index 40607ff13..87785da6c 100644 --- a/pkg/cli/scale.go +++ b/pkg/cli/scale.go @@ -12,7 +12,7 @@ import ( func init() { register("scale", "scale a service", Scale, stdcli.CommandOptions{ - Flags: append(stdcli.OptionFlags(structs.ServiceUpdateOptions{}), flagApp, flagRack), + Flags: append(stdcli.OptionFlags(structs.ServiceUpdateOptions{}), flagApp, flagRack, flagWatchInterval), Usage: "", Validate: func(c *stdcli.Context) error { if c.Value("count") != nil || c.Value("cpu") != nil || c.Value("memory") != nil { @@ -64,37 +64,39 @@ func Scale(rack sdk.Interface, c *stdcli.Context) error { return c.OK() } - var ss structs.Services - running := map[string]int{} + return watch(func(r sdk.Interface, c *stdcli.Context) error { + var ss structs.Services + running := map[string]int{} - if s.Version < "20180708231844" { - ss, err = rack.FormationGet(app(c)) - if err != nil { - return err + if s.Version < "20180708231844" { + ss, err = rack.FormationGet(app(c)) + if err != nil { + return err + } + } else { + ss, err = rack.ServiceList(app(c)) + if err != nil { + return err + } } - } else { - ss, err = rack.ServiceList(app(c)) + + sort.Slice(ss, func(i, j int) bool { return ss[i].Name < ss[j].Name }) + + ps, err := rack.ProcessList(app(c), structs.ProcessListOptions{}) if err != nil { return err } - } - sort.Slice(ss, func(i, j int) bool { return ss[i].Name < ss[j].Name }) - - ps, err := rack.ProcessList(app(c), structs.ProcessListOptions{}) - if err != nil { - return err - } - - for _, p := range ps { - running[p.Name] += 1 - } + for _, p := range ps { + running[p.Name] += 1 + } - t := c.Table("SERVICE", "DESIRED", "RUNNING", "CPU", "MEMORY") + t := c.Table("SERVICE", "DESIRED", "RUNNING", "CPU", "MEMORY") - for _, s := range ss { - t.AddRow(s.Name, fmt.Sprintf("%d", s.Count), fmt.Sprintf("%d", running[s.Name]), fmt.Sprintf("%d", s.Cpu), fmt.Sprintf("%d", s.Memory)) - } + for _, s := range ss { + t.AddRow(s.Name, fmt.Sprintf("%d", s.Count), fmt.Sprintf("%d", running[s.Name]), fmt.Sprintf("%d", s.Cpu), fmt.Sprintf("%d", s.Memory)) + } - return t.Print() + return t.Print() + })(rack, c) } diff --git a/pkg/cli/services.go b/pkg/cli/services.go index 1611d8de6..f54245374 100644 --- a/pkg/cli/services.go +++ b/pkg/cli/services.go @@ -10,8 +10,8 @@ import ( ) func init() { - register("services", "list services for an app", Services, stdcli.CommandOptions{ - Flags: []stdcli.Flag{flagApp, flagRack}, + register("services", "list services for an app", watch(Services), stdcli.CommandOptions{ + Flags: []stdcli.Flag{flagApp, flagRack, flagWatchInterval}, Validate: stdcli.Args(0), })