Skip to content

Commit

Permalink
Add watch for list commands (#758)
Browse files Browse the repository at this point in the history
  • Loading branch information
nightfury1204 committed Apr 8, 2024
1 parent cbee2ca commit b9949b9
Show file tree
Hide file tree
Showing 16 changed files with 109 additions and 59 deletions.
4 changes: 2 additions & 2 deletions pkg/cli/apps.go
Expand Up @@ -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),
})

Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/balancers.go
Expand Up @@ -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),
})
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/builds.go
Expand Up @@ -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),
})

Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/certs.go
Expand Up @@ -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),
})

Expand Down
11 changes: 6 additions & 5 deletions pkg/cli/cli.go
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/env.go
Expand Up @@ -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),
})

Expand Down
46 changes: 46 additions & 0 deletions pkg/cli/helpers.go
Expand Up @@ -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"
Expand Down Expand Up @@ -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")
Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/instances.go
Expand Up @@ -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),
})

Expand Down
8 changes: 4 additions & 4 deletions pkg/cli/ps.go
Expand Up @@ -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),
})

Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/rack.go
Expand Up @@ -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),
})

Expand Down
3 changes: 2 additions & 1 deletion pkg/cli/racks.go
Expand Up @@ -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),
})
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/registries.go
Expand Up @@ -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),
})

Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/releases.go
Expand Up @@ -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),
})

Expand Down
8 changes: 4 additions & 4 deletions pkg/cli/resources.go
Expand Up @@ -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),
})

Expand Down Expand Up @@ -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),
})
Expand Down
52 changes: 27 additions & 25 deletions pkg/cli/scale.go
Expand Up @@ -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: "<service>",
Validate: func(c *stdcli.Context) error {
if c.Value("count") != nil || c.Value("cpu") != nil || c.Value("memory") != nil {
Expand Down Expand Up @@ -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)
}
4 changes: 2 additions & 2 deletions pkg/cli/services.go
Expand Up @@ -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),
})

Expand Down

0 comments on commit b9949b9

Please sign in to comment.