github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/storage/filesystemlistformatters.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 "strings" 11 "text/tabwriter" 12 13 "github.com/dustin/go-humanize" 14 "github.com/juju/errors" 15 ) 16 17 // formatFilesystemListTabular returns a tabular summary of filesystem instances. 18 func formatFilesystemListTabular(value interface{}) ([]byte, error) { 19 infos, ok := value.(map[string]FilesystemInfo) 20 if !ok { 21 return nil, errors.Errorf("expected value of type %T, got %T", infos, value) 22 } 23 return formatFilesystemListTabularTyped(infos), nil 24 } 25 26 func formatFilesystemListTabularTyped(infos map[string]FilesystemInfo) []byte { 27 var out bytes.Buffer 28 const ( 29 // To format things into columns. 30 minwidth = 0 31 tabwidth = 1 32 padding = 2 33 padchar = ' ' 34 flags = 0 35 ) 36 tw := tabwriter.NewWriter(&out, minwidth, tabwidth, padding, padchar, flags) 37 38 print := func(values ...string) { 39 fmt.Fprintln(tw, strings.Join(values, "\t")) 40 } 41 print("MACHINE", "UNIT", "STORAGE", "ID", "VOLUME", "PROVIDER-ID", "MOUNTPOINT", "SIZE", "STATE", "MESSAGE") 42 43 filesystemAttachmentInfos := make(filesystemAttachmentInfos, 0, len(infos)) 44 for filesystemId, info := range infos { 45 filesystemAttachmentInfo := filesystemAttachmentInfo{ 46 FilesystemId: filesystemId, 47 FilesystemInfo: info, 48 } 49 if info.Attachments == nil { 50 filesystemAttachmentInfos = append(filesystemAttachmentInfos, filesystemAttachmentInfo) 51 continue 52 } 53 // Each unit attachment must have a corresponding filesystem 54 // attachment. Enumerate each of the filesystem attachments, 55 // and locate the corresponding unit attachment if any. 56 // Each filesystem attachment has at most one corresponding 57 // unit attachment. 58 for machineId, machineInfo := range info.Attachments.Machines { 59 filesystemAttachmentInfo := filesystemAttachmentInfo 60 filesystemAttachmentInfo.MachineId = machineId 61 filesystemAttachmentInfo.MachineFilesystemAttachment = machineInfo 62 for unitId, unitInfo := range info.Attachments.Units { 63 if unitInfo.MachineId == machineId { 64 filesystemAttachmentInfo.UnitId = unitId 65 filesystemAttachmentInfo.UnitStorageAttachment = unitInfo 66 break 67 } 68 } 69 filesystemAttachmentInfos = append(filesystemAttachmentInfos, filesystemAttachmentInfo) 70 } 71 } 72 sort.Sort(filesystemAttachmentInfos) 73 74 for _, info := range filesystemAttachmentInfos { 75 var size string 76 if info.Size > 0 { 77 size = humanize.IBytes(info.Size * humanize.MiByte) 78 } 79 print( 80 info.MachineId, info.UnitId, info.Storage, 81 info.FilesystemId, info.Volume, info.ProviderFilesystemId, 82 info.MountPoint, size, 83 string(info.Status.Current), info.Status.Message, 84 ) 85 } 86 87 tw.Flush() 88 return out.Bytes() 89 } 90 91 type filesystemAttachmentInfo struct { 92 FilesystemId string 93 FilesystemInfo 94 95 MachineId string 96 MachineFilesystemAttachment 97 98 UnitId string 99 UnitStorageAttachment 100 } 101 102 type filesystemAttachmentInfos []filesystemAttachmentInfo 103 104 func (v filesystemAttachmentInfos) Len() int { 105 return len(v) 106 } 107 108 func (v filesystemAttachmentInfos) Swap(i, j int) { 109 v[i], v[j] = v[j], v[i] 110 } 111 112 func (v filesystemAttachmentInfos) Less(i, j int) bool { 113 switch compareStrings(v[i].MachineId, v[j].MachineId) { 114 case -1: 115 return true 116 case 1: 117 return false 118 } 119 120 switch compareSlashSeparated(v[i].UnitId, v[j].UnitId) { 121 case -1: 122 return true 123 case 1: 124 return false 125 } 126 127 switch compareSlashSeparated(v[i].Storage, v[j].Storage) { 128 case -1: 129 return true 130 case 1: 131 return false 132 } 133 134 return v[i].FilesystemId < v[j].FilesystemId 135 }