]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/plugin/discovery/find.go
vendor: github.com/hashicorp/terraform/...@v0.10.0
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / plugin / discovery / find.go
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 }