1 // getter is a package for downloading files or directories from a variety of
4 // getter is unique in its ability to download both directories and files.
5 // It also detects certain source strings to be protocol-specific URLs. For
6 // example, "github.com/hashicorp/go-getter" would turn into a Git URL and
7 // use the Git protocol.
9 // Protocols and detectors are extensible.
11 // To get started, see Client.
22 cleanhttp "github.com/hashicorp/go-cleanhttp"
25 // Getter defines the interface that schemes must implement to download
27 type Getter interface {
28 // Get downloads the given URL into the given directory. This always
29 // assumes that we're updating and gets the latest version that it can.
31 // The directory may already exist (if we're updating). If it is in a
32 // format that isn't understood, an error should be returned. Get shouldn't
33 // simply nuke the directory.
34 Get(string, *url.URL) error
36 // GetFile downloads the give URL into the given path. The URL must
37 // reference a single file. If possible, the Getter should check if
38 // the remote end contains the same file and no-op this operation.
39 GetFile(string, *url.URL) error
41 // ClientMode returns the mode based on the given URL. This is used to
42 // allow clients to let the getters decide which mode to use.
43 ClientMode(*url.URL) (ClientMode, error)
45 // SetClient allows a getter to know it's client
46 // in order to access client's Get functions or
51 // Getters is the mapping of scheme to the Getter implementation that will
52 // be used to get a dependency.
53 var Getters map[string]Getter
55 // forcedRegexp is the regular expression that finds forced getters. This
56 // syntax is schema::url, example: git::https://foo.com
57 var forcedRegexp = regexp.MustCompile(`^([A-Za-z0-9]+)::(.+)$`)
59 // httpClient is the default client to be used by HttpGetters.
60 var httpClient = cleanhttp.DefaultClient()
63 httpGetter := &HttpGetter{
67 Getters = map[string]Getter{
68 "file": new(FileGetter),
69 "git": new(GitGetter),
70 "gcs": new(GCSGetter),
78 // Get downloads the directory specified by src into the folder specified by
79 // dst. If dst already exists, Get will attempt to update it.
81 // src is a URL, whereas dst is always just a file path to a folder. This
82 // folder doesn't need to exist. It will be created if it doesn't exist.
83 func Get(dst, src string, opts ...ClientOption) error {
92 // GetAny downloads a URL into the given destination. Unlike Get or
93 // GetFile, both directories and files are supported.
95 // dst must be a directory. If src is a file, it will be downloaded
96 // into dst with the basename of the URL. If src is a directory or
97 // archive, it will be unpacked directly into dst.
98 func GetAny(dst, src string, opts ...ClientOption) error {
107 // GetFile downloads the file specified by src into the path specified by
109 func GetFile(dst, src string, opts ...ClientOption) error {
118 // getRunCommand is a helper that will run a command and capture the output
119 // in the case an error happens.
120 func getRunCommand(cmd *exec.Cmd) error {
128 if exiterr, ok := err.(*exec.ExitError); ok {
129 // The program has exited with an exit code != 0
130 if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
132 "%s exited with %d: %s",
139 return fmt.Errorf("error running %s: %s", cmd.Path, buf.String())
142 // getForcedGetter takes a source and returns the tuple of the forced
143 // getter and the raw URL (without the force syntax).
144 func getForcedGetter(src string) (string, string) {
146 if ms := forcedRegexp.FindStringSubmatch(src); ms != nil {