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  }