diff options
author | Martin Polden <mpolden@mpolden.no> | 2023-08-23 11:38:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-23 11:38:05 +0200 |
commit | ba88ba050dc729f0405df6386aa731eb5dc50502 (patch) | |
tree | f897001636bd0a2f7820c8f54a1a7f8004b8020a /client | |
parent | 0b90f4fd3efc480d7fa2f46b037ccb6b3c5e13a9 (diff) | |
parent | 14dc0c331f8d607019f60e745e22137d0865cfd9 (diff) |
Merge pull request #28120 from vespa-engine/mpolden/clone-to-cwd
Support cloning into existing and empty directory
Diffstat (limited to 'client')
-rw-r--r-- | client/go/internal/cli/cmd/clone.go | 26 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/clone_test.go | 42 |
2 files changed, 54 insertions, 14 deletions
diff --git a/client/go/internal/cli/cmd/clone.go b/client/go/internal/cli/cmd/clone.go index 6fb97581ea3..a835892990b 100644 --- a/client/go/internal/cli/cmd/clone.go +++ b/client/go/internal/cli/cmd/clone.go @@ -6,8 +6,10 @@ package cmd import ( "archive/zip" + "errors" "fmt" "io" + "io/fs" "log" "net/http" "os" @@ -76,6 +78,23 @@ type zipFile struct { modTime time.Time } +func (c *cloner) createDirectory(path string) error { + if err := os.Mkdir(path, 0755); err != nil { + if errors.Is(err, fs.ErrExist) { + entries, err := os.ReadDir(path) + if err != nil { + return err + } + if len(entries) > 0 { + return fmt.Errorf("%s already exists and is not empty", path) + } + } else { + return err + } + } + return nil +} + // Clone copies the application identified by applicationName into given path. If the cached copy of sample applications // has expired (as determined by its entity tag), a current copy will be downloaded from GitHub automatically. func (c *cloner) Clone(applicationName, path string) error { @@ -95,9 +114,8 @@ func (c *cloner) Clone(applicationName, path string) error { dirPrefix := "sample-apps-master/" + applicationName + "/" if strings.HasPrefix(f.Name, dirPrefix) { if !found { // Create destination directory lazily when source is found - createErr := os.Mkdir(path, 0755) - if createErr != nil { - return fmt.Errorf("could not create directory '%s': %w", color.CyanString(path), createErr) + if err := c.createDirectory(path); err != nil { + return fmt.Errorf("could not create directory: %w", err) } } found = true @@ -111,7 +129,7 @@ func (c *cloner) Clone(applicationName, path string) error { if !found { return errHint(fmt.Errorf("could not find source application '%s'", color.CyanString(applicationName)), "Use -f to ignore the cache") } else { - log.Print("Created ", color.CyanString(path)) + log.Print("Cloned into ", color.CyanString(path)) } return nil } diff --git a/client/go/internal/cli/cmd/clone_test.go b/client/go/internal/cli/cmd/clone_test.go index f136299db85..3d7250cc760 100644 --- a/client/go/internal/cli/cmd/clone_test.go +++ b/client/go/internal/cli/cmd/clone_test.go @@ -18,14 +18,16 @@ import ( ) func TestClone(t *testing.T) { - assertCreated("text-search", "mytestapp", t) -} - -func assertCreated(sampleAppName string, app string, t *testing.T) { + origWd, err := os.Getwd() + require.Nil(t, err) + sampleAppName := "text-search" + app := "mytestapp" tempDir := t.TempDir() app1 := filepath.Join(tempDir, "app1") - defer os.RemoveAll(app) - + t.Cleanup(func() { + os.Chdir(origWd) + os.RemoveAll(app) + }) httpClient := &mock.HTTPClient{} cli, stdout, stderr := newTestCLI(t) cli.httpClient = httpClient @@ -35,7 +37,7 @@ func assertCreated(sampleAppName string, app string, t *testing.T) { // Initial cloning. GitHub includes the ETag header, but we don't require it httpClient.NextResponseBytes(200, testdata) require.Nil(t, cli.Run("clone", sampleAppName, app1)) - assert.Equal(t, "Created "+app1+"\n", stdout.String()) + assert.Equal(t, "Cloned into "+app1+"\n", stdout.String()) assertFiles(t, app1) // Clone with cache hit @@ -43,8 +45,27 @@ func assertCreated(sampleAppName string, app string, t *testing.T) { stdout.Reset() app2 := filepath.Join(tempDir, "app2") require.Nil(t, cli.Run("clone", sampleAppName, app2)) - assert.Equal(t, "Using cached sample apps ...\nCreated "+app2+"\n", stdout.String()) + assert.Equal(t, "Using cached sample apps ...\nCloned into "+app2+"\n", stdout.String()) assertFiles(t, app2) + stdout.Reset() + + // Clone to current directory (dot) + emptyDir := filepath.Join(tempDir, "mypath1") + require.Nil(t, os.Mkdir(emptyDir, 0755)) + require.Nil(t, os.Chdir(emptyDir)) + httpClient.NextStatus(http.StatusNotModified) + require.Nil(t, cli.Run("clone", sampleAppName, ".")) + assert.Equal(t, "Using cached sample apps ...\nCloned into .\n", stdout.String()) + assertFiles(t, ".") + stdout.Reset() + + // Clone to non-empty directory + httpClient.NextStatus(http.StatusNotModified) + nonEmptyDir := filepath.Join(tempDir, "mypath2") + require.Nil(t, os.MkdirAll(filepath.Join(nonEmptyDir, "more"), 0755)) + require.NotNil(t, cli.Run("clone", sampleAppName, nonEmptyDir)) + assert.Equal(t, "Error: could not create directory: "+nonEmptyDir+" already exists and is not empty\n", stderr.String()) + stderr.Reset() // Clone while ignoring cache headers := make(http.Header) @@ -53,7 +74,7 @@ func assertCreated(sampleAppName string, app string, t *testing.T) { stdout.Reset() app3 := filepath.Join(tempDir, "app3") require.Nil(t, cli.Run("clone", "-f", sampleAppName, app3)) - assert.Equal(t, "Created "+app3+"\n", stdout.String()) + assert.Equal(t, "Cloned into "+app3+"\n", stdout.String()) assertFiles(t, app3) // Cloning falls back to cached copy if GitHub is unavailable @@ -62,7 +83,7 @@ func assertCreated(sampleAppName string, app string, t *testing.T) { app4 := filepath.Join(tempDir, "app4") require.Nil(t, cli.Run("clone", "-f=false", sampleAppName, app4)) assert.Equal(t, "Warning: could not download sample apps: github returned status 500\n", stderr.String()) - assert.Equal(t, "Using cached sample apps ...\nCreated "+app4+"\n", stdout.String()) + assert.Equal(t, "Using cached sample apps ...\nCloned into "+app4+"\n", stdout.String()) assertFiles(t, app4) // The only cached file is the latest one @@ -79,6 +100,7 @@ func assertCreated(sampleAppName string, app string, t *testing.T) { } func assertFiles(t *testing.T, app string) { + t.Helper() assert.True(t, util.PathExists(filepath.Join(app, "README.md"))) assert.True(t, util.PathExists(filepath.Join(app, "src", "main", "application"))) assert.True(t, util.IsDirectory(filepath.Join(app, "src", "main", "application"))) |