3 // A PluginMetaSet is a set of PluginMeta objects meeting a certain criteria.
5 // Methods on this type allow filtering of the set to produce subsets that
6 // meet more restrictive criteria.
7 type PluginMetaSet map[PluginMeta]struct{}
9 // Add inserts the given PluginMeta into the receiving set. This is a no-op
10 // if the given meta is already present.
11 func (s PluginMetaSet) Add(p PluginMeta) {
15 // Remove removes the given PluginMeta from the receiving set. This is a no-op
16 // if the given meta is not already present.
17 func (s PluginMetaSet) Remove(p PluginMeta) {
21 // Has returns true if the given meta is in the receiving set, or false
23 func (s PluginMetaSet) Has(p PluginMeta) bool {
28 // Count returns the number of metas in the set
29 func (s PluginMetaSet) Count() int {
33 // ValidateVersions returns two new PluginMetaSets, separating those with
34 // versions that have syntax-valid semver versions from those that don't.
36 // Eliminating invalid versions from consideration (and possibly warning about
37 // them) is usually the first step of working with a meta set after discovery
39 func (s PluginMetaSet) ValidateVersions() (valid, invalid PluginMetaSet) {
40 valid = make(PluginMetaSet)
41 invalid = make(PluginMetaSet)
43 if _, err := p.Version.Parse(); err == nil {
52 // WithName returns the subset of metas that have the given name.
53 func (s PluginMetaSet) WithName(name string) PluginMetaSet {
54 ns := make(PluginMetaSet)
63 // WithVersion returns the subset of metas that have the given version.
65 // This should be used only with the "valid" result from ValidateVersions;
66 // it will ignore any plugin metas that have invalid version strings.
67 func (s PluginMetaSet) WithVersion(version Version) PluginMetaSet {
68 ns := make(PluginMetaSet)
70 gotVersion, err := p.Version.Parse()
74 if gotVersion.Equal(version) {
81 // ByName groups the metas in the set by their Names, returning a map.
82 func (s PluginMetaSet) ByName() map[string]PluginMetaSet {
83 ret := make(map[string]PluginMetaSet)
85 if _, ok := ret[p.Name]; !ok {
86 ret[p.Name] = make(PluginMetaSet)
93 // Newest returns the one item from the set that has the newest Version value.
95 // The result is meaningful only if the set is already filtered such that
96 // all of the metas have the same Name.
98 // If there isn't at least one meta in the set then this function will panic.
99 // Use Count() to ensure that there is at least one value before calling.
101 // If any of the metas have invalid version strings then this function will
102 // panic. Use ValidateVersions() first to filter out metas with invalid
105 // If two metas have the same Version then one is arbitrarily chosen. This
106 // situation should be avoided by pre-filtering the set.
107 func (s PluginMetaSet) Newest() PluginMeta {
109 panic("can't call NewestStable on empty PluginMetaSet")
113 var winner PluginMeta
114 var winnerVersion Version
116 version, err := p.Version.Parse()
121 if first == true || version.NewerThan(winnerVersion) {
123 winnerVersion = version
131 // ConstrainVersions takes a set of requirements and attempts to
132 // return a map from name to a set of metas that have the matching
133 // name and an appropriate version.
135 // If any of the given requirements match *no* plugins then its PluginMetaSet
136 // in the returned map will be empty.
138 // All viable metas are returned, so the caller can apply any desired filtering
139 // to reduce down to a single option. For example, calling Newest() to obtain
140 // the highest available version.
142 // If any of the metas in the set have invalid version strings then this
143 // function will panic. Use ValidateVersions() first to filter out metas with
145 func (s PluginMetaSet) ConstrainVersions(reqd PluginRequirements) map[string]PluginMetaSet {
146 ret := make(map[string]PluginMetaSet)
149 allowedVersions, ok := reqd[name]
153 if _, ok := ret[p.Name]; !ok {
154 ret[p.Name] = make(PluginMetaSet)
156 version, err := p.Version.Parse()
160 if allowedVersions.Allows(version) {
167 // OverridePaths returns a new set where any existing plugins with the given
168 // names are removed and replaced with the single path given in the map.
170 // This is here only to continue to support the legacy way of overriding
171 // plugin binaries in the .terraformrc file. It treats all given plugins
172 // as pre-versioning (version 0.0.0). This mechanism will eventually be
173 // phased out, with vendor directories being the intended replacement.
174 func (s PluginMetaSet) OverridePaths(paths map[string]string) PluginMetaSet {
175 ret := make(PluginMetaSet)
177 if _, ok := paths[p.Name]; ok {
178 // Skip plugins that we're overridding
185 // Now add the metadata for overriding plugins
186 for name, path := range paths {
189 Version: VersionZero,