github.com/weiwenhao/getter@v1.30.1/get.go (about) 1 // getter is a package for downloading files or directories from a variety of 2 // protocols. 3 // 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/weiwenhao/getter" would turn into a Git URL and 7 // use the Git protocol. 8 // 9 // Protocols and detectors are extensible. 10 // 11 // To get started, see Client. 12 package getter 13 14 import ( 15 "bytes" 16 "fmt" 17 "net/url" 18 "os/exec" 19 "regexp" 20 "syscall" 21 22 cleanhttp "github.com/hashicorp/go-cleanhttp" 23 ) 24 25 // Getter defines the interface that schemes must implement to download 26 // things. 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. 30 // 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 35 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 40 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) 44 45 // SetClient allows a getter to know it's client 46 // in order to access client's Get functions or 47 // progress tracking. 48 SetClient(*Client) 49 } 50 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 54 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]+)::(.+)$`) 58 59 // httpClient is the default client to be used by HttpGetters. 60 var httpClient = cleanhttp.DefaultClient() 61 62 func init() { 63 httpGetter := &HttpGetter{ 64 Netrc: true, 65 } 66 67 Getters = map[string]Getter{ 68 "file": new(FileGetter), 69 "http": httpGetter, 70 "https": httpGetter, 71 } 72 } 73 74 // Get downloads the directory specified by src into the folder specified by 75 // dst. If dst already exists, Get will attempt to update it. 76 // 77 // src is a URL, whereas dst is always just a file path to a folder. This 78 // folder doesn't need to exist. It will be created if it doesn't exist. 79 func Get(dst, src string, opts ...ClientOption) error { 80 return (&Client{ 81 Src: src, 82 Dst: dst, 83 Dir: true, 84 Options: opts, 85 }).Get() 86 } 87 88 // GetAny downloads a URL into the given destination. Unlike Get or 89 // GetFile, both directories and files are supported. 90 // 91 // dst must be a directory. If src is a file, it will be downloaded 92 // into dst with the basename of the URL. If src is a directory or 93 // archive, it will be unpacked directly into dst. 94 func GetAny(dst, src string, opts ...ClientOption) error { 95 return (&Client{ 96 Src: src, 97 Dst: dst, 98 Mode: ClientModeAny, 99 Options: opts, 100 }).Get() 101 } 102 103 // GetFile downloads the file specified by src into the path specified by 104 // dst. 105 func GetFile(dst, src string, opts ...ClientOption) error { 106 return (&Client{ 107 Src: src, 108 Dst: dst, 109 Dir: false, 110 Options: opts, 111 }).Get() 112 } 113 114 // getRunCommand is a helper that will run a command and capture the output 115 // in the case an error happens. 116 func getRunCommand(cmd *exec.Cmd) error { 117 var buf bytes.Buffer 118 cmd.Stdout = &buf 119 cmd.Stderr = &buf 120 err := cmd.Run() 121 if err == nil { 122 return nil 123 } 124 if exiterr, ok := err.(*exec.ExitError); ok { 125 // The program has exited with an exit code != 0 126 if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { 127 return fmt.Errorf( 128 "%s exited with %d: %s", 129 cmd.Path, 130 status.ExitStatus(), 131 buf.String()) 132 } 133 } 134 135 return fmt.Errorf("error running %s: %s", cmd.Path, buf.String()) 136 } 137 138 // getForcedGetter takes a source and returns the tuple of the forced 139 // getter and the raw URL (without the force syntax). 140 func getForcedGetter(src string) (string, string) { 141 var forced string 142 if ms := forcedRegexp.FindStringSubmatch(src); ms != nil { 143 forced = ms[1] 144 src = ms[2] 145 } 146 147 return forced, src 148 }