From e5a1b1a368edeb68e527c0f5e4f114d6ec6470cb Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 4 Feb 2020 19:15:44 +0100 Subject: [PATCH] Allow to not download local files and simply reference them 'inplace' given an option, remove the 'Dir' bool option & rename ClientMode to Mode (#232) adds the Inplace bool field to a Request allowing to use local files 'inplace' and just setting the GetResult.Dst to the source file. This will allow Packer to not do any operation and to use big local files 'inplace'. --- checksum.go | 6 +- client.go | 26 ++++---- client_option_progress_test.go | 2 - cmd/go-getter/main.go | 8 +-- get.go | 18 +++--- get_file.go | 16 ++++- get_file_symlink_windows.go | 11 +--- get_file_test.go | 20 +++---- get_gcs.go | 8 +-- get_gcs_test.go | 24 ++++---- get_git.go | 4 +- get_git_test.go | 6 +- get_hg.go | 4 +- get_http.go | 12 ++-- get_mock.go | 6 +- get_s3.go | 8 +-- get_s3_test.go | 32 +++++----- get_test.go | 105 +++++++++++++++++++++++++++++---- go.mod | 1 + client_mode.go => mode.go | 18 +++--- request.go | 15 ++--- 21 files changed, 214 insertions(+), 136 deletions(-) rename client_mode.go => mode.go (53%) diff --git a/checksum.go b/checksum.go index 705d5576d..d10ab2c0b 100644 --- a/checksum.go +++ b/checksum.go @@ -206,9 +206,9 @@ func (c *Client) ChecksumFromFile(ctx context.Context, checksumURL, checksummedP req := &Request{ // Pwd: c.Pwd, TODO(adrien): pass pwd ? - Dir: false, - Src: checksumURL, - Dst: tempfile, + Mode: ModeFile, + Src: checksumURL, + Dst: tempfile, // ProgressListener: c.ProgressListener, TODO(adrien): pass progress bar ? } if _, err = c.Get(ctx, req); err != nil { diff --git a/client.go b/client.go index 7a43d492e..a6a1bf2bd 100644 --- a/client.go +++ b/client.go @@ -46,12 +46,8 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) { } // Store this locally since there are cases we swap this - if req.Mode == ClientModeInvalid { - if req.Dir { - req.Mode = ClientModeDir - } else { - req.Mode = ClientModeFile - } + if req.Mode == ModeInvalid { + req.Mode = ModeAny } var err error @@ -140,9 +136,9 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) { // Swap the download directory to be our temporary path and // store the old values. decompressDst = req.Dst - decompressDir = req.Mode != ClientModeFile + decompressDir = req.Mode != ModeFile req.Dst = filepath.Join(td, "archive") - req.Mode = ClientModeFile + req.Mode = ModeFile } // Determine checksum if we have one @@ -155,16 +151,16 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) { q.Del("checksum") req.u.RawQuery = q.Encode() - if req.Mode == ClientModeAny { + if req.Mode == ModeAny { // Ask the getter which client mode to use - req.Mode, err = g.ClientMode(ctx, req.u) + req.Mode, err = g.Mode(ctx, req.u) if err != nil { return nil, err } // Destination is the base name of the URL path in "any" mode when // a file source is detected. - if req.Mode == ClientModeFile { + if req.Mode == ModeFile { filename := filepath.Base(req.u.Path) // Determine if we have a custom file name @@ -182,7 +178,7 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) { // If we're not downloading a directory, then just download the file // and return. - if req.Mode == ClientModeFile { + if req.Mode == ModeFile { getFile := true if checksum != nil { if err := checksum.checksum(req.Dst); err == nil { @@ -214,16 +210,16 @@ func (c *Client) Get(ctx context.Context, req *Request) (*GetResult, error) { // Swap the information back req.Dst = decompressDst if decompressDir { - req.Mode = ClientModeAny + req.Mode = ModeAny } else { - req.Mode = ClientModeFile + req.Mode = ModeFile } } // We check the dir value again because it can be switched back // if we were unarchiving. If we're still only Get-ing a file, then // we're done. - if req.Mode == ClientModeFile { + if req.Mode == ModeFile { return &GetResult{req.Dst}, nil } } diff --git a/client_option_progress_test.go b/client_option_progress_test.go index a7b644dc2..8309f9091 100644 --- a/client_option_progress_test.go +++ b/client_option_progress_test.go @@ -54,7 +54,6 @@ func TestGet_progress(t *testing.T) { Dst: dst, Src: s.URL + "/file?thig=this&that", ProgressListener: p, - Dir: false, } if _, err := DefaultClient.Get(ctx, req); err != nil { t.Fatalf("download failed: %v", err) @@ -63,7 +62,6 @@ func TestGet_progress(t *testing.T) { Dst: dst, Src: s.URL + "/otherfile?thig=this&that", ProgressListener: p, - Dir: false, } if _, err := DefaultClient.Get(ctx, req); err != nil { t.Fatalf("download failed: %v", err) diff --git a/cmd/go-getter/main.go b/cmd/go-getter/main.go index 9c03f1ec2..9c52d6bf6 100644 --- a/cmd/go-getter/main.go +++ b/cmd/go-getter/main.go @@ -22,14 +22,14 @@ func main() { } // Get the mode - var mode getter.ClientMode + var mode getter.Mode switch *modeRaw { case "any": - mode = getter.ClientModeAny + mode = getter.ModeAny case "file": - mode = getter.ClientModeFile + mode = getter.ModeFile case "dir": - mode = getter.ClientModeDir + mode = getter.ModeDir default: log.Fatalf("Invalid client mode, must be 'any', 'file', or 'dir': %s", *modeRaw) os.Exit(1) diff --git a/get.go b/get.go index 5f9ce7afd..c82f52f05 100644 --- a/get.go +++ b/get.go @@ -39,9 +39,9 @@ type Getter interface { // the remote end contains the same file and no-op this operation. GetFile(context.Context, *Request) error - // ClientMode returns the mode based on the given URL. This is used to + // Mode returns the mode based on the given URL. This is used to // allow clients to let the getters decide which mode to use. - ClientMode(context.Context, *url.URL) (ClientMode, error) + Mode(context.Context, *url.URL) (Mode, error) // SetClient allows a getter to know it's client // in order to access client's Get functions or @@ -89,9 +89,9 @@ func init() { // folder doesn't need to exist. It will be created if it doesn't exist. func Get(ctx context.Context, dst, src string) (*GetResult, error) { req := &Request{ - Src: src, - Dst: dst, - Dir: true, + Src: src, + Dst: dst, + Mode: ModeDir, } return DefaultClient.Get(ctx, req) } @@ -106,7 +106,7 @@ func GetAny(ctx context.Context, dst, src string) (*GetResult, error) { req := &Request{ Src: src, Dst: dst, - Mode: ClientModeAny, + Mode: ModeAny, } return DefaultClient.Get(ctx, req) } @@ -115,9 +115,9 @@ func GetAny(ctx context.Context, dst, src string) (*GetResult, error) { // dst. func GetFile(ctx context.Context, dst, src string) (*GetResult, error) { req := &Request{ - Src: src, - Dst: dst, - Dir: false, + Src: src, + Dst: dst, + Mode: ModeFile, } return DefaultClient.Get(ctx, req) } diff --git a/get_file.go b/get_file.go index eccd41210..f11d13ecf 100644 --- a/get_file.go +++ b/get_file.go @@ -14,7 +14,7 @@ type FileGetter struct { getter } -func (g *FileGetter) ClientMode(ctx context.Context, u *url.URL) (ClientMode, error) { +func (g *FileGetter) Mode(ctx context.Context, u *url.URL) (Mode, error) { path := u.Path if u.RawPath != "" { path = u.RawPath @@ -27,10 +27,10 @@ func (g *FileGetter) ClientMode(ctx context.Context, u *url.URL) (ClientMode, er // Check if the source is a directory. if fi.IsDir() { - return ClientModeDir, nil + return ModeDir, nil } - return ClientModeFile, nil + return ModeFile, nil } func (g *FileGetter) Get(ctx context.Context, req *Request) error { @@ -51,6 +51,11 @@ func (g *FileGetter) Get(ctx context.Context, req *Request) error { return err } + if req.Inplace { + req.Dst = path + return nil + } + // If the destination already exists, it must be a symlink if err == nil { mode := fi.Mode() @@ -85,6 +90,11 @@ func (g *FileGetter) GetFile(ctx context.Context, req *Request) error { return fmt.Errorf("source path must be a file") } + if req.Inplace { + req.Dst = path + return nil + } + _, err := os.Lstat(req.Dst) if err != nil && !os.IsNotExist(err) { return err diff --git a/get_file_symlink_windows.go b/get_file_symlink_windows.go index 5b8032a2a..dd0b7fe84 100644 --- a/get_file_symlink_windows.go +++ b/get_file_symlink_windows.go @@ -3,12 +3,12 @@ package getter import ( "fmt" "os/exec" - "strings" + "path/filepath" "syscall" ) func SymlinkAny(oldname, newname string) error { - sourcePath := toBackslash(oldname) + sourcePath := filepath.FromSlash(oldname) // Use mklink to create a junction point output, err := exec.Command("cmd", "/c", "mklink", "/J", newname, sourcePath).CombinedOutput() @@ -19,10 +19,3 @@ func SymlinkAny(oldname, newname string) error { } var ErrUnauthorized = syscall.ERROR_PRIVILEGE_NOT_HELD - -// 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) -} diff --git a/get_file_test.go b/get_file_test.go index 02fa03419..f18fe8d57 100644 --- a/get_file_test.go +++ b/get_file_test.go @@ -217,40 +217,40 @@ func TestFileGetter_percent2F(t *testing.T) { } } -func TestFileGetter_ClientMode_notexist(t *testing.T) { +func TestFileGetter_Mode_notexist(t *testing.T) { g := new(FileGetter) ctx := context.Background() u := testURL("nonexistent") - if _, err := g.ClientMode(ctx, u); err == nil { + if _, err := g.Mode(ctx, u); err == nil { t.Fatal("expect source file error") } } -func TestFileGetter_ClientMode_file(t *testing.T) { +func TestFileGetter_Mode_file(t *testing.T) { g := new(FileGetter) ctx := context.Background() // Check the client mode when pointed at a file. - mode, err := g.ClientMode(ctx, testModuleURL("basic-file/foo.txt")) + mode, err := g.Mode(ctx, testModuleURL("basic-file/foo.txt")) if err != nil { t.Fatalf("err: %s", err) } - if mode != ClientModeFile { - t.Fatal("expect ClientModeFile") + if mode != ModeFile { + t.Fatal("expect ModeFile") } } -func TestFileGetter_ClientMode_dir(t *testing.T) { +func TestFileGetter_Mode_dir(t *testing.T) { g := new(FileGetter) ctx := context.Background() // Check the client mode when pointed at a directory. - mode, err := g.ClientMode(ctx, testModuleURL("basic")) + mode, err := g.Mode(ctx, testModuleURL("basic")) if err != nil { t.Fatalf("err: %s", err) } - if mode != ClientModeDir { - t.Fatal("expect ClientModeDir") + if mode != ModeDir { + t.Fatal("expect ModeDir") } } diff --git a/get_gcs.go b/get_gcs.go index f81913890..a1c6409c1 100644 --- a/get_gcs.go +++ b/get_gcs.go @@ -18,7 +18,7 @@ type GCSGetter struct { getter } -func (g *GCSGetter) ClientMode(ctx context.Context, u *url.URL) (ClientMode, error) { +func (g *GCSGetter) Mode(ctx context.Context, u *url.URL) (Mode, error) { // Parse URL bucket, object, err := g.parseURL(u) @@ -42,16 +42,16 @@ func (g *GCSGetter) ClientMode(ctx context.Context, u *url.URL) (ClientMode, err } if strings.HasSuffix(obj.Name, "/") { // A directory matched the prefix search, so this must be a directory - return ClientModeDir, nil + return ModeDir, nil } else if obj.Name != object { // A file matched the prefix search and doesn't have the same name // as the query, so this must be a directory - return ClientModeDir, nil + return ModeDir, nil } } // There are no directories or subdirectories, and if a match was returned, // it was exactly equal to the prefix search. So return File mode - return ClientModeFile, nil + return ModeFile, nil } func (g *GCSGetter) Get(ctx context.Context, req *Request) error { diff --git a/get_gcs_test.go b/get_gcs_test.go index 54b16b09d..9874cd305 100644 --- a/get_gcs_test.go +++ b/get_gcs_test.go @@ -122,41 +122,41 @@ func TestGCSGetter_GetFile_notfound(t *testing.T) { } } -func TestGCSGetter_ClientMode_dir(t *testing.T) { +func TestGCSGetter_Mode_dir(t *testing.T) { defer initGCPCredentials(t)() g := new(GCSGetter) ctx := context.Background() // Check client mode on a key prefix with only a single key. - mode, err := g.ClientMode(ctx, + mode, err := g.Mode(ctx, testURL("https://www.googleapis.com/storage/v1/go-getter-test/go-getter/folder/subfolder")) if err != nil { t.Fatalf("err: %s", err) } - if mode != ClientModeDir { - t.Fatal("expect ClientModeDir") + if mode != ModeDir { + t.Fatal("expect ModeDir") } } -func TestGCSGetter_ClientMode_file(t *testing.T) { +func TestGCSGetter_Mode_file(t *testing.T) { defer initGCPCredentials(t)() g := new(GCSGetter) ctx := context.Background() // Check client mode on a key prefix which contains sub-keys. - mode, err := g.ClientMode(ctx, + mode, err := g.Mode(ctx, testURL("https://www.googleapis.com/storage/v1/go-getter-test/go-getter/folder/subfolder/sub.tf")) if err != nil { t.Fatalf("err: %s", err) } - if mode != ClientModeFile { - t.Fatal("expect ClientModeFile") + if mode != ModeFile { + t.Fatal("expect ModeFile") } } -func TestGCSGetter_ClientMode_notfound(t *testing.T) { +func TestGCSGetter_Mode_notfound(t *testing.T) { defer initGCPCredentials(t)() g := new(GCSGetter) @@ -164,13 +164,13 @@ func TestGCSGetter_ClientMode_notfound(t *testing.T) { // Check the client mode when a non-existent key is looked up. This does not // return an error, but rather should just return the file mode. - mode, err := g.ClientMode(ctx, + mode, err := g.Mode(ctx, testURL("https://www.googleapis.com/storage/v1/go-getter-test/go-getter/foobar")) if err != nil { t.Fatalf("err: %s", err) } - if mode != ClientModeFile { - t.Fatal("expect ClientModeFile") + if mode != ModeFile { + t.Fatal("expect ModeFile") } } diff --git a/get_git.go b/get_git.go index e236067bc..4a0b044f7 100644 --- a/get_git.go +++ b/get_git.go @@ -28,8 +28,8 @@ type GitGetter struct { var defaultBranchRegexp = regexp.MustCompile(`\s->\sorigin/(.*)`) -func (g *GitGetter) ClientMode(_ context.Context, u *url.URL) (ClientMode, error) { - return ClientModeDir, nil +func (g *GitGetter) Mode(_ context.Context, u *url.URL) (Mode, error) { + return ModeDir, nil } func (g *GitGetter) Get(ctx context.Context, req *Request) error { diff --git a/get_git_test.go b/get_git_test.go index fde606863..eedba0ed4 100644 --- a/get_git_test.go +++ b/get_git_test.go @@ -409,7 +409,7 @@ func TestGitGetter_sshSCPStyle(t *testing.T) { Dst: dst, Pwd: ".", - Mode: ClientModeDir, + Mode: ModeDir, } client := &Client{ Detectors: []Detector{ @@ -452,7 +452,7 @@ func TestGitGetter_sshExplicitPort(t *testing.T) { Dst: dst, Pwd: ".", - Mode: ClientModeDir, + Mode: ModeDir, } client := &Client{ @@ -496,7 +496,7 @@ func TestGitGetter_sshSCPStyleInvalidScheme(t *testing.T) { Dst: dst, Pwd: ".", - Mode: ClientModeDir, + Mode: ModeDir, } client := &Client{ diff --git a/get_hg.go b/get_hg.go index 365c3caae..4532113e4 100644 --- a/get_hg.go +++ b/get_hg.go @@ -19,8 +19,8 @@ type HgGetter struct { getter } -func (g *HgGetter) ClientMode(ctx context.Context, _ *url.URL) (ClientMode, error) { - return ClientModeDir, nil +func (g *HgGetter) Mode(ctx context.Context, _ *url.URL) (Mode, error) { + return ModeDir, nil } func (g *HgGetter) Get(ctx context.Context, req *Request) error { diff --git a/get_http.go b/get_http.go index a80ad2502..27671b32d 100644 --- a/get_http.go +++ b/get_http.go @@ -52,11 +52,11 @@ type HttpGetter struct { Header http.Header } -func (g *HttpGetter) ClientMode(ctx context.Context, u *url.URL) (ClientMode, error) { +func (g *HttpGetter) Mode(ctx context.Context, u *url.URL) (Mode, error) { if strings.HasSuffix(u.Path, "/") { - return ClientModeDir, nil + return ModeDir, nil } - return ClientModeFile, nil + return ModeFile, nil } func (g *HttpGetter) Get(ctx context.Context, req *Request) error { @@ -117,9 +117,9 @@ func (g *HttpGetter) Get(ctx context.Context, req *Request) error { // into a temporary directory, then copy over the proper subdir. source, subDir := SourceDirSubdir(source) req = &Request{ - Dir: true, - Src: source, - Dst: req.Dst, + Mode: ModeDir, + Src: source, + Dst: req.Dst, } if subDir == "" { _, err = DefaultClient.Get(ctx, req) diff --git a/get_mock.go b/get_mock.go index 786677e35..26ea38143 100644 --- a/get_mock.go +++ b/get_mock.go @@ -47,9 +47,9 @@ func (g *MockGetter) GetFile(ctx context.Context, req *Request) error { return g.GetFileErr } -func (g *MockGetter) ClientMode(ctx context.Context, u *url.URL) (ClientMode, error) { +func (g *MockGetter) Mode(ctx context.Context, u *url.URL) (Mode, error) { if l := len(u.Path); l > 0 && u.Path[l-1:] == "/" { - return ClientModeDir, nil + return ModeDir, nil } - return ClientModeFile, nil + return ModeFile, nil } diff --git a/get_s3.go b/get_s3.go index d45962a57..77d8fb317 100644 --- a/get_s3.go +++ b/get_s3.go @@ -22,7 +22,7 @@ type S3Getter struct { getter } -func (g *S3Getter) ClientMode(ctx context.Context, u *url.URL) (ClientMode, error) { +func (g *S3Getter) Mode(ctx context.Context, u *url.URL) (Mode, error) { // Parse URL region, bucket, path, _, creds, err := g.parseUrl(u) if err != nil { @@ -47,18 +47,18 @@ func (g *S3Getter) ClientMode(ctx context.Context, u *url.URL) (ClientMode, erro for _, o := range resp.Contents { // Use file mode on exact match. if *o.Key == path { - return ClientModeFile, nil + return ModeFile, nil } // Use dir mode if child keys are found. if strings.HasPrefix(*o.Key, path+"/") { - return ClientModeDir, nil + return ModeDir, nil } } // There was no match, so just return file mode. The download is going // to fail but we will let S3 return the proper error later. - return ClientModeFile, nil + return ModeFile, nil } func (g *S3Getter) Get(ctx context.Context, req *Request) error { diff --git a/get_s3_test.go b/get_s3_test.go index 303b1ce04..67d3b5ea3 100644 --- a/get_s3_test.go +++ b/get_s3_test.go @@ -136,39 +136,39 @@ func TestS3Getter_GetFile_notfound(t *testing.T) { } } -func TestS3Getter_ClientMode_dir(t *testing.T) { +func TestS3Getter_Mode_dir(t *testing.T) { ctx := context.Background() g := new(S3Getter) // Check client mode on a key prefix with only a single key. - mode, err := g.ClientMode(ctx, + mode, err := g.Mode(ctx, testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/folder")) if err != nil { t.Fatalf("err: %s", err) } - if mode != ClientModeDir { - t.Fatal("expect ClientModeDir") + if mode != ModeDir { + t.Fatal("expect ModeDir") } } -func TestS3Getter_ClientMode_file(t *testing.T) { +func TestS3Getter_Mode_file(t *testing.T) { ctx := context.Background() g := new(S3Getter) // Check client mode on a key prefix which contains sub-keys. - mode, err := g.ClientMode(ctx, + mode, err := g.Mode(ctx, testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/folder/main.tf")) if err != nil { t.Fatalf("err: %s", err) } - if mode != ClientModeFile { - t.Fatal("expect ClientModeFile") + if mode != ModeFile { + t.Fatal("expect ModeFile") } } -func TestS3Getter_ClientMode_notfound(t *testing.T) { +func TestS3Getter_Mode_notfound(t *testing.T) { ctx := context.Background() g := new(S3Getter) @@ -178,30 +178,30 @@ func TestS3Getter_ClientMode_notfound(t *testing.T) { // can return an appropriate error later on. This also checks that the // prefix is handled properly (e.g., "/fold" and "/folder" don't put the // client mode into "dir". - mode, err := g.ClientMode(ctx, + mode, err := g.Mode(ctx, testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/fold")) if err != nil { t.Fatalf("err: %s", err) } - if mode != ClientModeFile { - t.Fatal("expect ClientModeFile") + if mode != ModeFile { + t.Fatal("expect ModeFile") } } -func TestS3Getter_ClientMode_collision(t *testing.T) { +func TestS3Getter_Mode_collision(t *testing.T) { ctx := context.Background() g := new(S3Getter) // Check that the client mode is "file" if there is both an object and a // folder with a common prefix (i.e., a "collision" in the namespace). - mode, err := g.ClientMode(ctx, + mode, err := g.Mode(ctx, testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/collision/foo")) if err != nil { t.Fatalf("err: %s", err) } - if mode != ClientModeFile { - t.Fatal("expect ClientModeFile") + if mode != ModeFile { + t.Fatal("expect ModeFile") } } diff --git a/get_test.go b/get_test.go index 8a23b47eb..7b35dd02d 100644 --- a/get_test.go +++ b/get_test.go @@ -99,10 +99,10 @@ func TestGet_fileDetect(t *testing.T) { } req := &Request{ - Src: u, - Dst: dst, - Pwd: pwd, - Dir: true, + Src: u, + Dst: dst, + Pwd: pwd, + Mode: ModeAny, } client := &Client{} @@ -261,7 +261,7 @@ func TestGet_archiveSubdirWildMultiMatch(t *testing.T) { t.Fatalf("err: %s", err) } if op != nil { - t.Fatal("operation should be nil") + t.Fatal("GetResult should be nil") } } } @@ -583,9 +583,9 @@ func TestGetFile_checksumURL(t *testing.T) { getter := &MockGetter{Proxy: new(FileGetter)} req := &Request{ - Src: u, - Dst: dst, - Dir: false, + Src: u, + Dst: dst, + Mode: ModeFile, } client := &Client{ Getters: map[string]Getter{ @@ -638,9 +638,9 @@ func TestGetFile_checksumSkip(t *testing.T) { getter := &MockGetter{Proxy: new(FileGetter)} req := &Request{ - Src: u, - Dst: dst, - Dir: false, + Src: u, + Dst: dst, + Mode: ModeFile, } client := &Client{ Getters: map[string]Getter{ @@ -677,3 +677,86 @@ func TestGetFile_checksumSkip(t *testing.T) { t.Fatalf("get should not have been called") } } + +func TestGetFile_inplace(t *testing.T) { + ctx := context.Background() + + dst := tempTestFile(t) + defer os.RemoveAll(filepath.Dir(dst)) + src := testModule("basic-file/foo.txt") + + getter := &MockGetter{Proxy: new(FileGetter)} + req := &Request{ + Src: src + "?checksum=md5:09f7e02f1290be211da707a266f153b3", + Dst: dst, + Mode: ModeFile, + Inplace: true, + } + client := &Client{ + Getters: map[string]Getter{ + "file": getter, + }, + } + + // get the file + op, err := client.Get(ctx, req) + if err != nil { + t.Fatalf("err: %s", err) + } + if diff := cmp.Diff(&GetResult{Dst: strings.ReplaceAll(src, "file://", "")}, op); diff != "" { + t.Fatalf("unexpected op: %s", diff) + } + + if v := getter.GetFileURL.Query().Get("checksum"); v != "" { + t.Fatalf("bad: %s", v) + } + + // remove proxy file getter and reset GetFileCalled so that we can re-test. + getter.Proxy = nil + getter.GetFileCalled = false + + op, err = client.Get(ctx, req) + if err != nil { + t.Fatalf("err: %s", err) + } + if diff := cmp.Diff(&GetResult{Dst: strings.ReplaceAll(src, "file://", "")}, op); diff != "" { + t.Fatalf("unexpected op: %s", diff) + } + + if getter.GetFileCalled { + t.Fatalf("get should not have been called") + } +} + +func TestGetFile_inplace_badChecksum(t *testing.T) { + ctx := context.Background() + + dst := tempTestFile(t) + defer os.RemoveAll(filepath.Dir(dst)) + src := testModule("basic-file/foo.txt") + + getter := &MockGetter{Proxy: new(FileGetter)} + req := &Request{ + Src: src + "?checksum=md5:09f7e02f1290be211da707a266f153b4", + Dst: dst, + Mode: ModeFile, + Inplace: true, + } + client := &Client{ + Getters: map[string]Getter{ + "file": getter, + }, + } + + // get the file + op, err := client.Get(ctx, req) + if err == nil { + t.Fatalf("err is nil") + } + if _, ok := err.(*ChecksumError); !ok { + t.Fatalf("err is not a checksum error: %v", err) + } + if op != nil { + t.Fatalf("op is not nil") + } +} diff --git a/go.mod b/go.mod index 30606f9b8..495d5ad72 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/cheggaaa/pb v1.0.27 github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.7.0 // indirect + github.com/google/go-cmp v0.3.0 github.com/hashicorp/go-cleanhttp v0.5.0 github.com/hashicorp/go-safetemp v1.0.0 github.com/hashicorp/go-version v1.1.0 diff --git a/client_mode.go b/mode.go similarity index 53% rename from client_mode.go rename to mode.go index 7f02509a7..c9fd2d9c7 100644 --- a/client_mode.go +++ b/mode.go @@ -1,24 +1,24 @@ package getter -// ClientMode is the mode that the client operates in. -type ClientMode uint +// Mode is the mode that the client operates in. +type Mode uint const ( - ClientModeInvalid ClientMode = iota + ModeInvalid Mode = iota - // ClientModeAny downloads anything it can. In this mode, dst must + // ModeAny 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 + ModeAny - // ClientModeFile downloads a single file. In this mode, dst must + // ModeFile 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 + ModeFile - // ClientModeDir downloads a directory. In this mode, dst must be + // ModeDir 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 + ModeDir ) diff --git a/request.go b/request.go index a93d2ba33..f8f24d592 100644 --- a/request.go +++ b/request.go @@ -16,9 +16,9 @@ type Request struct { Dst string Pwd string - // Mode is the method of download the client will use. See ClientMode + // Mode is the method of download the client will use. See Mode // for documentation. - Mode ClientMode + Mode Mode // Copy, in local file mode if set to true, will copy data instead of using // a symlink. If false, attempts to symlink to speed up the operation and @@ -26,13 +26,10 @@ type Request struct { // on windows. Copy bool - // 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 + // Inplace, in local file mode if set to true, do nothing and the returned + // operation will simply contain the source file path. Inplace has precedence + // over Copy. + Inplace bool // ProgressListener allows to track file downloads. // By default a no op progress listener is used.