github.com/koron/hk@v0.0.0-20150303213137-b8aeaa3ab34c/dynos.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "io" 6 "os" 7 "sort" 8 "strconv" 9 "strings" 10 "text/tabwriter" 11 "time" 12 13 "github.com/heroku/hk/Godeps/_workspace/src/github.com/bgentry/heroku-go" 14 ) 15 16 var cmdDynos = &Command{ 17 Run: runDynos, 18 Usage: "dynos [<name>...]", 19 NeedsApp: true, 20 Category: "dyno", 21 Short: "list dynos", 22 Long: ` 23 Lists dynos. Shows the name, size, state, age, and command. 24 25 Examples: 26 27 $ hk dynos 28 run.3794 2X up 1m bash 29 web.1 1X up 15h "blog /app /tmp/dst" 30 web.2 1X up 8h "blog /app /tmp/dst" 31 32 $ hk dynos web 33 web.1 1X up 15h "blog /app /tmp/dst" 34 web.2 1X up 8h "blog /app /tmp/dst" 35 `, 36 } 37 38 func runDynos(cmd *Command, names []string) { 39 w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) 40 defer w.Flush() 41 42 if len(names) > 1 { 43 cmd.PrintUsage() 44 os.Exit(2) 45 } 46 listDynos(w, names) 47 } 48 49 func listDynos(w io.Writer, names []string) { 50 appname := mustApp() 51 dynos, err := client.DynoList(appname, nil) 52 must(err) 53 sort.Sort(DynosByName(dynos)) 54 55 if len(names) == 0 { 56 for _, d := range dynos { 57 listDyno(w, &d) 58 } 59 return 60 } 61 62 for _, name := range names { 63 for _, d := range dynos { 64 if !strings.Contains(name, ".") { 65 if strings.HasPrefix(d.Name, name+".") { 66 listDyno(w, &d) 67 } 68 } else { 69 if d.Name == name { 70 listDyno(w, &d) 71 } 72 } 73 } 74 } 75 } 76 77 func listDyno(w io.Writer, d *heroku.Dyno) { 78 listRec(w, 79 d.Name, 80 d.Size, 81 d.State, 82 prettyDuration{dynoAge(d)}, 83 maybeQuote(d.Command), 84 ) 85 } 86 87 // quotes s as a json string if it contains any weird chars 88 // currently weird is anything other than [alnum]_- 89 func maybeQuote(s string) string { 90 for _, r := range s { 91 if !('0' <= r && r <= '9' || 'a' <= r && r <= 'z' || 92 'A' <= r && r <= 'Z' || r == '-' || r == '_') { 93 return quote(s) 94 } 95 } 96 return s 97 } 98 99 // quotes s as a json string 100 func quote(s string) string { 101 b, _ := json.Marshal(s) 102 return string(b) 103 } 104 105 type DynosByName []heroku.Dyno 106 107 func (p DynosByName) Len() int { return len(p) } 108 func (p DynosByName) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 109 func (p DynosByName) Less(i, j int) bool { 110 return p[i].Type < p[j].Type || p[i].Type == p[j].Type && dynoSeq(&p[i]) < dynoSeq(&p[j]) 111 } 112 113 func dynoAge(d *heroku.Dyno) time.Duration { 114 return time.Now().Sub(d.UpdatedAt) 115 } 116 117 func dynoSeq(d *heroku.Dyno) int { 118 i, _ := strconv.Atoi(strings.TrimPrefix(d.Name, d.Type+".")) 119 return i 120 }