github.com/koron/hk@v0.0.0-20150303213137-b8aeaa3ab34c/apps.go (about) 1 package main 2 3 import ( 4 "io" 5 "os" 6 "sort" 7 "strings" 8 "text/tabwriter" 9 "time" 10 11 "github.com/heroku/hk/Godeps/_workspace/src/github.com/bgentry/heroku-go" 12 ) 13 14 var cmdApps = &Command{ 15 Run: runApps, 16 Usage: "apps [<name>...]", 17 Category: "app", 18 Short: "list apps", 19 Long: ` 20 Lists apps. Shows the app name, owner, and last release time (or 21 time the app was created, if it's never been released). 22 23 Examples: 24 25 $ hk apps 26 myapp user@test.com us Jan 2 12:34 27 myapp-eu user@longdomainname… eu Jan 2 12:35 28 29 $ hk apps myapp 30 myapp user@test.com us Jan 2 12:34 31 `, 32 } 33 34 func init() { 35 cmdApps.Flag.StringVarP(&flagOrgName, "org", "o", "", "organization name") 36 } 37 38 func runApps(cmd *Command, names []string) { 39 w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) 40 defer w.Flush() 41 var apps []hkapp 42 if len(names) == 0 { 43 var err error 44 apps, err = getAppList(flagOrgName) 45 must(err) 46 } else { 47 appch := make(chan *heroku.App, len(names)) 48 errch := make(chan error, len(names)) 49 for _, name := range names { 50 if name == "" { 51 appch <- nil 52 } else { 53 go func(appname string) { 54 if app, err := client.AppInfo(appname); err != nil { 55 errch <- err 56 } else { 57 appch <- app 58 } 59 }(name) 60 } 61 } 62 for _ = range names { 63 select { 64 case err := <-errch: 65 printFatal(err.Error()) 66 case app := <-appch: 67 if app != nil { 68 apps = append(apps, fromApp(*app)) 69 } 70 } 71 } 72 } 73 printAppList(w, apps) 74 } 75 76 func getAppList(orgName string) ([]hkapp, error) { 77 if orgName != "" { 78 apps, err := client.OrganizationAppListForOrganization(orgName, &heroku.ListRange{Field: "name", Max: 1000}) 79 if err != nil { 80 return nil, err 81 } 82 return fromOrgApps(apps), nil 83 } 84 85 apps, err := client.AppList(&heroku.ListRange{Field: "name", Max: 1000}) 86 if err != nil { 87 return nil, err 88 } 89 return fromApps(apps), nil 90 } 91 92 func printAppList(w io.Writer, apps []hkapp) { 93 sort.Sort(appsByName(apps)) 94 abbrevEmailApps(apps) 95 for _, a := range apps { 96 if a.Name != "" { 97 listApp(w, a) 98 } 99 } 100 } 101 102 func abbrevEmailApps(apps []hkapp) { 103 domains := make(map[string]int) 104 for _, a := range apps { 105 if a.Organization != "" { 106 parts := strings.SplitN(a.OwnerEmail, "@", 2) 107 if len(parts) == 2 { 108 domains["@"+parts[1]]++ 109 } 110 } 111 } 112 smax, nmax := "", 0 113 for s, n := range domains { 114 if n > nmax { 115 smax = s 116 nmax = n 117 } 118 } 119 for i := range apps { 120 if apps[i].Organization != "" { 121 // reference the app directly in the slice so we're not modifying a copy 122 if strings.HasSuffix(apps[i].OwnerEmail, smax) { 123 apps[i].OwnerEmail = apps[i].OwnerEmail[:len(apps[i].OwnerEmail)-len(smax)] 124 } 125 } 126 } 127 } 128 129 func listApp(w io.Writer, a hkapp) { 130 t := a.CreatedAt 131 if a.ReleasedAt != nil { 132 t = *a.ReleasedAt 133 } 134 orgOrEmail := a.Organization 135 if orgOrEmail == "" { 136 orgOrEmail = a.OwnerEmail 137 } 138 listRec(w, 139 a.Name, 140 abbrev(orgOrEmail, 20), 141 a.Region, 142 prettyTime{t}, 143 ) 144 } 145 146 type appsByName []hkapp 147 148 func (a appsByName) Len() int { return len(a) } 149 func (a appsByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 150 func (a appsByName) Less(i, j int) bool { return a[i].Name < a[j].Name } 151 152 type hkapp struct { 153 ArchivedAt *time.Time 154 BuildpackProvidedDescription *string 155 CreatedAt time.Time 156 GitURL string 157 Id string 158 Maintenance bool 159 Name string 160 Organization string 161 OwnerEmail string 162 Region string 163 ReleasedAt *time.Time 164 RepoSize *int 165 SlugSize *int 166 Stack string 167 UpdatedAt time.Time 168 WebURL string 169 } 170 171 func fromApp(app heroku.App) (happ hkapp) { 172 orgName := "" 173 if strings.HasSuffix(app.Owner.Email, "@herokumanager.com") { 174 orgName = strings.TrimSuffix(app.Owner.Email, "@herokumanager.com") 175 } 176 return hkapp{ 177 ArchivedAt: app.ArchivedAt, 178 BuildpackProvidedDescription: app.BuildpackProvidedDescription, 179 CreatedAt: app.CreatedAt, 180 GitURL: app.GitURL, 181 Id: app.Id, 182 Maintenance: app.Maintenance, 183 Name: app.Name, 184 Organization: orgName, 185 OwnerEmail: app.Owner.Email, 186 Region: app.Region.Name, 187 ReleasedAt: app.ReleasedAt, 188 RepoSize: app.RepoSize, 189 SlugSize: app.SlugSize, 190 Stack: app.Stack.Name, 191 UpdatedAt: app.UpdatedAt, 192 WebURL: app.WebURL, 193 } 194 } 195 196 func fromApps(apps []heroku.App) (happs []hkapp) { 197 happs = make([]hkapp, len(apps)) 198 for i := range apps { 199 happs[i] = fromApp(apps[i]) 200 } 201 return 202 } 203 204 func fromOrgApp(oapp heroku.OrganizationApp) (happ hkapp) { 205 orgName := "" 206 if oapp.Organization != nil { 207 orgName = oapp.Organization.Name 208 } 209 return hkapp{ 210 ArchivedAt: oapp.ArchivedAt, 211 BuildpackProvidedDescription: oapp.BuildpackProvidedDescription, 212 CreatedAt: oapp.CreatedAt, 213 GitURL: oapp.GitURL, 214 Id: oapp.Id, 215 Maintenance: oapp.Maintenance, 216 Name: oapp.Name, 217 Organization: orgName, 218 Region: oapp.Region.Name, 219 ReleasedAt: oapp.ReleasedAt, 220 RepoSize: oapp.RepoSize, 221 SlugSize: oapp.SlugSize, 222 Stack: oapp.Stack.Name, 223 UpdatedAt: oapp.UpdatedAt, 224 WebURL: oapp.WebURL, 225 } 226 } 227 228 func fromOrgApps(oapps []heroku.OrganizationApp) (happs []hkapp) { 229 happs = make([]hkapp, len(oapps)) 230 for i := range oapps { 231 happs[i] = fromOrgApp(oapps[i]) 232 } 233 return 234 }