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",
|
"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",
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
|
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)
|
||||||
|
|
|
@ -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.
|
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
|
||||||
})
|
})
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
// 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 {
|
||||||
|
|
Loading…
Reference in New Issue