]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/internal/initwd/getter.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / internal / initwd / getter.go
1 package initwd
2
3 import (
4 "fmt"
5 "log"
6 "os"
7 "path/filepath"
8 "strings"
9
10 cleanhttp "github.com/hashicorp/go-cleanhttp"
11 getter "github.com/hashicorp/go-getter"
12 "github.com/hashicorp/terraform/registry/regsrc"
13 )
14
15 // We configure our own go-getter detector and getter sets here, because
16 // the set of sources we support is part of Terraform's documentation and
17 // so we don't want any new sources introduced in go-getter to sneak in here
18 // and work even though they aren't documented. This also insulates us from
19 // any meddling that might be done by other go-getter callers linked into our
20 // executable.
21
22 var goGetterDetectors = []getter.Detector{
23 new(getter.GitHubDetector),
24 new(getter.BitBucketDetector),
25 new(getter.S3Detector),
26 new(getter.FileDetector),
27 }
28
29 var goGetterNoDetectors = []getter.Detector{}
30
31 var goGetterDecompressors = map[string]getter.Decompressor{
32 "bz2": new(getter.Bzip2Decompressor),
33 "gz": new(getter.GzipDecompressor),
34 "xz": new(getter.XzDecompressor),
35 "zip": new(getter.ZipDecompressor),
36
37 "tar.bz2": new(getter.TarBzip2Decompressor),
38 "tar.tbz2": new(getter.TarBzip2Decompressor),
39
40 "tar.gz": new(getter.TarGzipDecompressor),
41 "tgz": new(getter.TarGzipDecompressor),
42
43 "tar.xz": new(getter.TarXzDecompressor),
44 "txz": new(getter.TarXzDecompressor),
45 }
46
47 var goGetterGetters = map[string]getter.Getter{
48 "file": new(getter.FileGetter),
49 "git": new(getter.GitGetter),
50 "hg": new(getter.HgGetter),
51 "s3": new(getter.S3Getter),
52 "http": getterHTTPGetter,
53 "https": getterHTTPGetter,
54 }
55
56 var getterHTTPClient = cleanhttp.DefaultClient()
57
58 var getterHTTPGetter = &getter.HttpGetter{
59 Client: getterHTTPClient,
60 Netrc: true,
61 }
62
63 // A reusingGetter is a helper for the module installer that remembers
64 // the final resolved addresses of all of the sources it has already been
65 // asked to install, and will copy from a prior installation directory if
66 // it has the same resolved source address.
67 //
68 // The keys in a reusingGetter are resolved and trimmed source addresses
69 // (with a scheme always present, and without any "subdir" component),
70 // and the values are the paths where each source was previously installed.
71 type reusingGetter map[string]string
72
73 // getWithGoGetter retrieves the package referenced in the given address
74 // into the installation path and then returns the full path to any subdir
75 // indicated in the address.
76 //
77 // The errors returned by this function are those surfaced by the underlying
78 // go-getter library, which have very inconsistent quality as
79 // end-user-actionable error messages. At this time we do not have any
80 // reasonable way to improve these error messages at this layer because
81 // the underlying errors are not separately recognizable.
82 func (g reusingGetter) getWithGoGetter(instPath, addr string) (string, error) {
83 packageAddr, subDir := splitAddrSubdir(addr)
84
85 log.Printf("[DEBUG] will download %q to %s", packageAddr, instPath)
86
87 realAddr, err := getter.Detect(packageAddr, instPath, getter.Detectors)
88 if err != nil {
89 return "", err
90 }
91
92 if isMaybeRelativeLocalPath(realAddr) {
93 return "", &MaybeRelativePathErr{addr}
94 }
95
96 var realSubDir string
97 realAddr, realSubDir = splitAddrSubdir(realAddr)
98 if realSubDir != "" {
99 subDir = filepath.Join(realSubDir, subDir)
100 }
101
102 if realAddr != packageAddr {
103 log.Printf("[TRACE] go-getter detectors rewrote %q to %q", packageAddr, realAddr)
104 }
105
106 if prevDir, exists := g[realAddr]; exists {
107 log.Printf("[TRACE] copying previous install %s to %s", prevDir, instPath)
108 err := os.Mkdir(instPath, os.ModePerm)
109 if err != nil {
110 return "", fmt.Errorf("failed to create directory %s: %s", instPath, err)
111 }
112 err = copyDir(instPath, prevDir)
113 if err != nil {
114 return "", fmt.Errorf("failed to copy from %s to %s: %s", prevDir, instPath, err)
115 }
116 } else {
117 log.Printf("[TRACE] fetching %q to %q", realAddr, instPath)
118 client := getter.Client{
119 Src: realAddr,
120 Dst: instPath,
121 Pwd: instPath,
122
123 Mode: getter.ClientModeDir,
124
125 Detectors: goGetterNoDetectors, // we already did detection above
126 Decompressors: goGetterDecompressors,
127 Getters: goGetterGetters,
128 }
129 err = client.Get()
130 if err != nil {
131 return "", err
132 }
133 // Remember where we installed this so we might reuse this directory
134 // on subsequent calls to avoid re-downloading.
135 g[realAddr] = instPath
136 }
137
138 // Our subDir string can contain wildcards until this point, so that
139 // e.g. a subDir of * can expand to one top-level directory in a .tar.gz
140 // archive. Now that we've expanded the archive successfully we must
141 // resolve that into a concrete path.
142 var finalDir string
143 if subDir != "" {
144 finalDir, err = getter.SubdirGlob(instPath, subDir)
145 log.Printf("[TRACE] expanded %q to %q", subDir, finalDir)
146 if err != nil {
147 return "", err
148 }
149 } else {
150 finalDir = instPath
151 }
152
153 // If we got this far then we have apparently succeeded in downloading
154 // the requested object!
155 return filepath.Clean(finalDir), nil
156 }
157
158 // splitAddrSubdir splits the given address (which is assumed to be a
159 // registry address or go-getter-style address) into a package portion
160 // and a sub-directory portion.
161 //
162 // The package portion defines what should be downloaded and then the
163 // sub-directory portion, if present, specifies a sub-directory within
164 // the downloaded object (an archive, VCS repository, etc) that contains
165 // the module's configuration files.
166 //
167 // The subDir portion will be returned as empty if no subdir separator
168 // ("//") is present in the address.
169 func splitAddrSubdir(addr string) (packageAddr, subDir string) {
170 return getter.SourceDirSubdir(addr)
171 }
172
173 var localSourcePrefixes = []string{
174 "./",
175 "../",
176 ".\\",
177 "..\\",
178 }
179
180 func isLocalSourceAddr(addr string) bool {
181 for _, prefix := range localSourcePrefixes {
182 if strings.HasPrefix(addr, prefix) {
183 return true
184 }
185 }
186 return false
187 }
188
189 func isRegistrySourceAddr(addr string) bool {
190 _, err := regsrc.ParseModuleSource(addr)
191 return err == nil
192 }
193
194 type MaybeRelativePathErr struct {
195 Addr string
196 }
197
198 func (e *MaybeRelativePathErr) Error() string {
199 return fmt.Sprintf("Terraform cannot determine the module source for %s", e.Addr)
200 }
201
202 func isMaybeRelativeLocalPath(addr string) bool {
203 if strings.HasPrefix(addr, "file://") {
204 _, err := os.Stat(addr[7:])
205 if err != nil {
206 return true
207 }
208 }
209 return false
210 }