Update go-getter and add samba shared files tests to step_download (#8954)
This commit is contained in:
parent
7ff8ba33cf
commit
aa52e690ee
|
@ -67,8 +67,9 @@
|
|||
* core: Ensure HTTP server information `PackerHTTPIP`, `PackerHTTPPort`, and
|
||||
`PackerHTTPAddr` are available via the `build` template engine for all
|
||||
supported builders [GH-9238]
|
||||
* core: fix regression that broke use of pwd when retrieving the checksum from
|
||||
* core: Fix regression that broke use of pwd when retrieving the checksum from
|
||||
a file [GH-9129].
|
||||
* core: Fix `iso_url` to accept SMB shared files UNC and windows network paths. [GH-8954]
|
||||
* post-processor/vagrant: Add "provider_override" template option to allow
|
||||
artifacts from the Artifice post-processor [GH-9239]
|
||||
* post-processor/vsphere-template: Add VSphere builder's artifact to vsphere-
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"type": "virtualbox-iso",
|
||||
"iso_checksum": "946a6077af6f5f95a51f82fdc44051c7aa19f9cfc5f737954845a6050543d7c2",
|
||||
"iso_checksum_type": "sha256",
|
||||
"iso_checksum": "sha256:946a6077af6f5f95a51f82fdc44051c7aa19f9cfc5f737954845a6050543d7c2",
|
||||
"iso_url": "http://old-releases.ubuntu.com/releases/14.04.1/ubuntu-14.04.1-server-amd64.iso",
|
||||
"disk_size": "40960",
|
||||
"guest_os_type": "Ubuntu_64",
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
@ -59,8 +60,8 @@ var defaultGetterClient = getter.Client{
|
|||
}
|
||||
|
||||
func init() {
|
||||
defaultGetterClient.Getters["gcs"] = &gcs.Getter{}
|
||||
defaultGetterClient.Getters["s3"] = &s3.Getter{}
|
||||
defaultGetterClient.Getters = append(defaultGetterClient.Getters, new(gcs.Getter))
|
||||
defaultGetterClient.Getters = append(defaultGetterClient.Getters, new(s3.Getter))
|
||||
}
|
||||
|
||||
func (s *StepDownload) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
|
@ -108,15 +109,7 @@ func (s *StepDownload) Run(ctx context.Context, state multistep.StateBag) multis
|
|||
}
|
||||
|
||||
func (s *StepDownload) download(ctx context.Context, ui packer.Ui, source string) (string, error) {
|
||||
if runtime.GOOS == "windows" {
|
||||
// Check that the user specified a UNC path, and promote it to an smb:// uri.
|
||||
if strings.HasPrefix(source, "\\\\") && len(source) > 2 && source[2] != '?' {
|
||||
source = filepath.ToSlash(source[2:])
|
||||
source = fmt.Sprintf("smb://%s", source)
|
||||
}
|
||||
}
|
||||
|
||||
u, err := urlhelper.Parse(source)
|
||||
u, err := parseSourceURL(source)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("url parse: %s", err)
|
||||
}
|
||||
|
@ -222,4 +215,17 @@ func (s *StepDownload) download(ctx context.Context, ui packer.Ui, source string
|
|||
}
|
||||
}
|
||||
|
||||
func parseSourceURL(source string) (*url.URL, error) {
|
||||
if runtime.GOOS == "windows" {
|
||||
// Check that the user specified a UNC path, and promote it to an smb:// uri.
|
||||
if strings.HasPrefix(source, "\\\\") && len(source) > 2 && source[2] != '?' {
|
||||
source = filepath.ToSlash(source[2:])
|
||||
source = fmt.Sprintf("smb://%s", source)
|
||||
}
|
||||
}
|
||||
|
||||
u, err := urlhelper.Parse(source)
|
||||
return u, err
|
||||
}
|
||||
|
||||
func (s *StepDownload) Cleanup(multistep.StateBag) {}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
@ -259,8 +260,6 @@ func TestStepDownload_download(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Bad: non expected error %s", err.Error())
|
||||
}
|
||||
// because of the inplace option; the result file will not be renamed
|
||||
// sha.ova.
|
||||
os.RemoveAll(step.TargetPath)
|
||||
|
||||
// Abs path with no extension provided
|
||||
|
@ -270,8 +269,6 @@ func TestStepDownload_download(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Bad: non expected error %s", err.Error())
|
||||
}
|
||||
// because of the inplace option; the result file will not be renamed
|
||||
// sha.ova.
|
||||
os.RemoveAll(step.TargetPath)
|
||||
|
||||
// Path with file
|
||||
|
@ -280,11 +277,38 @@ func TestStepDownload_download(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Bad: non expected error %s", err.Error())
|
||||
}
|
||||
// because of the inplace option; the result file will not be renamed
|
||||
// sha.ova.
|
||||
os.RemoveAll(step.TargetPath)
|
||||
}
|
||||
|
||||
func TestStepDownload_WindowsParseSourceURL(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("skip windows specific tests")
|
||||
}
|
||||
|
||||
source := "\\\\hostname\\dir\\filename.txt"
|
||||
url, err := parseSourceURL(source)
|
||||
if err != nil {
|
||||
t.Fatalf("bad: parsing source url failed: %s", err.Error())
|
||||
}
|
||||
if url.Scheme != "smb" {
|
||||
t.Fatalf("bad: url should contain smb scheme but contains: %s", url.Scheme)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepDownload_ParseSourceSmbURL(t *testing.T) {
|
||||
source := "smb://hostname/dir/filename.txt"
|
||||
url, err := parseSourceURL(source)
|
||||
if err != nil {
|
||||
t.Fatalf("bad: parsing source url failed: %s", err.Error())
|
||||
}
|
||||
if url.Scheme != "smb" {
|
||||
t.Fatalf("bad: url should contain smb scheme but contains: %s", url.Scheme)
|
||||
}
|
||||
if url.String() != "smb://hostname/dir/filename.txt" {
|
||||
t.Fatalf("bad: url should contain smb scheme but contains: %s", url.String())
|
||||
}
|
||||
}
|
||||
|
||||
func createTempDir(t *testing.T) string {
|
||||
dir, err := tmp.Dir("pkr")
|
||||
if err != nil {
|
||||
|
|
6
go.mod
6
go.mod
|
@ -64,9 +64,9 @@ require (
|
|||
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||
github.com/hashicorp/go-cty-funcs v0.0.0-20200520133146-0d04eb807361
|
||||
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200514151440-7b188cad6b7d
|
||||
github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200514151440-7b188cad6b7d
|
||||
github.com/hashicorp/go-getter/v2 v2.0.0-20200518081638-5b5e57151574
|
||||
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad
|
||||
github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200604122502-a6995fa1edad
|
||||
github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad
|
||||
github.com/hashicorp/go-immutable-radix v1.1.0 // indirect
|
||||
github.com/hashicorp/go-msgpack v0.5.5 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.0
|
||||
|
|
12
go.sum
12
go.sum
|
@ -298,13 +298,13 @@ github.com/hashicorp/go-cty-funcs v0.0.0-20200520133146-0d04eb807361 h1:qFuR7ZaM
|
|||
github.com/hashicorp/go-cty-funcs v0.0.0-20200520133146-0d04eb807361/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA=
|
||||
github.com/hashicorp/go-getter v1.4.1 h1:3A2Mh8smGFcf5M+gmcv898mZdrxpseik45IpcyISLsA=
|
||||
github.com/hashicorp/go-getter v1.4.1/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
|
||||
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200514151440-7b188cad6b7d h1:zLZhNNEeKm8varoECAnpbvVpZOBlQYTl5Ozni1rt6xo=
|
||||
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200514151440-7b188cad6b7d/go.mod h1:e752jX43t0ynGvZNR7UVizfZX9icakpmUetiv7LH7xY=
|
||||
github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200514151440-7b188cad6b7d h1:yOCiz5jYW08tR38XiFMCI1vcnW9Wc+BD4oMQC7ujsSA=
|
||||
github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200514151440-7b188cad6b7d/go.mod h1:kcB6Mv+0wzYXbQjTAeD/Pb85145WcFk2EElpe02fuoE=
|
||||
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad h1:QPLyAkuTS5Uf9uqJQxCTDDFgmD+gVAzSvqkGb3h+7oQ=
|
||||
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad/go.mod h1:e752jX43t0ynGvZNR7UVizfZX9icakpmUetiv7LH7xY=
|
||||
github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200604122502-a6995fa1edad h1:hwk5mQRwVvZc/f+So1kHbOhW/f7P2fEcCr2D5pSk9sI=
|
||||
github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200604122502-a6995fa1edad/go.mod h1:kcB6Mv+0wzYXbQjTAeD/Pb85145WcFk2EElpe02fuoE=
|
||||
github.com/hashicorp/go-getter/v2 v2.0.0-20200511090339-3107ec4af37a/go.mod h1:QJ+LwRM91JBKBLyHoKBrcmi49i9Tu/ItpgTNXWSnpGM=
|
||||
github.com/hashicorp/go-getter/v2 v2.0.0-20200518081638-5b5e57151574 h1:Js4KcJYjGgPD3XZznxBhGOCxwS4X90VVnJorqOa55f8=
|
||||
github.com/hashicorp/go-getter/v2 v2.0.0-20200518081638-5b5e57151574/go.mod h1:QJ+LwRM91JBKBLyHoKBrcmi49i9Tu/ItpgTNXWSnpGM=
|
||||
github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad h1:BfRfKjQgvwJrXF2apbeqoqeuxzDcxZIeI/eCj6HLkM4=
|
||||
github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad/go.mod h1:bM2M11foprILIk1Slmr2wBrJYsdQTym//+QMJqgm3F8=
|
||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM=
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package getter
|
||||
package gcs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -6,11 +6,11 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// GCSDetector implements Detector to detect GCS URLs and turn
|
||||
// Detector implements Detector to detect GCS URLs and turn
|
||||
// them into URLs that the GCSGetter can understand.
|
||||
type GCSDetector struct{}
|
||||
type Detector struct{}
|
||||
|
||||
func (d *GCSDetector) Detect(src, _ string) (string, bool, error) {
|
||||
func (d *Detector) Detect(src, _ string) (string, bool, error) {
|
||||
if len(src) == 0 {
|
||||
return "", false, nil
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ func (d *GCSDetector) Detect(src, _ string) (string, bool, error) {
|
|||
return "", false, nil
|
||||
}
|
||||
|
||||
func (d *GCSDetector) detectHTTP(src string) (string, bool, error) {
|
||||
func (d *Detector) detectHTTP(src string) (string, bool, error) {
|
||||
|
||||
parts := strings.Split(src, "/")
|
||||
if len(parts) < 5 {
|
||||
|
@ -39,5 +39,5 @@ func (d *GCSDetector) detectHTTP(src string) (string, bool, error) {
|
|||
return "", false, fmt.Errorf("error parsing GCS URL: %s", err)
|
||||
}
|
||||
|
||||
return "gcs::" + url.String(), true, nil
|
||||
return url.String(), true, nil
|
||||
}
|
|
@ -15,8 +15,7 @@ import (
|
|||
|
||||
// Getter is a Getter implementation that will download a module from
|
||||
// a GCS bucket.
|
||||
type Getter struct {
|
||||
}
|
||||
type Getter struct {}
|
||||
|
||||
func (g *Getter) Mode(ctx context.Context, u *url.URL) (getter.Mode, error) {
|
||||
|
||||
|
@ -165,3 +164,48 @@ func (g *Getter) parseURL(u *url.URL) (bucket, path string, err error) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (g *Getter) Detect(req *getter.Request) (bool, error) {
|
||||
src := req.Src
|
||||
if len(src) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if req.Forced != "" {
|
||||
// There's a getter being forced
|
||||
if !g.validScheme(req.Forced) {
|
||||
// Current getter is not the forced one
|
||||
// Don't use it to try to download the artifact
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
isForcedGetter := req.Forced != "" && g.validScheme(req.Forced)
|
||||
|
||||
u, err := url.Parse(src)
|
||||
if err == nil && u.Scheme != "" {
|
||||
if isForcedGetter {
|
||||
// Is the forced getter and source is a valid url
|
||||
return true, nil
|
||||
}
|
||||
if g.validScheme(u.Scheme) {
|
||||
return true, nil
|
||||
}
|
||||
// Valid url with a scheme that is not valid for current getter
|
||||
return false, nil
|
||||
}
|
||||
|
||||
src, ok, err := new(Detector).Detect(src, req.Pwd)
|
||||
if err != nil {
|
||||
return ok, err
|
||||
}
|
||||
if ok {
|
||||
req.Src = src
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (g *Getter) validScheme(scheme string) bool {
|
||||
return scheme == "gcs"
|
||||
}
|
||||
|
|
|
@ -28,16 +28,20 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
|||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
|
@ -73,8 +77,14 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
|
|||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-getter v1.4.1 h1:3A2Mh8smGFcf5M+gmcv898mZdrxpseik45IpcyISLsA=
|
||||
github.com/hashicorp/go-getter v1.4.1/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
|
||||
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
||||
|
@ -82,6 +92,7 @@ github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
|
|||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
|
@ -89,6 +100,9 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
|
@ -97,6 +111,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
|
||||
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
|
@ -274,6 +289,7 @@ google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
|||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package getter
|
||||
package s3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -6,11 +6,11 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// S3Detector implements Detector to detect S3 URLs and turn
|
||||
// Detector implements Detector to detect S3 URLs and turn
|
||||
// them into URLs that the S3 getter can understand.
|
||||
type S3Detector struct{}
|
||||
type Detector struct{}
|
||||
|
||||
func (d *S3Detector) Detect(src, _ string) (string, bool, error) {
|
||||
func (d *Detector) Detect(src, _ string) (string, bool, error) {
|
||||
if len(src) == 0 {
|
||||
return "", false, nil
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ func (d *S3Detector) Detect(src, _ string) (string, bool, error) {
|
|||
return "", false, nil
|
||||
}
|
||||
|
||||
func (d *S3Detector) detectHTTP(src string) (string, bool, error) {
|
||||
func (d *Detector) detectHTTP(src string) (string, bool, error) {
|
||||
parts := strings.Split(src, "/")
|
||||
if len(parts) < 2 {
|
||||
return "", false, fmt.Errorf(
|
||||
|
@ -40,22 +40,22 @@ func (d *S3Detector) detectHTTP(src string) (string, bool, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *S3Detector) detectPathStyle(region string, parts []string) (string, bool, error) {
|
||||
func (d *Detector) detectPathStyle(region string, parts []string) (string, bool, error) {
|
||||
urlStr := fmt.Sprintf("https://%s.amazonaws.com/%s", region, strings.Join(parts, "/"))
|
||||
url, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return "", false, fmt.Errorf("error parsing S3 URL: %s", err)
|
||||
}
|
||||
|
||||
return "s3::" + url.String(), true, nil
|
||||
return url.String(), true, nil
|
||||
}
|
||||
|
||||
func (d *S3Detector) detectVhostStyle(region, bucket string, parts []string) (string, bool, error) {
|
||||
func (d *Detector) detectVhostStyle(region, bucket string, parts []string) (string, bool, error) {
|
||||
urlStr := fmt.Sprintf("https://%s.amazonaws.com/%s/%s", region, bucket, strings.Join(parts, "/"))
|
||||
url, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return "", false, fmt.Errorf("error parsing S3 URL: %s", err)
|
||||
}
|
||||
|
||||
return "s3::" + url.String(), true, nil
|
||||
return url.String(), true, nil
|
||||
}
|
|
@ -20,8 +20,7 @@ import (
|
|||
|
||||
// Getter is a Getter implementation that will download a module from
|
||||
// a S3 bucket.
|
||||
type Getter struct {
|
||||
}
|
||||
type Getter struct{}
|
||||
|
||||
func (g *Getter) Mode(ctx context.Context, u *url.URL) (getter.Mode, error) {
|
||||
// Parse URL
|
||||
|
@ -272,3 +271,47 @@ func (g *Getter) parseUrl(u *url.URL) (region, bucket, path, version string, cre
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
func (g *Getter) Detect(req *getter.Request) (bool, error) {
|
||||
src := req.Src
|
||||
if len(src) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if req.Forced != "" {
|
||||
// There's a getter being forced
|
||||
if !g.validScheme(req.Forced) {
|
||||
// Current getter is not the forced one
|
||||
// Don't use it to try to download the artifact
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
isForcedGetter := req.Forced != "" && g.validScheme(req.Forced)
|
||||
|
||||
u, err := url.Parse(src)
|
||||
if err == nil && u.Scheme != "" {
|
||||
if isForcedGetter {
|
||||
// Is the forced getter and source is a valid url
|
||||
return true, nil
|
||||
}
|
||||
if g.validScheme(u.Scheme) {
|
||||
return true, nil
|
||||
}
|
||||
// Valid url with a scheme that is not valid for current getter
|
||||
return false, nil
|
||||
}
|
||||
|
||||
src, ok, err := new(Detector).Detect(src, req.Pwd)
|
||||
if err != nil {
|
||||
return ok, err
|
||||
}
|
||||
if ok {
|
||||
req.Src = src
|
||||
}
|
||||
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (g *Getter) validScheme(scheme string) bool {
|
||||
return scheme == "s3"
|
||||
}
|
||||
|
|
|
@ -1,20 +1,63 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
|
||||
github.com/aws/aws-sdk-go v1.30.8 h1:4BHbh8K3qKmcnAgToZ2LShldRF9inoqIBccpCLNCy3I=
|
||||
github.com/aws/aws-sdk-go v1.30.8/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-getter v1.4.1 h1:3A2Mh8smGFcf5M+gmcv898mZdrxpseik45IpcyISLsA=
|
||||
github.com/hashicorp/go-getter v1.4.1/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
|
||||
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
||||
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
|
||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
|
@ -23,17 +66,92 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
|
||||
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# Dockerfile to create a go-getter container with smbclient dependency that is used by the get_smb.go tests
|
||||
FROM golang:latest
|
||||
|
||||
COPY . /go-getter
|
||||
WORKDIR /go-getter
|
||||
|
||||
RUN go mod download
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install smbclient
|
|
@ -0,0 +1,9 @@
|
|||
# Dockerfile to create a smb server that is used by the get_smb.go tests
|
||||
FROM dperson/samba
|
||||
|
||||
# Create shared folders
|
||||
RUN mkdir -p /public && mkdir -p /private
|
||||
|
||||
# Create shared files and directories under the shared folders (data and mnt)
|
||||
RUN echo 'Hello' > /public/file.txt && mkdir -p /public/subdir && echo 'Hello' > /public/subdir/file.txt
|
||||
RUN echo 'Hello' > /private/file.txt && mkdir -p /private/subdir && echo 'Hello' > /private/subdir/file.txt
|
|
@ -0,0 +1,12 @@
|
|||
start-smb:
|
||||
@docker-compose build
|
||||
docker-compose up -d samba
|
||||
|
||||
smbtests-prepare:
|
||||
@docker-compose build
|
||||
@docker-compose up -d
|
||||
@sleep 60
|
||||
|
||||
smbtests:
|
||||
@docker cp ./ gogetter:/go-getter/
|
||||
@docker exec -it gogetter bash -c "env ACC_SMB_TEST=1 go test -v ./... -run=TestSmb_"
|
|
@ -72,6 +72,7 @@ can be augmented at runtime by implementing the `Getter` interface.
|
|||
* HTTP
|
||||
* Amazon S3
|
||||
* Google GCP
|
||||
* SMB
|
||||
|
||||
In addition to the above protocols, go-getter has what are called "detectors."
|
||||
These take a URL and attempt to automatically choose the best protocol for
|
||||
|
@ -360,3 +361,45 @@ In order to access to GCS, authentication credentials should be provided. More i
|
|||
#### GCS Testing
|
||||
|
||||
The tests for `get_gcs.go` require you to have GCP credentials set in your environment. These credentials can have any level of permissions to any project, they just need to exist. This means setting `GOOGLE_APPLICATION_CREDENTIALS="~/path/to/credentials.json"` or `GOOGLE_CREDENTIALS="{stringified-credentials-json}"`. Due to this configuration, `get_gcs_test.go` will fail for external contributors in CircleCI.
|
||||
|
||||
### SMB (smb)
|
||||
|
||||
There are two options that go-getter will use to download a file in a smb shared folder. The first option uses
|
||||
[`smbclient`](https://www.samba.org/samba/docs/current/man-html/smbclient.1.html) and the second one uses the file system
|
||||
to look for a file in a local mount of the shared folder in the OS specific volume folder. go-getter will try to download
|
||||
files from a smb shared folder whenever the url is prefixed with `smb://`.
|
||||
|
||||
⚠️ The [`smbclient`](https://www.samba.org/samba/docs/current/man-html/smbclient.1.html) command is available only for Linux.
|
||||
This is the ONLY option for a Linux user and therefore the client must be installed.
|
||||
|
||||
The `smbclient` cli is not available for Windows and MacOS. The go-getter
|
||||
will try to get files using the file system, when this happens the getter uses the FileGetter implementation.
|
||||
|
||||
When connecting to a smb server, the OS creates a local mount in a system specific volume folder, and go-getter will
|
||||
try to access the following folders when looking for local mounts.
|
||||
|
||||
- MacOS: /Volumes/<shared_path>
|
||||
- Windows: \\\\\<host>\\\<shared_path>
|
||||
|
||||
The following examples work for all the OSes:
|
||||
- smb://host/shared/dir (downloads directory content)
|
||||
- smb://host/shared/dir/file (downloads file)
|
||||
|
||||
The following examples work for Linux:
|
||||
- smb://username:password@host/shared/dir (downloads directory content)
|
||||
- smb://username@host/shared/dir
|
||||
- smb://username:password@host/shared/dir/file (downloads file)
|
||||
- smb://username@host/shared/dir/file
|
||||
|
||||
⚠️ The above examples also work on the other OSes but the authentication is not used to access the file system.
|
||||
|
||||
|
||||
|
||||
#### SMB Testing
|
||||
The test for `get_smb.go` requires a smb server running which can be started inside a docker container by
|
||||
running `make start-smb`. Once the container is up the shared folder can be accessed via `smb://<ip|name>/public/<dir|file>` or
|
||||
`smb://user:password@<ip|name>/private/<dir|file>` by another container or machine in the same network.
|
||||
|
||||
To run the tests inside `get_smb_test.go` and `client_test.go`, prepare the environment with `make smbtests-prepare`. On prepare some
|
||||
mock files and directories will be added to the shared folder and a go-getter container will start together with the samba server.
|
||||
Once the environment for testing is prepared, run `make smbtests` to run the tests.
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
urlhelper "github.com/hashicorp/go-getter/v2/helper/url"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
safetemp "github.com/hashicorp/go-safetemp"
|
||||
)
|
||||
|
||||
|
@ -19,18 +20,13 @@ import (
|
|||
// Using a client directly allows more fine-grained control over how downloading
|
||||
// is done, as well as customizing the protocols supported.
|
||||
type Client struct {
|
||||
|
||||
// Detectors is the list of detectors that are tried on the source.
|
||||
// If this is nil, then the default Detectors will be used.
|
||||
Detectors []Detector
|
||||
|
||||
// Decompressors is the map of decompressors supported by this client.
|
||||
// If this is nil, then the default value is the Decompressors global.
|
||||
Decompressors map[string]Decompressor
|
||||
|
||||
// Getters is the map of protocols supported by this client. If this
|
||||
// Getters is the list of protocols supported by this client. If this
|
||||
// is nil, then the default Getters variable will be used.
|
||||
Getters map[string]Getter
|
||||
Getters []Getter
|
||||
}
|
||||
|
||||
// GetResult is the result of a Client.Get
|
||||
|
@ -50,43 +46,75 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) {
|
|||
req.Mode = ModeAny
|
||||
}
|
||||
|
||||
var err error
|
||||
req.Src, err = Detect(req.Src, req.Pwd, c.Detectors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var force string
|
||||
// Determine if we have a forced protocol, i.e. "git::http://..."
|
||||
force, req.Src = getForcedGetter(req.Src)
|
||||
|
||||
// If there is a subdir component, then we download the root separately
|
||||
// and then copy over the proper subdir.
|
||||
var realDst, subDir string
|
||||
req.Src, subDir = SourceDirSubdir(req.Src)
|
||||
if subDir != "" {
|
||||
req.Src, req.subDir = SourceDirSubdir(req.Src)
|
||||
if req.subDir != "" {
|
||||
td, tdcloser, err := safetemp.Dir("", "getter")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tdcloser.Close()
|
||||
|
||||
realDst = req.Dst
|
||||
req.realDst = req.Dst
|
||||
req.Dst = td
|
||||
}
|
||||
|
||||
req.u, err = urlhelper.Parse(req.Src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if force == "" {
|
||||
force = req.u.Scheme
|
||||
var multierr []error
|
||||
for _, g := range c.Getters {
|
||||
shouldDownload, err := Detect(req, g)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !shouldDownload {
|
||||
// the request should not be processed by that getter
|
||||
continue
|
||||
}
|
||||
|
||||
result, getErr := c.get(ctx, req, g)
|
||||
if getErr != nil {
|
||||
if getErr.Fatal {
|
||||
return nil, getErr.Err
|
||||
}
|
||||
multierr = append(multierr, getErr.Err)
|
||||
continue
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
g, ok := c.Getters[force]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(
|
||||
"download not supported for scheme '%s'", force)
|
||||
if len(multierr) == 1 {
|
||||
// This is for keeping the error original format
|
||||
return nil, multierr[0]
|
||||
}
|
||||
|
||||
if multierr != nil {
|
||||
var result *multierror.Error
|
||||
result = multierror.Append(result, multierr...)
|
||||
return nil, fmt.Errorf("error downloading '%s': %s", req.Src, result.Error())
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("error downloading '%s'", req.Src)
|
||||
}
|
||||
|
||||
// getError is the Error response object returned by get(context.Context, *Request, Getter)
|
||||
// to tell the client whether to halt (Fatal) Get or to keep trying to get an artifact.
|
||||
type getError struct {
|
||||
// When Fatal is true something went wrong with get(context.Context, *Request, Getter)
|
||||
// and the client should halt and return the Err.
|
||||
Fatal bool
|
||||
Err error
|
||||
}
|
||||
|
||||
func (ge *getError) Error() string {
|
||||
return ge.Err.Error()
|
||||
}
|
||||
|
||||
func (c *Client) get(ctx context.Context, req *Request, g Getter) (*GetResult, *getError) {
|
||||
u, err := urlhelper.Parse(req.Src)
|
||||
req.u = u
|
||||
if err != nil {
|
||||
return nil, &getError{true, err}
|
||||
}
|
||||
|
||||
// We have magic query parameters that we use to signal different features
|
||||
|
@ -105,8 +133,7 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) {
|
|||
if b, err := strconv.ParseBool(archiveV); err == nil && !b {
|
||||
archiveV = "-"
|
||||
}
|
||||
}
|
||||
if archiveV == "" {
|
||||
} else {
|
||||
// We don't appear to... but is it part of the filename?
|
||||
matchingLen := 0
|
||||
for k := range c.Decompressors {
|
||||
|
@ -128,8 +155,8 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) {
|
|||
// this at the end of everything.
|
||||
td, err := ioutil.TempDir("", "getter")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error creating temporary directory for archive: %s", err)
|
||||
return nil, &getError{true, fmt.Errorf(
|
||||
"Error creating temporary directory for archive: %s", err)}
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
|
@ -144,7 +171,7 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) {
|
|||
// Determine checksum if we have one
|
||||
checksum, err := c.GetChecksum(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid checksum: %s", err)
|
||||
return nil, &getError{true, fmt.Errorf("invalid checksum: %s", err)}
|
||||
}
|
||||
|
||||
// Delete the query parameter if we have it.
|
||||
|
@ -155,7 +182,7 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) {
|
|||
// Ask the getter which client mode to use
|
||||
req.Mode, err = g.Mode(ctx, req.u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, &getError{false, err}
|
||||
}
|
||||
|
||||
// Destination is the base name of the URL path in "any" mode when
|
||||
|
@ -187,14 +214,13 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) {
|
|||
}
|
||||
}
|
||||
if getFile {
|
||||
err := g.GetFile(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err := g.GetFile(ctx, req); err != nil {
|
||||
return nil, &getError{false, err}
|
||||
}
|
||||
|
||||
if checksum != nil {
|
||||
if err := checksum.Checksum(req.Dst); err != nil {
|
||||
return nil, err
|
||||
return nil, &getError{true, err}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +230,7 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) {
|
|||
// into the final destination with the proper mode.
|
||||
err := decompressor.Decompress(decompressDst, req.Dst, decompressDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, &getError{true, err}
|
||||
}
|
||||
|
||||
// Swap the information back
|
||||
|
@ -232,36 +258,67 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) {
|
|||
// If we're getting a directory, then this is an error. You cannot
|
||||
// checksum a directory. TODO: test
|
||||
if checksum != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"checksum cannot be specified for directory download")
|
||||
return nil, &getError{true, 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(ctx, req)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error downloading '%s': %s", req.Src, err)
|
||||
return nil, err
|
||||
if err := g.Get(ctx, req); err != nil {
|
||||
return nil, &getError{false, err}
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a subdir, copy that over
|
||||
if subDir != "" {
|
||||
if err := os.RemoveAll(realDst); err != nil {
|
||||
return nil, err
|
||||
if req.subDir != "" {
|
||||
if err := os.RemoveAll(req.realDst); err != nil {
|
||||
return nil, &getError{true, err}
|
||||
}
|
||||
if err := os.MkdirAll(realDst, 0755); err != nil {
|
||||
return nil, err
|
||||
if err := os.MkdirAll(req.realDst, 0755); err != nil {
|
||||
return nil, &getError{true, err}
|
||||
}
|
||||
|
||||
// Process any globs
|
||||
subDir, err := SubdirGlob(req.Dst, subDir)
|
||||
subDir, err := SubdirGlob(req.Dst, req.subDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, &getError{true, err}
|
||||
}
|
||||
|
||||
return &GetResult{realDst}, copyDir(ctx, realDst, subDir, false)
|
||||
err = copyDir(ctx, req.realDst, subDir, false)
|
||||
if err != nil {
|
||||
return nil, &getError{false, err}
|
||||
}
|
||||
return &GetResult{req.realDst}, nil
|
||||
}
|
||||
|
||||
return &GetResult{req.Dst}, nil
|
||||
|
||||
}
|
||||
|
||||
func (c *Client) checkArchive(req *Request) string {
|
||||
q := req.u.Query()
|
||||
archiveV := q.Get("archive")
|
||||
if archiveV != "" {
|
||||
// Delete the paramter since it is a magic parameter we don't
|
||||
// want to pass on to the Getter
|
||||
q.Del("archive")
|
||||
req.u.RawQuery = q.Encode()
|
||||
|
||||
// If we can parse the value as a bool and it is false, then
|
||||
// set the archive to "-" which should never map to a decompressor
|
||||
if b, err := strconv.ParseBool(archiveV); err == nil && !b {
|
||||
archiveV = "-"
|
||||
}
|
||||
}
|
||||
if archiveV == "" {
|
||||
// We don't appear to... but is it part of the filename?
|
||||
matchingLen := 0
|
||||
for k := range c.Decompressors {
|
||||
if strings.HasSuffix(req.u.Path, "."+k) && len(k) > matchingLen {
|
||||
archiveV = k
|
||||
matchingLen = len(k)
|
||||
}
|
||||
}
|
||||
}
|
||||
return archiveV
|
||||
}
|
||||
|
|
|
@ -6,14 +6,9 @@ func (c *Client) configure() error {
|
|||
if c.Decompressors == nil {
|
||||
c.Decompressors = Decompressors
|
||||
}
|
||||
// Default detector values
|
||||
if c.Detectors == nil {
|
||||
c.Detectors = Detectors
|
||||
}
|
||||
// Default getter values
|
||||
if c.Getters == nil {
|
||||
c.Getters = Getters
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package getter
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/go-getter/v2/helper/url"
|
||||
)
|
||||
|
@ -16,90 +15,45 @@ type Detector interface {
|
|||
Detect(string, string) (string, bool, error)
|
||||
}
|
||||
|
||||
// Detectors is the list of detectors that are tried on an invalid URL.
|
||||
// This is also the order they're tried (index 0 is first).
|
||||
var Detectors []Detector
|
||||
// Detect is a method used to detect if a Getter is a candidate for downloading an artifact
|
||||
// by calling the Getter.Detect(*Request) method
|
||||
func Detect(req *Request, getter Getter) (bool, error) {
|
||||
originalSrc := req.Src
|
||||
|
||||
func init() {
|
||||
Detectors = []Detector{
|
||||
new(GitHubDetector),
|
||||
new(GitDetector),
|
||||
new(BitBucketDetector),
|
||||
new(S3Detector),
|
||||
new(GCSDetector),
|
||||
new(FileDetector),
|
||||
}
|
||||
}
|
||||
|
||||
// Detect turns a source string into another source string if it is
|
||||
// detected to be of a known pattern.
|
||||
//
|
||||
// The third parameter should be the list of detectors to use in the
|
||||
// order to try them. If you don't want to configure this, just use
|
||||
// the global Detectors variable.
|
||||
//
|
||||
// This is safe to be called with an already valid source string: Detect
|
||||
// will just return it.
|
||||
func Detect(src string, pwd string, ds []Detector) (string, error) {
|
||||
getForce, getSrc := getForcedGetter(src)
|
||||
|
||||
// Separate out the subdir if there is one, we don't pass that to detect
|
||||
getSrc, subDir := SourceDirSubdir(getSrc)
|
||||
|
||||
u, err := url.Parse(getSrc)
|
||||
if err == nil && u.Scheme != "" {
|
||||
// Valid URL
|
||||
return src, nil
|
||||
getForce, getSrc := getForcedGetter(req.Src)
|
||||
if getForce != "" {
|
||||
req.Forced = getForce
|
||||
}
|
||||
|
||||
for _, d := range ds {
|
||||
result, ok, err := d.Detect(getSrc, pwd)
|
||||
req.Src = getSrc
|
||||
ok, err := getter.Detect(req)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
if !ok {
|
||||
// Write back the original source
|
||||
req.Src = originalSrc
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
result, detectSubdir := SourceDirSubdir(req.Src)
|
||||
|
||||
// If we have a subdir from the detection, then prepend it to our
|
||||
// requested subdir.
|
||||
if detectSubdir != "" {
|
||||
u, err := url.Parse(result)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
return true, fmt.Errorf("Error parsing URL: %s", err)
|
||||
}
|
||||
u.Path += "//" + detectSubdir
|
||||
|
||||
var detectForce string
|
||||
detectForce, result = getForcedGetter(result)
|
||||
result, detectSubdir := SourceDirSubdir(result)
|
||||
// a subdir may contain wildcards, but in order to support them we
|
||||
// have to ensure the path isn't escaped.
|
||||
u.RawPath = u.Path
|
||||
|
||||
// If we have a subdir from the detection, then prepend it to our
|
||||
// requested subdir.
|
||||
if detectSubdir != "" {
|
||||
if subDir != "" {
|
||||
subDir = filepath.Join(detectSubdir, subDir)
|
||||
} else {
|
||||
subDir = detectSubdir
|
||||
}
|
||||
}
|
||||
|
||||
if subDir != "" {
|
||||
u, err := url.Parse(result)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error parsing URL: %s", err)
|
||||
}
|
||||
u.Path += "//" + subDir
|
||||
|
||||
// a subdir may contain wildcards, but in order to support them we
|
||||
// have to ensure the path isn't escaped.
|
||||
u.RawPath = u.Path
|
||||
|
||||
result = u.String()
|
||||
}
|
||||
|
||||
// Preserve the forced getter if it exists. We try to use the
|
||||
// original set force first, followed by any force set by the
|
||||
// detector.
|
||||
if getForce != "" {
|
||||
result = fmt.Sprintf("%s::%s", getForce, result)
|
||||
} else if detectForce != "" {
|
||||
result = fmt.Sprintf("%s::%s", detectForce, result)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
result = u.String()
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("invalid source string: %s", src)
|
||||
req.Src = result
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
@ -56,12 +56,6 @@ func fmtFileURL(path string) string {
|
|||
if runtime.GOOS == "windows" {
|
||||
// Make sure we're using "/" on Windows. URLs are "/"-based.
|
||||
path = filepath.ToSlash(path)
|
||||
return fmt.Sprintf("file://%s", path)
|
||||
}
|
||||
|
||||
// Make sure that we don't start with "/" since we add that below.
|
||||
if path[0] == '/' {
|
||||
path = path[1:]
|
||||
}
|
||||
return fmt.Sprintf("file:///%s", path)
|
||||
return path
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
version: '3.2'
|
||||
|
||||
services:
|
||||
samba:
|
||||
build:
|
||||
dockerfile: Dockerfile-smbserver
|
||||
context: .
|
||||
container_name: samba
|
||||
environment:
|
||||
USERID: "0"
|
||||
GROUPID: "0"
|
||||
networks:
|
||||
- default
|
||||
ports:
|
||||
- "139:139/tcp" # default smb port
|
||||
- "445:445/tcp" # default smb port
|
||||
volumes:
|
||||
- /mnt:/mnt:z
|
||||
command: '-s "public;/public" -s "private;/private;yes;no;no;user" -u "user;password" -p'
|
||||
|
||||
gogetter:
|
||||
build:
|
||||
context: .
|
||||
container_name: gogetter
|
||||
depends_on:
|
||||
- samba
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- /mnt:/mnt
|
||||
command: tail -f /dev/null
|
||||
|
||||
networks:
|
||||
default:
|
|
@ -42,13 +42,21 @@ type Getter interface {
|
|||
// Mode returns the mode based on the given URL. This is used to
|
||||
// allow clients to let the getters decide which mode to use.
|
||||
Mode(context.Context, *url.URL) (Mode, error)
|
||||
|
||||
// Detect detects whether the Request.Src matches a known pattern to
|
||||
// turn it into a proper URL, and also transforms and update Request.Src
|
||||
// when necessary.
|
||||
// The Getter must validate if the Request.Src is a valid URL
|
||||
// with a valid scheme for the Getter, and also check if the
|
||||
// current Getter is the forced one and return true if that's the case.
|
||||
Detect(*Request) (bool, error)
|
||||
}
|
||||
|
||||
// Getters is the mapping of scheme to the Getter implementation that will
|
||||
// be used to get a dependency.
|
||||
var Getters map[string]Getter
|
||||
var Getters []Getter
|
||||
|
||||
// forcedRegexp is the regular expression that finds forced getters. This
|
||||
// forcedRegexp is the regular expression that finds Forced getters. This
|
||||
// syntax is schema::url, example: git::https://foo.com
|
||||
var forcedRegexp = regexp.MustCompile(`^([A-Za-z0-9]+)::(.+)$`)
|
||||
|
||||
|
@ -57,7 +65,6 @@ var httpClient = cleanhttp.DefaultClient()
|
|||
|
||||
var DefaultClient = &Client{
|
||||
Getters: Getters,
|
||||
Detectors: Detectors,
|
||||
Decompressors: Decompressors,
|
||||
}
|
||||
|
||||
|
@ -66,12 +73,20 @@ func init() {
|
|||
Netrc: true,
|
||||
}
|
||||
|
||||
Getters = map[string]Getter{
|
||||
"file": new(FileGetter),
|
||||
"git": new(GitGetter),
|
||||
"hg": new(HgGetter),
|
||||
"http": httpGetter,
|
||||
"https": httpGetter,
|
||||
// The order of the Getters in the list may affect the result
|
||||
// depending if the Request.Src is detected as valid by multiple getters
|
||||
Getters = []Getter{
|
||||
&GitGetter{[]Detector{
|
||||
new(GitHubDetector),
|
||||
new(GitDetector),
|
||||
new(BitBucketDetector),
|
||||
},
|
||||
},
|
||||
new(HgGetter),
|
||||
new(SmbClientGetter),
|
||||
new(SmbMountGetter),
|
||||
httpGetter,
|
||||
new(FileGetter),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// FileGetter is a Getter implementation that will download a module from
|
||||
// a file scheme.
|
||||
type FileGetter struct {
|
||||
}
|
||||
type FileGetter struct{}
|
||||
|
||||
func (g *FileGetter) Mode(ctx context.Context, u *url.URL) (Mode, error) {
|
||||
path := u.Path
|
||||
|
@ -148,3 +148,54 @@ func (g *FileGetter) GetFile(ctx context.Context, req *Request) error {
|
|||
_, err = Copy(ctx, dstF, srcF)
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *FileGetter) Detect(req *Request) (bool, error) {
|
||||
var src, pwd string
|
||||
src = req.Src
|
||||
pwd = req.Pwd
|
||||
if len(src) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if req.Forced != "" {
|
||||
// There's a getter being Forced
|
||||
if !g.validScheme(req.Forced) {
|
||||
// Current getter is not the Forced one
|
||||
// Don't use it to try to download the artifact
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
isForcedGetter := req.Forced != "" && g.validScheme(req.Forced)
|
||||
|
||||
u, err := url.Parse(src)
|
||||
if err == nil && u.Scheme != "" {
|
||||
if isForcedGetter {
|
||||
// Is the Forced getter and source is a valid url
|
||||
return true, nil
|
||||
}
|
||||
if g.validScheme(u.Scheme) {
|
||||
return true, nil
|
||||
}
|
||||
if !(runtime.GOOS == "windows" && len(u.Scheme) == 1) {
|
||||
return false, nil
|
||||
}
|
||||
// For windows, we try to get the artifact
|
||||
// if it has a non valid scheme with 1 char
|
||||
// e.g. C:/foo/bar for other cases a prefix file:// is necessary
|
||||
}
|
||||
|
||||
src, ok, err := new(FileDetector).Detect(src, pwd)
|
||||
if err != nil {
|
||||
return ok, err
|
||||
}
|
||||
if ok {
|
||||
req.Src = src
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (g *FileGetter) validScheme(scheme string) bool {
|
||||
return scheme == "file"
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
// GitGetter is a Getter implementation that will download a module from
|
||||
// a git repository.
|
||||
type GitGetter struct {
|
||||
Detectors []Detector
|
||||
}
|
||||
|
||||
var defaultBranchRegexp = regexp.MustCompile(`\s->\sorigin/(.*)`)
|
||||
|
@ -313,3 +314,66 @@ func checkGitVersion(min string) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GitGetter) Detect(req *Request) (bool, error) {
|
||||
src := req.Src
|
||||
if len(src) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if req.Forced != "" {
|
||||
// There's a getter being Forced
|
||||
if !g.validScheme(req.Forced) {
|
||||
// Current getter is not the Forced one
|
||||
// Don't use it to try to download the artifact
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
isForcedGetter := req.Forced != "" && g.validScheme(req.Forced)
|
||||
|
||||
u, err := url.Parse(src)
|
||||
if err == nil && u.Scheme != "" {
|
||||
if isForcedGetter {
|
||||
// Is the Forced getter and source is a valid url
|
||||
return true, nil
|
||||
}
|
||||
if g.validScheme(u.Scheme) {
|
||||
return true, nil
|
||||
}
|
||||
// Valid url with a scheme that is not valid for current getter
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for _, d := range g.Detectors {
|
||||
src, ok, err := d.Detect(src, req.Pwd)
|
||||
if err != nil {
|
||||
return ok, err
|
||||
}
|
||||
forced, src := getForcedGetter(src)
|
||||
if ok && g.validScheme(forced) {
|
||||
req.Src = src
|
||||
return ok, nil
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = url.Parse(req.Src); err != nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if isForcedGetter {
|
||||
// Is the Forced getter and should be used to download the artifact
|
||||
if req.Pwd != "" && !filepath.IsAbs(src) {
|
||||
// Make sure to add pwd to relative paths
|
||||
src = filepath.Join(req.Pwd, src)
|
||||
}
|
||||
// Make sure we're using "/" on Windows. URLs are "/"-based.
|
||||
req.Src = filepath.ToSlash(src)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (g *GitGetter) validScheme(scheme string) bool {
|
||||
return scheme == "git" || scheme == "ssh"
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@ import (
|
|||
|
||||
// HgGetter is a Getter implementation that will download a module from
|
||||
// a Mercurial repository.
|
||||
type HgGetter struct {
|
||||
}
|
||||
type HgGetter struct{}
|
||||
|
||||
func (g *HgGetter) Mode(ctx context.Context, _ *url.URL) (Mode, error) {
|
||||
return ModeDir, nil
|
||||
|
@ -125,6 +124,63 @@ func (g *HgGetter) update(ctx context.Context, dst string, u *url.URL, rev strin
|
|||
return getRunCommand(cmd)
|
||||
}
|
||||
|
||||
func (g *HgGetter) Detect(req *Request) (bool, error) {
|
||||
src := req.Src
|
||||
if len(src) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if req.Forced != "" {
|
||||
// There's a getter being Forced
|
||||
if !g.validScheme(req.Forced) {
|
||||
// Current getter is not the Forced one
|
||||
// Don't use it to try to download the artifact
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
isForcedGetter := req.Forced != "" && g.validScheme(req.Forced)
|
||||
|
||||
u, err := url.Parse(src)
|
||||
if err == nil && u.Scheme != "" {
|
||||
if isForcedGetter {
|
||||
// Is the Forced getter and source is a valid url
|
||||
return true, nil
|
||||
}
|
||||
if g.validScheme(u.Scheme) {
|
||||
return true, nil
|
||||
}
|
||||
// Valid url with a scheme that is not valid for current getter
|
||||
return false, nil
|
||||
}
|
||||
|
||||
src, ok, err := new(BitBucketDetector).Detect(src, req.Pwd)
|
||||
if err != nil {
|
||||
return ok, err
|
||||
}
|
||||
forced, src := getForcedGetter(src)
|
||||
if ok && g.validScheme(forced) {
|
||||
req.Src = src
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
if isForcedGetter {
|
||||
// Is the Forced getter and should be used to download the artifact
|
||||
if req.Pwd != "" && !filepath.IsAbs(src) {
|
||||
// Make sure to add pwd to relative paths
|
||||
src = filepath.Join(req.Pwd, src)
|
||||
}
|
||||
// Make sure we're using "/" on Windows. URLs are "/"-based.
|
||||
req.Src = filepath.ToSlash(src)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (g *HgGetter) validScheme(scheme string) bool {
|
||||
return scheme == "hg"
|
||||
}
|
||||
|
||||
func fixWindowsDrivePath(u *url.URL) bool {
|
||||
// hg assumes a file:/// prefix for Windows drive letter file paths.
|
||||
// (e.g. file:///c:/foo/bar)
|
||||
|
|
|
@ -319,3 +319,38 @@ func charsetReader(charset string, input io.Reader) (io.Reader, error) {
|
|||
return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *HttpGetter) Detect(req *Request) (bool, error) {
|
||||
if len(req.Src) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if req.Forced != "" {
|
||||
// There's a getter being Forced
|
||||
if !g.validScheme(req.Forced) {
|
||||
// Current getter is not the Forced one
|
||||
// Don't use it to try to download the artifact
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
isForcedGetter := req.Forced != "" && g.validScheme(req.Forced)
|
||||
|
||||
u, err := url.Parse(req.Src)
|
||||
if err == nil && u.Scheme != "" {
|
||||
if isForcedGetter {
|
||||
// Is the Forced getter and source is a valid url
|
||||
return true, nil
|
||||
}
|
||||
if g.validScheme(u.Scheme) {
|
||||
return true, nil
|
||||
}
|
||||
// Valid url with a scheme that is not valid for current getter
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (g *HttpGetter) validScheme(scheme string) bool {
|
||||
return scheme == "http" || scheme == "https"
|
||||
}
|
||||
|
|
|
@ -52,3 +52,10 @@ func (g *MockGetter) Mode(ctx context.Context, u *url.URL) (Mode, error) {
|
|||
}
|
||||
return ModeFile, nil
|
||||
}
|
||||
|
||||
func (g *MockGetter) Detect(req *Request) (bool, error) {
|
||||
if g.Proxy != nil {
|
||||
return g.Proxy.Detect(req)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
package getter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// SmbMountGetter is a Getter implementation that will download an artifact from
|
||||
// a shared folder using the file system using FileGetter implementation.
|
||||
// For Unix and MacOS users, the Getter will look for usual system specific mount paths such as:
|
||||
// /Volumes/ for MacOS
|
||||
// /run/user/1000/gvfs/smb-share:server=<hostIP>,share=<path> for Unix
|
||||
type SmbMountGetter struct{}
|
||||
|
||||
func (g *SmbMountGetter) Mode(ctx context.Context, u *url.URL) (Mode, error) {
|
||||
if u.Host == "" || u.Path == "" {
|
||||
return 0, new(smbPathError)
|
||||
}
|
||||
|
||||
prefix, path := g.findPrefixAndPath(u)
|
||||
u.Path = prefix + path
|
||||
|
||||
return new(FileGetter).Mode(ctx, u)
|
||||
}
|
||||
|
||||
func (g *SmbMountGetter) Get(ctx context.Context, req *Request) error {
|
||||
if req.u.Host == "" || req.u.Path == "" {
|
||||
return new(smbPathError)
|
||||
}
|
||||
|
||||
prefix, path := g.findPrefixAndPath(req.u)
|
||||
req.u.Path = prefix + path
|
||||
|
||||
return new(FileGetter).Get(ctx, req)
|
||||
}
|
||||
|
||||
func (g *SmbMountGetter) GetFile(ctx context.Context, req *Request) error {
|
||||
if req.u.Host == "" || req.u.Path == "" {
|
||||
return new(smbPathError)
|
||||
}
|
||||
|
||||
prefix, path := g.findPrefixAndPath(req.u)
|
||||
req.u.Path = prefix + path
|
||||
|
||||
return new(FileGetter).GetFile(ctx, req)
|
||||
}
|
||||
|
||||
func (g *SmbMountGetter) findPrefixAndPath(u *url.URL) (string, string) {
|
||||
var prefix, path string
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
prefix = string(os.PathSeparator) + string(os.PathSeparator)
|
||||
path = filepath.Join(u.Host, u.Path)
|
||||
case "darwin":
|
||||
prefix = string(os.PathSeparator)
|
||||
path = filepath.Join("Volumes", u.Path)
|
||||
}
|
||||
return prefix, path
|
||||
}
|
||||
|
||||
func (g *SmbMountGetter) Detect(req *Request) (bool, error) {
|
||||
if runtime.GOOS == "linux" {
|
||||
// Linux has the smbclient command which is a safer approach to retrieve an artifact from a samba shared folder.
|
||||
// Therefore, this should be used instead of looking in the file system.
|
||||
return false, nil
|
||||
}
|
||||
if len(req.Src) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if req.Forced != "" {
|
||||
// There's a getter being Forced
|
||||
if !g.validScheme(req.Forced) {
|
||||
// Current getter is not the Forced one
|
||||
// Don't use it to try to download the artifact
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
isForcedGetter := req.Forced != "" && g.validScheme(req.Forced)
|
||||
|
||||
u, err := url.Parse(req.Src)
|
||||
if err == nil && u.Scheme != "" {
|
||||
if isForcedGetter {
|
||||
// Is the Forced getter and source is a valid url
|
||||
return true, nil
|
||||
}
|
||||
if g.validScheme(u.Scheme) {
|
||||
return true, nil
|
||||
}
|
||||
// Valid url with a scheme that is not valid for current getter
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (g *SmbMountGetter) validScheme(scheme string) bool {
|
||||
return scheme == "smb"
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
package getter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SmbClientGetter is a Getter implementation that will download a module from
|
||||
// a shared folder using smbclient cli.
|
||||
type SmbClientGetter struct{}
|
||||
|
||||
func (g *SmbClientGetter) Mode(ctx context.Context, u *url.URL) (Mode, error) {
|
||||
if u.Host == "" || u.Path == "" {
|
||||
return 0, new(smbPathError)
|
||||
}
|
||||
|
||||
// Use smbclient cli to verify mode
|
||||
mode, err := g.smbClientMode(u)
|
||||
if err == nil {
|
||||
return mode, nil
|
||||
}
|
||||
return 0, &smbGeneralError{err}
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) smbClientMode(u *url.URL) (Mode, error) {
|
||||
hostPath, filePath, err := g.findHostAndFilePath(u)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
file := ""
|
||||
// Get file and subdirectory name when existent
|
||||
if strings.Contains(filePath, "/") {
|
||||
i := strings.LastIndex(filePath, "/")
|
||||
file = filePath[i+1:]
|
||||
filePath = filePath[:i]
|
||||
} else {
|
||||
file = filePath
|
||||
filePath = "."
|
||||
}
|
||||
|
||||
cmdArgs := g.smbclientCmdArgs(u.User, hostPath, filePath)
|
||||
// check if file exists in the smb shared folder and check the mode
|
||||
isDir, err := g.isDirectory(cmdArgs, file)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if isDir {
|
||||
return ModeDir, nil
|
||||
}
|
||||
return ModeFile, nil
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) Get(ctx context.Context, req *Request) error {
|
||||
if req.u.Host == "" || req.u.Path == "" {
|
||||
return new(smbPathError)
|
||||
}
|
||||
|
||||
// If dst folder doesn't exists, we need to remove the created on later in case of failures
|
||||
dstExisted := false
|
||||
if req.Dst != "" {
|
||||
if _, err := os.Lstat(req.Dst); err == nil {
|
||||
dstExisted = true
|
||||
}
|
||||
}
|
||||
|
||||
// Download the directory content using smbclient cli
|
||||
err := g.smbclientGet(req)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !dstExisted {
|
||||
// Remove the destination created for smbclient
|
||||
os.Remove(req.Dst)
|
||||
}
|
||||
|
||||
return &smbGeneralError{err}
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) smbclientGet(req *Request) error {
|
||||
hostPath, directory, err := g.findHostAndFilePath(req.u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdArgs := g.smbclientCmdArgs(req.u.User, hostPath, ".")
|
||||
// check directory exists in the smb shared folder and is a directory
|
||||
isDir, err := g.isDirectory(cmdArgs, directory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isDir {
|
||||
return fmt.Errorf("%s source path must be a directory", directory)
|
||||
}
|
||||
|
||||
// download everything that's inside the directory (files and subdirectories)
|
||||
cmdArgs = append(cmdArgs, "-c")
|
||||
cmdArgs = append(cmdArgs, "prompt OFF;recurse ON; mget *")
|
||||
|
||||
if req.Dst != "" {
|
||||
_, err := os.Lstat(req.Dst)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// Create destination folder if it doesn't exist
|
||||
if err := os.MkdirAll(req.Dst, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create destination path: %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = g.runSmbClientCommand(req.Dst, cmdArgs)
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) GetFile(ctx context.Context, req *Request) error {
|
||||
if req.u.Host == "" || req.u.Path == "" {
|
||||
return new(smbPathError)
|
||||
}
|
||||
|
||||
// If dst folder doesn't exist, we need to remove the created one later in case of failures
|
||||
dstExisted := false
|
||||
if req.Dst != "" {
|
||||
if _, err := os.Lstat(req.Dst); err == nil {
|
||||
dstExisted = true
|
||||
}
|
||||
}
|
||||
|
||||
// If not mounted, try downloading the file using smbclient cli
|
||||
err := g.smbclientGetFile(req)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !dstExisted {
|
||||
// Remove the destination created for smbclient
|
||||
os.Remove(req.Dst)
|
||||
}
|
||||
|
||||
return &smbGeneralError{err}
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) smbclientGetFile(req *Request) error {
|
||||
hostPath, filePath, err := g.findHostAndFilePath(req.u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get file and subdirectory name when existent
|
||||
file := ""
|
||||
if strings.Contains(filePath, "/") {
|
||||
i := strings.LastIndex(filePath, "/")
|
||||
file = filePath[i+1:]
|
||||
filePath = filePath[:i]
|
||||
} else {
|
||||
file = filePath
|
||||
filePath = "."
|
||||
}
|
||||
|
||||
cmdArgs := g.smbclientCmdArgs(req.u.User, hostPath, filePath)
|
||||
// check file exists in the smb shared folder and is not a directory
|
||||
isDir, err := g.isDirectory(cmdArgs, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isDir {
|
||||
return fmt.Errorf("%s source path must be a file", file)
|
||||
}
|
||||
|
||||
// download file
|
||||
cmdArgs = append(cmdArgs, "-c")
|
||||
if req.Dst != "" {
|
||||
_, err := os.Lstat(req.Dst)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// Create destination folder if it doesn't exist
|
||||
if err := os.MkdirAll(filepath.Dir(req.Dst), 0755); err != nil {
|
||||
return fmt.Errorf("failed to creat destination path: %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cmdArgs = append(cmdArgs, fmt.Sprintf("get %s %s", file, req.Dst))
|
||||
} else {
|
||||
cmdArgs = append(cmdArgs, fmt.Sprintf("get %s", file))
|
||||
}
|
||||
|
||||
_, err = g.runSmbClientCommand("", cmdArgs)
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) smbclientCmdArgs(used *url.Userinfo, hostPath string, fileDir string) (baseCmd []string) {
|
||||
baseCmd = append(baseCmd, "-N")
|
||||
|
||||
// Append auth user and password to baseCmd
|
||||
auth := used.Username()
|
||||
if auth != "" {
|
||||
if password, ok := used.Password(); ok {
|
||||
auth = auth + "%" + password
|
||||
}
|
||||
baseCmd = append(baseCmd, "-U")
|
||||
baseCmd = append(baseCmd, auth)
|
||||
}
|
||||
|
||||
baseCmd = append(baseCmd, hostPath)
|
||||
baseCmd = append(baseCmd, "--directory")
|
||||
baseCmd = append(baseCmd, fileDir)
|
||||
return baseCmd
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) findHostAndFilePath(u *url.URL) (string, string, error) {
|
||||
// Host path
|
||||
hostPath := "//" + u.Host
|
||||
|
||||
// Get shared directory
|
||||
path := strings.TrimPrefix(u.Path, "/")
|
||||
splt := regexp.MustCompile(`/`)
|
||||
directories := splt.Split(path, 2)
|
||||
|
||||
if len(directories) > 0 {
|
||||
hostPath = hostPath + "/" + directories[0]
|
||||
}
|
||||
|
||||
// Check file path
|
||||
if len(directories) <= 1 || directories[1] == "" {
|
||||
return "", "", fmt.Errorf("can not find file path and/or name in the smb url")
|
||||
}
|
||||
|
||||
return hostPath, directories[1], nil
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) isDirectory(args []string, object string) (bool, error) {
|
||||
args = append(args, "-c")
|
||||
args = append(args, fmt.Sprintf("allinfo %s", object))
|
||||
output, err := g.runSmbClientCommand("", args)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(output, "OBJECT_NAME_NOT_FOUND") {
|
||||
return false, fmt.Errorf("source path not found: %s", output)
|
||||
}
|
||||
return strings.Contains(output, "attributes: D"), nil
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) runSmbClientCommand(dst string, args []string) (string, error) {
|
||||
cmd := exec.Command("smbclient", args...)
|
||||
|
||||
if dst != "" {
|
||||
cmd.Dir = dst
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
cmd.Stdout = &buf
|
||||
cmd.Stderr = &buf
|
||||
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
return buf.String(), nil
|
||||
}
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
// The program has exited with an exit code != 0
|
||||
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||
return buf.String(), fmt.Errorf(
|
||||
"%s exited with %d: %s",
|
||||
cmd.Path,
|
||||
status.ExitStatus(),
|
||||
buf.String())
|
||||
}
|
||||
}
|
||||
return buf.String(), fmt.Errorf("error running %s: %s", cmd.Path, buf.String())
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) Detect(req *Request) (bool, error) {
|
||||
if len(req.Src) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if req.Forced != "" {
|
||||
// There's a getter being Forced
|
||||
if !g.validScheme(req.Forced) {
|
||||
// Current getter is not the Forced one
|
||||
// Don't use it to try to download the artifact
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
isForcedGetter := req.Forced != "" && g.validScheme(req.Forced)
|
||||
|
||||
u, err := url.Parse(req.Src)
|
||||
if err == nil && u.Scheme != "" {
|
||||
if isForcedGetter {
|
||||
// Is the Forced getter and source is a valid url
|
||||
return true, nil
|
||||
}
|
||||
if g.validScheme(u.Scheme) {
|
||||
return true, nil
|
||||
}
|
||||
// Valid url with a scheme that is not valid for current getter
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (g *SmbClientGetter) validScheme(scheme string) bool {
|
||||
return scheme == "smb"
|
||||
}
|
||||
|
||||
type smbPathError struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
func (e *smbPathError) Error() string {
|
||||
if e.Path == "" {
|
||||
return "samba path should contain valid host, filepath, and authentication if necessary (smb://<user>:<password>@<host>/<file_path>)"
|
||||
}
|
||||
return fmt.Sprintf("samba path should contain valid host, filepath, and authentication if necessary (%s)", e.Path)
|
||||
}
|
||||
|
||||
type smbGeneralError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *smbGeneralError) Error() string {
|
||||
if e != nil {
|
||||
return fmt.Sprintf("smbclient cli needs to be installed and credentials provided when necessary. \n err: %s", e.err.Error())
|
||||
}
|
||||
return "smbclient cli needs to be installed and credentials provided when necessary."
|
||||
}
|
|
@ -4,7 +4,7 @@ require (
|
|||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d
|
||||
github.com/google/go-cmp v0.3.0
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0
|
||||
github.com/hashicorp/go-getter v1.4.1
|
||||
github.com/hashicorp/go-multierror v1.1.0
|
||||
github.com/hashicorp/go-safetemp v1.0.0
|
||||
github.com/hashicorp/go-version v1.1.0
|
||||
github.com/mitchellh/go-homedir v1.0.0
|
||||
|
|
|
@ -2,9 +2,12 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1U
|
|||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-getter v1.4.1 h1:3A2Mh8smGFcf5M+gmcv898mZdrxpseik45IpcyISLsA=
|
||||
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
||||
|
|
|
@ -18,6 +18,21 @@ type Request struct {
|
|||
Dst string
|
||||
Pwd string
|
||||
|
||||
// Forced is the forced getter detected in the Src string during the
|
||||
// Getter detection. Forcing a getter means that go-getter will try
|
||||
// to download the artifact only with the Getter that is being forced.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// Request.Src Forced
|
||||
// git::ssh://git@git.example.com:2222/foo/bar.git git
|
||||
//
|
||||
// This field is used by the Getters to validate when they are forced to download
|
||||
// the artifact.
|
||||
// If both Request.Src and Forced contains a forced getter, the one in the Request.Src will
|
||||
// be considered and will override the value of this field.
|
||||
Forced string
|
||||
|
||||
// Mode is the method of download the client will use. See Mode
|
||||
// for documentation.
|
||||
Mode Mode
|
||||
|
@ -37,7 +52,8 @@ type Request struct {
|
|||
// By default a no op progress listener is used.
|
||||
ProgressListener ProgressTracker
|
||||
|
||||
u *url.URL
|
||||
u *url.URL
|
||||
subDir, realDst string
|
||||
}
|
||||
|
||||
func (req *Request) URL() *url.URL {
|
||||
|
|
|
@ -320,11 +320,11 @@ github.com/hashicorp/go-cty-funcs/crypto
|
|||
github.com/hashicorp/go-cty-funcs/encoding
|
||||
github.com/hashicorp/go-cty-funcs/filesystem
|
||||
github.com/hashicorp/go-cty-funcs/uuid
|
||||
# github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200514151440-7b188cad6b7d
|
||||
# github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad
|
||||
github.com/hashicorp/go-getter/gcs/v2
|
||||
# github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200514151440-7b188cad6b7d
|
||||
# github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200604122502-a6995fa1edad
|
||||
github.com/hashicorp/go-getter/s3/v2
|
||||
# github.com/hashicorp/go-getter/v2 v2.0.0-20200518081638-5b5e57151574
|
||||
# github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad
|
||||
github.com/hashicorp/go-getter/v2
|
||||
github.com/hashicorp/go-getter/v2/helper/url
|
||||
# github.com/hashicorp/go-hclog v0.12.0
|
||||
|
|
Loading…
Reference in New Issue