Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions cmd/fs/rm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package fs

import (
"github.com/databricks/cli/cmd/root"
"github.com/databricks/databricks-sdk-go/service/files"
"github.com/spf13/cobra"
)

var rmCmd = &cobra.Command{
Use: "rm PATH",
Short: "Remove files and directories from dbfs.",
Long: `Remove files and directories from dbfs.`,
Args: cobra.ExactArgs(1),
PreRunE: root.MustWorkspaceClient,

RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
w := root.WorkspaceClient(ctx)

path, err := resolveDbfsPath(args[0])
if err != nil {
return err
}

return w.Dbfs.Delete(ctx, files.Delete{
Path: path,
Recursive: recursive,
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prompted me to do #442 so we can use the filer here as well for symmetry.

Can be a follow up to this PR.

},
}

var recursive bool

func init() {
rmCmd.Flags().BoolVarP(&recursive, "recursive", "r", false, "Recursively delete a non-empty directory.")
fsCmd.AddCommand(rmCmd)
}
146 changes: 146 additions & 0 deletions internal/rm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package internal

import (
"context"
"io/fs"
"path"
"strings"
"testing"

"github.com/databricks/cli/libs/filer"
"github.com/databricks/databricks-sdk-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestFsRmForFile(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))

ctx := context.Background()
w, err := databricks.NewWorkspaceClient()
require.NoError(t, err)

tmpDir := temporaryDbfsDir(t, w)

f, err := filer.NewDbfsClient(w, tmpDir)
require.NoError(t, err)

// create file to delete
err = f.Write(ctx, "hello.txt", strings.NewReader("abc"))
require.NoError(t, err)

// check file was created
info, err := f.Stat(ctx, "hello.txt")
require.NoError(t, err)
require.Equal(t, "hello.txt", info.Name())
require.Equal(t, info.IsDir(), false)

// Run rm command
stdout, stderr := RequireSuccessfulRun(t, "fs", "rm", "dbfs:"+path.Join(tmpDir, "hello.txt"))
assert.Equal(t, "", stderr.String())
assert.Equal(t, "", stdout.String())

// assert file was deleted
_, err = f.Stat(ctx, "hello.txt")
assert.ErrorIs(t, err, fs.ErrNotExist)
}

func TestFsRmForEmptyDirectory(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))

ctx := context.Background()
w, err := databricks.NewWorkspaceClient()
require.NoError(t, err)

tmpDir := temporaryDbfsDir(t, w)

f, err := filer.NewDbfsClient(w, tmpDir)
require.NoError(t, err)

// create directory to delete
err = f.Mkdir(ctx, "avacado")
require.NoError(t, err)

// check directory was created
info, err := f.Stat(ctx, "avacado")
require.NoError(t, err)
require.Equal(t, "avacado", info.Name())
require.Equal(t, info.IsDir(), true)

// Run rm command
stdout, stderr := RequireSuccessfulRun(t, "fs", "rm", "dbfs:"+path.Join(tmpDir, "avacado"))
assert.Equal(t, "", stderr.String())
assert.Equal(t, "", stdout.String())

// assert directory was deleted
_, err = f.Stat(ctx, "avacado")
assert.ErrorIs(t, err, fs.ErrNotExist)
}

func TestFsRmForNonEmptyDirectory(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))

ctx := context.Background()
w, err := databricks.NewWorkspaceClient()
require.NoError(t, err)

tmpDir := temporaryDbfsDir(t, w)

f, err := filer.NewDbfsClient(w, tmpDir)
require.NoError(t, err)

// create file in dir
err = f.Write(ctx, "avacado/guacamole", strings.NewReader("abc"), filer.CreateParentDirectories)
require.NoError(t, err)

// check file was created
info, err := f.Stat(ctx, "avacado/guacamole")
require.NoError(t, err)
require.Equal(t, "guacamole", info.Name())
require.Equal(t, info.IsDir(), false)

// Run rm command
_, _, err = RequireErrorRun(t, "fs", "rm", "dbfs:"+path.Join(tmpDir, "avacado"))
assert.ErrorContains(t, err, "Non-recursive delete of non-empty directory")
}

func TestFsRmForNonExistentFile(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))

// No error is returned on command run
stdout, stderr := RequireSuccessfulRun(t, "fs", "rm", "dbfs:/does-not-exist")
assert.Equal(t, "", stderr.String())
assert.Equal(t, "", stdout.String())
}

func TestFsRmForNonEmptyDirectoryWithRecursiveFlag(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))

ctx := context.Background()
w, err := databricks.NewWorkspaceClient()
require.NoError(t, err)

tmpDir := temporaryDbfsDir(t, w)

f, err := filer.NewDbfsClient(w, tmpDir)
require.NoError(t, err)

// create file in dir
err = f.Write(ctx, "avacado/guacamole", strings.NewReader("abc"), filer.CreateParentDirectories)
require.NoError(t, err)

// check file was created
info, err := f.Stat(ctx, "avacado/guacamole")
require.NoError(t, err)
require.Equal(t, "guacamole", info.Name())
require.Equal(t, info.IsDir(), false)

// Run rm command
stdout, stderr := RequireSuccessfulRun(t, "fs", "rm", "dbfs:"+path.Join(tmpDir, "avacado"), "--recursive")
assert.Equal(t, "", stderr.String())
assert.Equal(t, "", stdout.String())

// assert directory was deleted
_, err = f.Stat(ctx, "avacado")
assert.ErrorIs(t, err, fs.ErrNotExist)
}