github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/tools/list.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package tools 5 6 import ( 7 "errors" 8 "fmt" 9 "strings" 10 11 "github.com/juju/utils/set" 12 13 "github.com/juju/juju/version" 14 ) 15 16 // List holds tools available in an environment. The order of tools within 17 // a List is not significant. 18 type List []*Tools 19 20 var ErrNoMatches = errors.New("no matching tools available") 21 22 // String returns the versions of the tools in src, separated by semicolons. 23 func (src List) String() string { 24 names := make([]string, len(src)) 25 for i, tools := range src { 26 names[i] = tools.Version.String() 27 } 28 return strings.Join(names, ";") 29 } 30 31 // AllSeries returns all series for which some tools in src were built. 32 func (src List) AllSeries() []string { 33 return src.collect(func(tools *Tools) string { 34 return tools.Version.Series 35 }) 36 } 37 38 // OneSeries returns the single series for which all tools in src were built. 39 func (src List) OneSeries() string { 40 series := src.AllSeries() 41 if len(series) != 1 { 42 panic(fmt.Errorf("should have gotten tools for one series, got %v", series)) 43 } 44 return series[0] 45 } 46 47 // Arches returns all architectures for which some tools in src were built. 48 func (src List) Arches() []string { 49 return src.collect(func(tools *Tools) string { 50 return tools.Version.Arch 51 }) 52 } 53 54 // collect calls f on all values in src and returns an alphabetically 55 // ordered list of the returned results without duplicates. 56 func (src List) collect(f func(*Tools) string) []string { 57 seen := make(set.Strings) 58 for _, tools := range src { 59 seen.Add(f(tools)) 60 } 61 return seen.SortedValues() 62 } 63 64 // URLs returns download URLs for the tools in src, keyed by binary version. 65 func (src List) URLs() map[version.Binary]string { 66 result := map[version.Binary]string{} 67 for _, tools := range src { 68 result[tools.Version] = tools.URL 69 } 70 return result 71 } 72 73 // Newest returns the greatest version in src, and the tools with that version. 74 func (src List) Newest() (version.Number, List) { 75 var result List 76 var best version.Number 77 for _, tools := range src { 78 if best.Compare(tools.Version.Number) < 0 { 79 // Found new best number; reset result list. 80 best = tools.Version.Number 81 result = append(result[:0], tools) 82 } else if tools.Version.Number == best { 83 result = append(result, tools) 84 } 85 } 86 return best, result 87 } 88 89 // NewestCompatible returns the most recent version compatible with 90 // base, i.e. with the same major and minor numbers and greater or 91 // equal patch and build numbers. 92 func (src List) NewestCompatible(base version.Number) (newest version.Number, found bool) { 93 newest = base 94 found = false 95 for _, tool := range src { 96 toolVersion := tool.Version.Number 97 if newest == toolVersion { 98 found = true 99 } else if newest.Compare(toolVersion) < 0 && 100 toolVersion.Major == newest.Major && 101 toolVersion.Minor == newest.Minor { 102 newest = toolVersion 103 found = true 104 } 105 } 106 return newest, found 107 } 108 109 // Exclude returns the tools in src that are not in excluded. 110 func (src List) Exclude(excluded List) List { 111 ignore := make(map[version.Binary]bool, len(excluded)) 112 for _, tool := range excluded { 113 ignore[tool.Version] = true 114 } 115 var result List 116 for _, tool := range src { 117 if !ignore[tool.Version] { 118 result = append(result, tool) 119 } 120 } 121 return result 122 } 123 124 // Match returns a List, derived from src, containing only those tools that 125 // match the supplied Filter. If no tools match, it returns ErrNoMatches. 126 func (src List) Match(f Filter) (List, error) { 127 var result List 128 for _, tools := range src { 129 if f.match(tools) { 130 result = append(result, tools) 131 } 132 } 133 if len(result) == 0 { 134 return nil, ErrNoMatches 135 } 136 return result, nil 137 } 138 139 func (l List) Len() int { return len(l) } 140 func (l List) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 141 func (l List) Less(i, j int) bool { return l[i].Version.String() < l[j].Version.String() } 142 143 // Filter holds criteria for choosing tools. 144 type Filter struct { 145 // Number, if non-zero, causes the filter to match only tools with 146 // that exact version number. 147 Number version.Number 148 149 // Series, if not empty, causes the filter to match only tools with 150 // that series. 151 Series string 152 153 // Arch, if not empty, causes the filter to match only tools with 154 // that architecture. 155 Arch string 156 } 157 158 // match returns true if the supplied tools match f. 159 func (f Filter) match(tools *Tools) bool { 160 if f.Number != version.Zero && tools.Version.Number != f.Number { 161 return false 162 } 163 if f.Series != "" && tools.Version.Series != f.Series { 164 return false 165 } 166 if f.Arch != "" && tools.Version.Arch != f.Arch { 167 return false 168 } 169 return true 170 }