Merge pull request #5739 from hashicorp/deps-update-go-getter

deps: Update hashicorp/go-getter
This commit is contained in:
James Nugent 2016-03-20 22:06:38 +00:00
commit bceb795c07
12 changed files with 331 additions and 113 deletions

4
Godeps/Godeps.json generated
View File

@ -633,11 +633,11 @@
}, },
{ {
"ImportPath": "github.com/hashicorp/go-getter", "ImportPath": "github.com/hashicorp/go-getter",
"Rev": "848242c76c346ef0aeb34787753b068f5f6f92fe" "Rev": "2822987a64e0df1236ac29dd277ddf79f4871f9a"
}, },
{ {
"ImportPath": "github.com/hashicorp/go-getter/helper/url", "ImportPath": "github.com/hashicorp/go-getter/helper/url",
"Rev": "848242c76c346ef0aeb34787753b068f5f6f92fe" "Rev": "2822987a64e0df1236ac29dd277ddf79f4871f9a"
}, },
{ {
"ImportPath": "github.com/hashicorp/go-multierror", "ImportPath": "github.com/hashicorp/go-multierror",

View File

@ -1,10 +1,12 @@
# go-getter # go-getter
[![Build Status](http://img.shields.io/travis/hashicorp/go-getter.svg?style=flat-square)][travis] [![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] [![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]
[travis]: http://travis-ci.org/hashicorp/go-getter [travis]: http://travis-ci.org/hashicorp/go-getter
[godocs]: http://godoc.org/github.com/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 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. 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 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 ## 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. protocols. go-getter has various "tricks" with this URL to do certain things.
This section documents the URL format. This section documents the URL format.

16
vendor/github.com/hashicorp/go-getter/appveyor.yml generated vendored Normal file
View File

@ -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 ./...

View File

@ -38,11 +38,9 @@ type Client struct {
Dst string Dst string
Pwd string Pwd string
// Dir, if true, tells the Client it is downloading a directory (versus // Mode is the method of download the client will use. See ClientMode
// a single file). This distinction is necessary since filenames and // for documentation.
// directory names follow the same format so disambiguating is impossible Mode ClientMode
// without knowing ahead of time.
Dir bool
// Detectors is the list of detectors that are tried on the source. // Detectors is the list of detectors that are tried on the source.
// If this is nil, then the default Detectors will be used. // 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 // Getters is the map of protocols supported by this client. If this
// is nil, then the default Getters variable will be used. // is nil, then the default Getters variable will be used.
Getters map[string]Getter 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. // Get downloads the configured source to the destination.
func (c *Client) Get() error { func (c *Client) Get() error {
// Store this locally since there are cases we swap this // 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 // Default decompressor value
decompressors := c.Decompressors decompressors := c.Decompressors
@ -166,9 +179,9 @@ func (c *Client) Get() error {
// Swap the download directory to be our temporary path and // Swap the download directory to be our temporary path and
// store the old values. // store the old values.
decompressDst = dst decompressDst = dst
decompressDir = dir decompressDir = mode != ClientModeFile
dst = filepath.Join(td, "archive") dst = filepath.Join(td, "archive")
dir = false mode = ClientModeFile
} }
// Determine if we have a checksum // Determine if we have a checksum
@ -179,13 +192,6 @@ func (c *Client) Get() error {
q.Del("checksum") q.Del("checksum")
u.RawQuery = q.Encode() 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 // Determine the checksum hash type
checksumType := "" checksumType := ""
idx := strings.Index(v, ":") idx := strings.Index(v, ":")
@ -216,9 +222,18 @@ func (c *Client) Get() error {
checksumValue = b 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 // If we're not downloading a directory, then just download the file
// and return. // and return.
if !dir { if mode == ClientModeFile {
err := g.GetFile(dst, u) err := g.GetFile(dst, u)
if err != nil { if err != nil {
return err return err
@ -240,13 +255,17 @@ func (c *Client) Get() error {
// Swap the information back // Swap the information back
dst = decompressDst dst = decompressDst
dir = decompressDir if decompressDir {
mode = ClientModeAny
} else {
mode = ClientModeFile
}
} }
// We check the dir value again because it can be switched back // 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 // if we were unarchiving. If we're still only Get-ing a file, then
// we're done. // we're done.
if !dir { if mode == ClientModeFile {
return nil 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 // In the case we have a decompressor we don't Get because it was Get
// above. // above.
if decompressor == nil { 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 // We're downloading a directory, which might require a bit more work
// if we're specifying a subdir. // if we're specifying a subdir.
err := g.Get(dst, u) err := g.Get(dst, u)

24
vendor/github.com/hashicorp/go-getter/client_mode.go generated vendored Normal file
View File

@ -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
)

View File

@ -92,6 +92,11 @@ func testListDir(t *testing.T, path string) []string {
} }
sub = sub[1:] // Trim the leading path sep. sub = sub[1:] // Trim the leading path sep.
// If it is a dir, add trailing sep
if info.IsDir() {
sub += "/"
}
result = append(result, sub) result = append(result, sub)
return nil return nil
}) })

View File

@ -60,7 +60,7 @@ func (d *TarGzipDecompressor) Decompress(dst, src string, dir bool) error {
} }
if hdr.FileInfo().IsDir() { if hdr.FileInfo().IsDir() {
if dir { if !dir {
return fmt.Errorf("expected a single file: %s", src) return fmt.Errorf("expected a single file: %s", src)
} }

View File

@ -72,6 +72,21 @@ func Get(dst, src string) error {
}).Get() }).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 // GetFile downloads the file specified by src into the path specified by
// dst. // dst.
func GetFile(dst, src string) error { func GetFile(dst, src string) error {

View File

@ -1,98 +1,8 @@
package getter package getter
import (
"fmt"
"io"
"net/url"
"os"
"path/filepath"
)
// FileGetter is a Getter implementation that will download a module from // FileGetter is a Getter implementation that will download a module from
// a file scheme. // a file scheme.
type FileGetter struct { type FileGetter struct {
// Copy, if set to true, will copy data instead of using a symlink // Copy, if set to true, will copy data instead of using a symlink
Copy bool 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
}

93
vendor/github.com/hashicorp/go-getter/get_file_unix.go generated vendored Normal file
View File

@ -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
}

View File

@ -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)
}

View File

@ -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 // Get the filename, and strip the filename from the URL so we can
// just get the repository directly. // just get the repository directly.
filename := filepath.Base(u.Path) 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 // Get the full repository
if err := g.Get(td, u); err != nil { if err := g.Get(td, u); err != nil {