Merge pull request #5739 from hashicorp/deps-update-go-getter
deps: Update hashicorp/go-getter
This commit is contained in:
commit
bceb795c07
|
@ -633,11 +633,11 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-getter",
|
||||
"Rev": "848242c76c346ef0aeb34787753b068f5f6f92fe"
|
||||
"Rev": "2822987a64e0df1236ac29dd277ddf79f4871f9a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-getter/helper/url",
|
||||
"Rev": "848242c76c346ef0aeb34787753b068f5f6f92fe"
|
||||
"Rev": "2822987a64e0df1236ac29dd277ddf79f4871f9a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-multierror",
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
# go-getter
|
||||
|
||||
[![Build Status](http://img.shields.io/travis/hashicorp/go-getter.svg?style=flat-square)][travis]
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/ulq3qr43n62croyq/branch/master?svg=true)][appveyor]
|
||||
[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]
|
||||
|
||||
[travis]: http://travis-ci.org/hashicorp/go-getter
|
||||
[godocs]: http://godoc.org/github.com/hashicorp/go-getter
|
||||
[appveyor]: https://ci.appveyor.com/project/hashicorp/go-getter/branch/master
|
||||
|
||||
go-getter is a library for Go (golang) for downloading files or directories
|
||||
from various sources using a URL as the primary form of input.
|
||||
|
@ -34,9 +36,21 @@ Installation can be done with a normal `go get`:
|
|||
$ go get github.com/hashicorp/go-getter
|
||||
```
|
||||
|
||||
go-getter also has a command you can use to test URL strings:
|
||||
|
||||
```
|
||||
$ go install github.com/hashicorp/go-getter/cmd/go-getter
|
||||
...
|
||||
|
||||
$ go-getter github.com/foo/bar ./foo
|
||||
...
|
||||
```
|
||||
|
||||
The command is useful for verifying URL structures.
|
||||
|
||||
## URL Format
|
||||
|
||||
go-getter uses a single string URL as input to downlaod from a variety of
|
||||
go-getter uses a single string URL as input to download from a variety of
|
||||
protocols. go-getter has various "tricks" with this URL to do certain things.
|
||||
This section documents the URL format.
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
version: "build-{branch}-{build}"
|
||||
image: Visual Studio 2015
|
||||
clone_folder: c:\gopath\github.com\hashicorp\go-getter
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
install:
|
||||
- cmd: >-
|
||||
echo %Path%
|
||||
|
||||
go version
|
||||
|
||||
go env
|
||||
|
||||
go get -d -v -t ./...
|
||||
build_script:
|
||||
- cmd: go test -v ./...
|
|
@ -38,11 +38,9 @@ type Client struct {
|
|||
Dst string
|
||||
Pwd string
|
||||
|
||||
// Dir, if true, tells the Client it is downloading a directory (versus
|
||||
// a single file). This distinction is necessary since filenames and
|
||||
// directory names follow the same format so disambiguating is impossible
|
||||
// without knowing ahead of time.
|
||||
Dir bool
|
||||
// Mode is the method of download the client will use. See ClientMode
|
||||
// for documentation.
|
||||
Mode ClientMode
|
||||
|
||||
// Detectors is the list of detectors that are tried on the source.
|
||||
// If this is nil, then the default Detectors will be used.
|
||||
|
@ -55,12 +53,27 @@ type Client struct {
|
|||
// Getters is the map of protocols supported by this client. If this
|
||||
// is nil, then the default Getters variable will be used.
|
||||
Getters map[string]Getter
|
||||
|
||||
// Dir, if true, tells the Client it is downloading a directory (versus
|
||||
// a single file). This distinction is necessary since filenames and
|
||||
// directory names follow the same format so disambiguating is impossible
|
||||
// without knowing ahead of time.
|
||||
//
|
||||
// WARNING: deprecated. If Mode is set, that will take precedence.
|
||||
Dir bool
|
||||
}
|
||||
|
||||
// Get downloads the configured source to the destination.
|
||||
func (c *Client) Get() error {
|
||||
// Store this locally since there are cases we swap this
|
||||
dir := c.Dir
|
||||
mode := c.Mode
|
||||
if mode == ClientModeInvalid {
|
||||
if c.Dir {
|
||||
mode = ClientModeDir
|
||||
} else {
|
||||
mode = ClientModeFile
|
||||
}
|
||||
}
|
||||
|
||||
// Default decompressor value
|
||||
decompressors := c.Decompressors
|
||||
|
@ -166,9 +179,9 @@ func (c *Client) Get() error {
|
|||
// Swap the download directory to be our temporary path and
|
||||
// store the old values.
|
||||
decompressDst = dst
|
||||
decompressDir = dir
|
||||
decompressDir = mode != ClientModeFile
|
||||
dst = filepath.Join(td, "archive")
|
||||
dir = false
|
||||
mode = ClientModeFile
|
||||
}
|
||||
|
||||
// Determine if we have a checksum
|
||||
|
@ -179,13 +192,6 @@ func (c *Client) Get() error {
|
|||
q.Del("checksum")
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
// If we're getting a directory, then this is an error. You cannot
|
||||
// checksum a directory. TODO: test
|
||||
if dir {
|
||||
return fmt.Errorf(
|
||||
"checksum cannot be specified for directory download")
|
||||
}
|
||||
|
||||
// Determine the checksum hash type
|
||||
checksumType := ""
|
||||
idx := strings.Index(v, ":")
|
||||
|
@ -216,9 +222,18 @@ func (c *Client) Get() error {
|
|||
checksumValue = b
|
||||
}
|
||||
|
||||
// For now, any means file. In the future, we'll ask the getter
|
||||
// what it thinks it is.
|
||||
if mode == ClientModeAny {
|
||||
mode = ClientModeFile
|
||||
|
||||
// Destination is the base name of the URL path
|
||||
dst = filepath.Join(dst, filepath.Base(u.Path))
|
||||
}
|
||||
|
||||
// If we're not downloading a directory, then just download the file
|
||||
// and return.
|
||||
if !dir {
|
||||
if mode == ClientModeFile {
|
||||
err := g.GetFile(dst, u)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -240,13 +255,17 @@ func (c *Client) Get() error {
|
|||
|
||||
// Swap the information back
|
||||
dst = decompressDst
|
||||
dir = decompressDir
|
||||
if decompressDir {
|
||||
mode = ClientModeAny
|
||||
} else {
|
||||
mode = ClientModeFile
|
||||
}
|
||||
}
|
||||
|
||||
// We check the dir value again because it can be switched back
|
||||
// if we were unarchiving. If we're still only Get-ing a file, then
|
||||
// we're done.
|
||||
if !dir {
|
||||
if mode == ClientModeFile {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -256,6 +275,13 @@ func (c *Client) Get() error {
|
|||
// In the case we have a decompressor we don't Get because it was Get
|
||||
// above.
|
||||
if decompressor == nil {
|
||||
// If we're getting a directory, then this is an error. You cannot
|
||||
// checksum a directory. TODO: test
|
||||
if checksumHash != nil {
|
||||
return fmt.Errorf(
|
||||
"checksum cannot be specified for directory download")
|
||||
}
|
||||
|
||||
// We're downloading a directory, which might require a bit more work
|
||||
// if we're specifying a subdir.
|
||||
err := g.Get(dst, u)
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package getter
|
||||
|
||||
// ClientMode is the mode that the client operates in.
|
||||
type ClientMode uint
|
||||
|
||||
const (
|
||||
ClientModeInvalid ClientMode = iota
|
||||
|
||||
// ClientModeAny downloads anything it can. In this mode, dst must
|
||||
// be a directory. If src is a file, it is saved into the directory
|
||||
// with the basename of the URL. If src is a directory or archive,
|
||||
// it is unpacked directly into dst.
|
||||
ClientModeAny
|
||||
|
||||
// ClientModeFile downloads a single file. In this mode, dst must
|
||||
// be a file path (doesn't have to exist). src must point to a single
|
||||
// file. It is saved as dst.
|
||||
ClientModeFile
|
||||
|
||||
// ClientModeDir downloads a directory. In this mode, dst must be
|
||||
// a directory path (doesn't have to exist). src must point to an
|
||||
// archive or directory (such as in s3).
|
||||
ClientModeDir
|
||||
)
|
|
@ -92,6 +92,11 @@ func testListDir(t *testing.T, path string) []string {
|
|||
}
|
||||
sub = sub[1:] // Trim the leading path sep.
|
||||
|
||||
// If it is a dir, add trailing sep
|
||||
if info.IsDir() {
|
||||
sub += "/"
|
||||
}
|
||||
|
||||
result = append(result, sub)
|
||||
return nil
|
||||
})
|
||||
|
|
|
@ -60,7 +60,7 @@ func (d *TarGzipDecompressor) Decompress(dst, src string, dir bool) error {
|
|||
}
|
||||
|
||||
if hdr.FileInfo().IsDir() {
|
||||
if dir {
|
||||
if !dir {
|
||||
return fmt.Errorf("expected a single file: %s", src)
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,21 @@ func Get(dst, src string) error {
|
|||
}).Get()
|
||||
}
|
||||
|
||||
// GetAny downloads a URL into the given destination. Unlike Get or
|
||||
// GetFile, both directories and files are supported.
|
||||
//
|
||||
// dst must be a directory. If src is a file, it will be downloaded
|
||||
// into dst with the basename of the URL. If src is a directory or
|
||||
// archive, it will be unpacked directly into dst.
|
||||
func GetAny(dst, src string) error {
|
||||
return (&Client{
|
||||
Src: src,
|
||||
Dst: dst,
|
||||
Mode: ClientModeAny,
|
||||
Getters: Getters,
|
||||
}).Get()
|
||||
}
|
||||
|
||||
// GetFile downloads the file specified by src into the path specified by
|
||||
// dst.
|
||||
func GetFile(dst, src string) error {
|
||||
|
|
|
@ -1,98 +1,8 @@
|
|||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// FileGetter is a Getter implementation that will download a module from
|
||||
// a file scheme.
|
||||
type FileGetter struct {
|
||||
// Copy, if set to true, will copy data instead of using a symlink
|
||||
Copy bool
|
||||
}
|
||||
|
||||
func (g *FileGetter) Get(dst string, u *url.URL) error {
|
||||
// The source path must exist and be a directory to be usable.
|
||||
if fi, err := os.Stat(u.Path); err != nil {
|
||||
return fmt.Errorf("source path error: %s", err)
|
||||
} else if !fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a directory")
|
||||
}
|
||||
|
||||
fi, err := os.Lstat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the destination already exists, it must be a symlink
|
||||
if err == nil {
|
||||
mode := fi.Mode()
|
||||
if mode&os.ModeSymlink == 0 {
|
||||
return fmt.Errorf("destination exists and is not a symlink")
|
||||
}
|
||||
|
||||
// Remove the destination
|
||||
if err := os.Remove(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.Symlink(u.Path, dst)
|
||||
}
|
||||
|
||||
func (g *FileGetter) GetFile(dst string, u *url.URL) error {
|
||||
// The source path must exist and be a directory to be usable.
|
||||
if fi, err := os.Stat(u.Path); err != nil {
|
||||
return fmt.Errorf("source path error: %s", err)
|
||||
} else if fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a file")
|
||||
}
|
||||
|
||||
_, err := os.Lstat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the destination already exists, it must be a symlink
|
||||
if err == nil {
|
||||
// Remove the destination
|
||||
if err := os.Remove(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we're not copying, just symlink and we're done
|
||||
if !g.Copy {
|
||||
return os.Symlink(u.Path, dst)
|
||||
}
|
||||
|
||||
// Copy
|
||||
srcF, err := os.Open(u.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcF.Close()
|
||||
|
||||
dstF, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstF.Close()
|
||||
|
||||
_, err = io.Copy(dstF, srcF)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
// +build !windows
|
||||
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func (g *FileGetter) Get(dst string, u *url.URL) error {
|
||||
// The source path must exist and be a directory to be usable.
|
||||
if fi, err := os.Stat(u.Path); err != nil {
|
||||
return fmt.Errorf("source path error: %s", err)
|
||||
} else if !fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a directory")
|
||||
}
|
||||
|
||||
fi, err := os.Lstat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the destination already exists, it must be a symlink
|
||||
if err == nil {
|
||||
mode := fi.Mode()
|
||||
if mode&os.ModeSymlink == 0 {
|
||||
return fmt.Errorf("destination exists and is not a symlink")
|
||||
}
|
||||
|
||||
// Remove the destination
|
||||
if err := os.Remove(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.Symlink(u.Path, dst)
|
||||
}
|
||||
|
||||
func (g *FileGetter) GetFile(dst string, u *url.URL) error {
|
||||
// The source path must exist and be a directory to be usable.
|
||||
if fi, err := os.Stat(u.Path); err != nil {
|
||||
return fmt.Errorf("source path error: %s", err)
|
||||
} else if fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a file")
|
||||
}
|
||||
|
||||
_, err := os.Lstat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the destination already exists, it must be a symlink
|
||||
if err == nil {
|
||||
// Remove the destination
|
||||
if err := os.Remove(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we're not copying, just symlink and we're done
|
||||
if !g.Copy {
|
||||
return os.Symlink(u.Path, dst)
|
||||
}
|
||||
|
||||
// Copy
|
||||
srcF, err := os.Open(u.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcF.Close()
|
||||
|
||||
dstF, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstF.Close()
|
||||
|
||||
_, err = io.Copy(dstF, srcF)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
// +build windows
|
||||
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (g *FileGetter) Get(dst string, u *url.URL) error {
|
||||
// The source path must exist and be a directory to be usable.
|
||||
if fi, err := os.Stat(u.Path); err != nil {
|
||||
return fmt.Errorf("source path error: %s", err)
|
||||
} else if !fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a directory")
|
||||
}
|
||||
|
||||
fi, err := os.Lstat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the destination already exists, it must be a symlink
|
||||
if err == nil {
|
||||
mode := fi.Mode()
|
||||
if mode&os.ModeSymlink == 0 {
|
||||
return fmt.Errorf("destination exists and is not a symlink")
|
||||
}
|
||||
|
||||
// Remove the destination
|
||||
if err := os.Remove(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sourcePath := toBackslash(u.Path)
|
||||
|
||||
// Use mklink to create a junction point
|
||||
output, err := exec.Command("cmd", "/c", "mklink", "/J", dst, sourcePath).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run mklink %v %v: %v %q", dst, sourcePath, err, output)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *FileGetter) GetFile(dst string, u *url.URL) error {
|
||||
// The source path must exist and be a directory to be usable.
|
||||
if fi, err := os.Stat(u.Path); err != nil {
|
||||
return fmt.Errorf("source path error: %s", err)
|
||||
} else if fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a file")
|
||||
}
|
||||
|
||||
_, err := os.Lstat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the destination already exists, it must be a symlink
|
||||
if err == nil {
|
||||
// Remove the destination
|
||||
if err := os.Remove(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we're not copying, just symlink and we're done
|
||||
if !g.Copy {
|
||||
return os.Symlink(u.Path, dst)
|
||||
}
|
||||
|
||||
// Copy
|
||||
srcF, err := os.Open(u.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcF.Close()
|
||||
|
||||
dstF, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstF.Close()
|
||||
|
||||
_, err = io.Copy(dstF, srcF)
|
||||
return err
|
||||
}
|
||||
|
||||
// toBackslash returns the result of replacing each slash character
|
||||
// in path with a backslash ('\') character. Multiple separators are
|
||||
// replaced by multiple backslashes.
|
||||
func toBackslash(path string) string {
|
||||
return strings.Replace(path, "/", "\\", -1)
|
||||
}
|
|
@ -71,7 +71,12 @@ func (g *HgGetter) GetFile(dst string, u *url.URL) error {
|
|||
// Get the filename, and strip the filename from the URL so we can
|
||||
// just get the repository directly.
|
||||
filename := filepath.Base(u.Path)
|
||||
u.Path = filepath.Dir(u.Path)
|
||||
u.Path = filepath.ToSlash(filepath.Dir(u.Path))
|
||||
|
||||
// If we're on Windows, we need to set the host to "localhost" for hg
|
||||
if runtime.GOOS == "windows" {
|
||||
u.Host = "localhost"
|
||||
}
|
||||
|
||||
// Get the full repository
|
||||
if err := g.Get(td, u); err != nil {
|
||||
|
|
Loading…
Reference in New Issue