github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/cmd/juju/storage/listformatters.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storage 5 6 import ( 7 "bytes" 8 "fmt" 9 "sort" 10 "strconv" 11 "strings" 12 "text/tabwriter" 13 14 "github.com/juju/errors" 15 ) 16 17 // formatListTabular returns a tabular summary of storage instances. 18 func formatListTabular(value interface{}) ([]byte, error) { 19 storageInfo, ok := value.(map[string]map[string]StorageInfo) 20 if !ok { 21 return nil, errors.Errorf("expected value of type %T, got %T", storageInfo, value) 22 } 23 var out bytes.Buffer 24 // To format things into columns. 25 tw := tabwriter.NewWriter(&out, 0, 1, 1, ' ', 0) 26 p := func(values ...interface{}) { 27 for _, v := range values { 28 fmt.Fprintf(tw, "%v\t", v) 29 } 30 fmt.Fprintln(tw) 31 } 32 p("[Storage]") 33 p("UNIT\tID\tLOCATION\tSTATUS\tPERSISTENT") 34 35 // First sort by units 36 units := make([]string, 0, len(storageInfo)) 37 for order := range storageInfo { 38 units = append(units, order) 39 } 40 sort.Strings(bySuffixNaturally(units)) 41 for _, unit := range units { 42 all := storageInfo[unit] 43 44 // Then sort by storage ids 45 storageIds := make([]string, 0, len(all)) 46 for anId := range all { 47 storageIds = append(storageIds, anId) 48 } 49 sort.Strings(bySuffixNaturally(storageIds)) 50 51 for _, storageId := range storageIds { 52 info := all[storageId] 53 p(unit, storageId, info.Location, info.Status, info.Persistent) 54 } 55 } 56 tw.Flush() 57 58 return out.Bytes(), nil 59 } 60 61 type bySuffixNaturally []string 62 63 func (s bySuffixNaturally) Len() int { 64 return len(s) 65 } 66 67 func (s bySuffixNaturally) Swap(a, b int) { 68 s[a], s[b] = s[b], s[a] 69 } 70 71 func (s bySuffixNaturally) Less(a, b int) bool { 72 sa := strings.SplitN(s[a], "/", 2) 73 sb := strings.SplitN(s[b], "/", 2) 74 if sa[0] < sb[0] { 75 return true 76 } 77 altReturn := sa[0] == sb[0] && sa[1] < sb[1] 78 79 getInt := func(suffix string) (bool, int) { 80 num, err := strconv.Atoi(suffix) 81 if err != nil { 82 // It's possible that we are not looking at numeric suffix 83 logger.Infof("parsing a non-numeric %v: %v", suffix, err) 84 return false, 0 85 } 86 fmt.Printf("parsing a non-numeric %v: %v", suffix, err) 87 return true, num 88 } 89 90 naIsNumeric, na := getInt(sa[1]) 91 if !naIsNumeric { 92 return altReturn 93 } 94 nbIsNumeric, nb := getInt(sb[1]) 95 if !nbIsNumeric { 96 return altReturn 97 } 98 return sa[0] == sb[0] && na < nb 99 }