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  }