diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/plugin/discovery/find.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/plugin/discovery/find.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go new file mode 100644 index 0000000..f5bc4c1 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go | |||
@@ -0,0 +1,168 @@ | |||
1 | package discovery | ||
2 | |||
3 | import ( | ||
4 | "io/ioutil" | ||
5 | "log" | ||
6 | "path/filepath" | ||
7 | "strings" | ||
8 | ) | ||
9 | |||
10 | // FindPlugins looks in the given directories for files whose filenames | ||
11 | // suggest that they are plugins of the given kind (e.g. "provider") and | ||
12 | // returns a PluginMetaSet representing the discovered potential-plugins. | ||
13 | // | ||
14 | // Currently this supports two different naming schemes. The current | ||
15 | // standard naming scheme is a subdirectory called $GOOS-$GOARCH containing | ||
16 | // files named terraform-$KIND-$NAME-V$VERSION. The legacy naming scheme is | ||
17 | // files directly in the given directory whose names are like | ||
18 | // terraform-$KIND-$NAME. | ||
19 | // | ||
20 | // Only one plugin will be returned for each unique plugin (name, version) | ||
21 | // pair, with preference given to files found in earlier directories. | ||
22 | // | ||
23 | // This is a convenience wrapper around FindPluginPaths and ResolvePluginsPaths. | ||
24 | func FindPlugins(kind string, dirs []string) PluginMetaSet { | ||
25 | return ResolvePluginPaths(FindPluginPaths(kind, dirs)) | ||
26 | } | ||
27 | |||
28 | // FindPluginPaths looks in the given directories for files whose filenames | ||
29 | // suggest that they are plugins of the given kind (e.g. "provider"). | ||
30 | // | ||
31 | // The return value is a list of absolute paths that appear to refer to | ||
32 | // plugins in the given directories, based only on what can be inferred | ||
33 | // from the naming scheme. The paths returned are ordered such that files | ||
34 | // in later dirs appear after files in earlier dirs in the given directory | ||
35 | // list. Within the same directory plugins are returned in a consistent but | ||
36 | // undefined order. | ||
37 | func FindPluginPaths(kind string, dirs []string) []string { | ||
38 | // This is just a thin wrapper around findPluginPaths so that we can | ||
39 | // use the latter in tests with a fake machineName so we can use our | ||
40 | // test fixtures. | ||
41 | return findPluginPaths(kind, dirs) | ||
42 | } | ||
43 | |||
44 | func findPluginPaths(kind string, dirs []string) []string { | ||
45 | prefix := "terraform-" + kind + "-" | ||
46 | |||
47 | ret := make([]string, 0, len(dirs)) | ||
48 | |||
49 | for _, dir := range dirs { | ||
50 | items, err := ioutil.ReadDir(dir) | ||
51 | if err != nil { | ||
52 | // Ignore missing dirs, non-dirs, etc | ||
53 | continue | ||
54 | } | ||
55 | |||
56 | log.Printf("[DEBUG] checking for %s in %q", kind, dir) | ||
57 | |||
58 | for _, item := range items { | ||
59 | fullName := item.Name() | ||
60 | |||
61 | if !strings.HasPrefix(fullName, prefix) { | ||
62 | log.Printf("[DEBUG] skipping %q, not a %s", fullName, kind) | ||
63 | continue | ||
64 | } | ||
65 | |||
66 | // New-style paths must have a version segment in filename | ||
67 | if strings.Contains(strings.ToLower(fullName), "_v") { | ||
68 | absPath, err := filepath.Abs(filepath.Join(dir, fullName)) | ||
69 | if err != nil { | ||
70 | log.Printf("[ERROR] plugin filepath error: %s", err) | ||
71 | continue | ||
72 | } | ||
73 | |||
74 | log.Printf("[DEBUG] found %s %q", kind, fullName) | ||
75 | ret = append(ret, filepath.Clean(absPath)) | ||
76 | continue | ||
77 | } | ||
78 | |||
79 | // Legacy style with files directly in the base directory | ||
80 | absPath, err := filepath.Abs(filepath.Join(dir, fullName)) | ||
81 | if err != nil { | ||
82 | log.Printf("[ERROR] plugin filepath error: %s", err) | ||
83 | continue | ||
84 | } | ||
85 | |||
86 | log.Printf("[WARNING] found legacy %s %q", kind, fullName) | ||
87 | |||
88 | ret = append(ret, filepath.Clean(absPath)) | ||
89 | } | ||
90 | } | ||
91 | |||
92 | return ret | ||
93 | } | ||
94 | |||
95 | // ResolvePluginPaths takes a list of paths to plugin executables (as returned | ||
96 | // by e.g. FindPluginPaths) and produces a PluginMetaSet describing the | ||
97 | // referenced plugins. | ||
98 | // | ||
99 | // If the same combination of plugin name and version appears multiple times, | ||
100 | // the earlier reference will be preferred. Several different versions of | ||
101 | // the same plugin name may be returned, in which case the methods of | ||
102 | // PluginMetaSet can be used to filter down. | ||
103 | func ResolvePluginPaths(paths []string) PluginMetaSet { | ||
104 | s := make(PluginMetaSet) | ||
105 | |||
106 | type nameVersion struct { | ||
107 | Name string | ||
108 | Version string | ||
109 | } | ||
110 | found := make(map[nameVersion]struct{}) | ||
111 | |||
112 | for _, path := range paths { | ||
113 | baseName := strings.ToLower(filepath.Base(path)) | ||
114 | if !strings.HasPrefix(baseName, "terraform-") { | ||
115 | // Should never happen with reasonable input | ||
116 | continue | ||
117 | } | ||
118 | |||
119 | baseName = baseName[10:] | ||
120 | firstDash := strings.Index(baseName, "-") | ||
121 | if firstDash == -1 { | ||
122 | // Should never happen with reasonable input | ||
123 | continue | ||
124 | } | ||
125 | |||
126 | baseName = baseName[firstDash+1:] | ||
127 | if baseName == "" { | ||
128 | // Should never happen with reasonable input | ||
129 | continue | ||
130 | } | ||
131 | |||
132 | // Trim the .exe suffix used on Windows before we start wrangling | ||
133 | // the remainder of the path. | ||
134 | if strings.HasSuffix(baseName, ".exe") { | ||
135 | baseName = baseName[:len(baseName)-4] | ||
136 | } | ||
137 | |||
138 | parts := strings.SplitN(baseName, "_v", 2) | ||
139 | name := parts[0] | ||
140 | version := VersionZero | ||
141 | if len(parts) == 2 { | ||
142 | version = parts[1] | ||
143 | } | ||
144 | |||
145 | // Auto-installed plugins contain an extra name portion representing | ||
146 | // the expected plugin version, which we must trim off. | ||
147 | if underX := strings.Index(version, "_x"); underX != -1 { | ||
148 | version = version[:underX] | ||
149 | } | ||
150 | |||
151 | if _, ok := found[nameVersion{name, version}]; ok { | ||
152 | // Skip duplicate versions of the same plugin | ||
153 | // (We do this during this step because after this we will be | ||
154 | // dealing with sets and thus lose our ordering with which to | ||
155 | // decide preference.) | ||
156 | continue | ||
157 | } | ||
158 | |||
159 | s.Add(PluginMeta{ | ||
160 | Name: name, | ||
161 | Version: VersionStr(version), | ||
162 | Path: path, | ||
163 | }) | ||
164 | found[nameVersion{name, version}] = struct{}{} | ||
165 | } | ||
166 | |||
167 | return s | ||
168 | } | ||