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