diff --git a/detect_gcs.go b/detect_gcs.go index 66e2bc399..11363737c 100644 --- a/detect_gcs.go +++ b/detect_gcs.go @@ -16,22 +16,28 @@ func (d *GCSDetector) Detect(src, _ string) (string, bool, error) { } if strings.Contains(src, "googleapis.com/") { - return d.detectHTTP(fmt.Sprintf("https://www.googleapis.com/%s", - strings.SplitN(src, "googleapis.com/", 2)[1])) + return d.detectHTTP(src) } return "", false, nil } func (d *GCSDetector) detectHTTP(src string) (string, bool, error) { - url, err := url.Parse(src) + + parts := strings.Split(src, "/") + if len(parts) < 5 { + return "", false, fmt.Errorf( + "URL is not a valid GCS URL") + } + version := parts[2] + bucket := parts[3] + object := strings.Join(parts[4:], "/") + + url, err := url.Parse(fmt.Sprintf("https://www.googleapis.com/storage/%s/%s/%s", + version, bucket, object)) if err != nil { return "", false, fmt.Errorf("error parsing GCS URL: %s", err) } - pathParts := strings.SplitN(url.Path, "/", 5) - if len(pathParts) != 5 { - return "", false, fmt.Errorf("URL is not a valid GCS URL") - } return "gcs::" + url.String(), true, nil } diff --git a/detect_gsc_test.go b/detect_gsc_test.go new file mode 100644 index 000000000..94e1ec42b --- /dev/null +++ b/detect_gsc_test.go @@ -0,0 +1,41 @@ +package getter + +import ( + "testing" +) + +func TestGCSDetector(t *testing.T) { + cases := []struct { + Input string + Output string + }{ + { + "www.googleapis.com/storage/v1/bucket/foo", + "gcs::https://www.googleapis.com/storage/v1/bucket/foo", + }, + { + "www.googleapis.com/storage/v1/bucket/foo/bar", + "gcs::https://www.googleapis.com/storage/v1/bucket/foo/bar", + }, + { + "www.googleapis.com/storage/v1/foo/bar.baz", + "gcs::https://www.googleapis.com/storage/v1/foo/bar.baz", + }, + } + + pwd := "/pwd" + f := new(GCSDetector) + for i, tc := range cases { + output, ok, err := f.Detect(tc.Input, pwd) + if err != nil { + t.Fatalf("err: %s", err) + } + if !ok { + t.Fatal("not ok") + } + + if output != tc.Output { + t.Fatalf("%d: bad: %#v", i, output) + } + } +} diff --git a/get_gcs.go b/get_gcs.go index 7c6836543..26e5a0ba1 100644 --- a/get_gcs.go +++ b/get_gcs.go @@ -3,7 +3,6 @@ package getter import ( "context" "fmt" - "log" "net/url" "os" "path/filepath" @@ -34,31 +33,27 @@ func (g *GCSGetter) ClientMode(u *url.URL) (ClientMode, error) { return 0, err } iter := client.Bucket(bucket).Objects(ctx, &storage.Query{Prefix: object}) - - count := 0 for { - objAtrr, err := iter.Next() + obj, err := iter.Next() + if err != nil && err != iterator.Done { + return 0, err + } if err == iterator.Done { - log.Printf("done") break } - if err != nil && err != iterator.Done { - return 0, err + if strings.HasSuffix(obj.Name, "/") { + // A directory matched the prefix search, so this must be a directory + return ClientModeDir, 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 } - log.Printf("iter: %+v", *objAtrr) - log.Println() - count++ - log.Printf("count: %d", count) - - } - log.Println() - if count <= 1 { - // Return file if there are no matches as well. - // GetFile will fail in this case. - return ClientModeFile, nil } - return ClientModeDir, 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 } func (g *GCSGetter) Get(dst string, u *url.URL) error { @@ -104,16 +99,18 @@ func (g *GCSGetter) Get(dst string, u *url.URL) error { break } - // Get the object destination path - objDst, err := filepath.Rel(object, obj.Name) - if err != nil { - return err - } - objDst = filepath.Join(dst, objDst) - // Download the matching object. - err = g.getObject(ctx, client, objDst, bucket, obj.Name) - if err != nil { - return err + if !strings.HasSuffix(obj.Name, "/") { + // Get the object destination path + objDst, err := filepath.Rel(object, obj.Name) + if err != nil { + return err + } + objDst = filepath.Join(dst, objDst) + // Download the matching object. + err = g.getObject(ctx, client, objDst, bucket, obj.Name) + if err != nil { + return err + } } } return nil diff --git a/get_gcs_test.go b/get_gcs_test.go index baf2d4132..20dcaf6ce 100644 --- a/get_gcs_test.go +++ b/get_gcs_test.go @@ -13,6 +13,7 @@ func init() { func TestGCSGetter_impl(t *testing.T) { var _ Getter = new(GCSGetter) } + func TestGCSGetter(t *testing.T) { g := new(GCSGetter) dst := tempDir(t) @@ -30,6 +31,7 @@ func TestGCSGetter(t *testing.T) { t.Fatalf("err: %s", err) } } + func TestGCSGetter_subdir(t *testing.T) { g := new(GCSGetter) dst := tempDir(t) @@ -85,7 +87,7 @@ func TestGCSGetter_ClientMode_dir(t *testing.T) { // Check client mode on a key prefix with only a single key. mode, err := g.ClientMode( - testURL("https://www.googleapis.com/storage/v1/eddie-test-devmvp-1/tf-environments")) + testURL("https://www.googleapis.com/storage/v1/hc-oss-test/go-getter/folder/subfolder")) if err != nil { t.Fatalf("err: %s", err) } @@ -94,19 +96,34 @@ func TestGCSGetter_ClientMode_dir(t *testing.T) { } } -// func TestGCSGetter_ClientMode_file(t *testing.T) { -// g := new(GCSGetter) - -// // Check client mode on a key prefix which contains sub-keys. -// mode, err := g.ClientMode( -// testURL("https://www.googleapis.com/storage/v1/hc-oss-test/go-getter/folder/main.tf")) -// if err != nil { -// t.Fatalf("err: %s", err) -// } -// if mode != ClientModeFile { -// t.Fatal("expect ClientModeFile") -// } -// } +func TestGCSGetter_ClientMode_file(t *testing.T) { + g := new(GCSGetter) + + // Check client mode on a key prefix which contains sub-keys. + mode, err := g.ClientMode( + testURL("https://www.googleapis.com/storage/v1/hc-oss-test/go-getter/folder/subfolder/sub.tf")) + if err != nil { + t.Fatalf("err: %s", err) + } + if mode != ClientModeFile { + t.Fatal("expect ClientModeFile") + } +} + +func TestGCSGetter_ClientMode_notfound(t *testing.T) { + g := new(GCSGetter) + + // 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( + testURL("https://www.googleapis.com/storage/v1/hc-oss-test/go-getter/foobar")) + if err != nil { + t.Fatalf("err: %s", err) + } + if mode != ClientModeFile { + t.Fatal("expect ClientModeFile") + } +} func TestGCSGetter_Url(t *testing.T) { var gcstests = []struct { diff --git a/get_git_test.go b/get_git_test.go index 666418824..ab44c8b1b 100644 --- a/get_git_test.go +++ b/get_git_test.go @@ -1,6 +1,7 @@ package getter import ( + "encoding/base64" "io/ioutil" "net/url" "os" @@ -227,32 +228,32 @@ func TestGitGetter_gitVersion(t *testing.T) { } } -// func TestGitGetter_sshKey(t *testing.T) { -// if !testHasGit { -// t.Log("git not found, skipping") -// t.Skip() -// } +func TestGitGetter_sshKey(t *testing.T) { + if !testHasGit { + t.Log("git not found, skipping") + t.Skip() + } -// g := new(GitGetter) -// dst := tempDir(t) + g := new(GitGetter) + dst := tempDir(t) -// encodedKey := base64.StdEncoding.EncodeToString([]byte(testGitToken)) + encodedKey := base64.StdEncoding.EncodeToString([]byte(testGitToken)) -// u, err := url.Parse("ssh://git@github.com/hashicorp/test-private-repo" + -// "?sshkey=" + encodedKey) -// if err != nil { -// t.Fatal(err) -// } + u, err := url.Parse("ssh://git@github.com/hashicorp/test-private-repo" + + "?sshkey=" + encodedKey) + if err != nil { + t.Fatal(err) + } -// if err := g.Get(dst, u); err != nil { -// t.Fatalf("err: %s", err) -// } + if err := g.Get(dst, u); err != nil { + t.Fatalf("err: %s", err) + } -// readmePath := filepath.Join(dst, "README.md") -// if _, err := os.Stat(readmePath); err != nil { -// t.Fatalf("err: %s", err) -// } -// } + readmePath := filepath.Join(dst, "README.md") + if _, err := os.Stat(readmePath); err != nil { + t.Fatalf("err: %s", err) + } +} func TestGitGetter_submodule(t *testing.T) { if !testHasGit { diff --git a/test b/test deleted file mode 100644 index b3a425249..000000000 --- a/test +++ /dev/null @@ -1 +0,0 @@ -placeholder \ No newline at end of file diff --git a/test/default.tfstate b/test/default.tfstate new file mode 100644 index 000000000..1e8d13b8b --- /dev/null +++ b/test/default.tfstate @@ -0,0 +1,15 @@ +{ + "version": 3, + "serial": 1, + "lineage": "cace175f-2333-0ab6-3108-ace60b611a78", + "modules": [ + { + "path": [ + "root" + ], + "outputs": {}, + "resources": {}, + "depends_on": [] + } + ] +}