-
Notifications
You must be signed in to change notification settings - Fork 154
Add workspace import_dir command to the CLI #418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
9f4bf12
Add workspace import_dir command to the CLI
shreyas-goenka 1244b3a
Merge remote-tracking branch 'origin' into import_dir
shreyas-goenka 2303f20
sync options redefine better
shreyas-goenka 0382c74
-
shreyas-goenka 289dd0d
-
shreyas-goenka fb5ea16
helper wsfs function
shreyas-goenka 931fae1
add check for isdir in readdir
shreyas-goenka 57a9578
added some intgegration test for repofiles and moved to filer
shreyas-goenka dc0ff89
repofiles integration test
shreyas-goenka 2be6b85
wip import-dir acc tests
shreyas-goenka c1ccf82
testdata
shreyas-goenka efc72b5
-
shreyas-goenka 7099874
Merge remote-tracking branch 'origin' into import_dir
shreyas-goenka 0f1cb67
remove underscore
shreyas-goenka 49f7969
set template in annotation
shreyas-goenka 298fed2
undo remote path public
shreyas-goenka 6cc2571
address some comments
shreyas-goenka bb17546
-
shreyas-goenka ae09abf
-
shreyas-goenka 14b63d0
-
shreyas-goenka 5fdd8a2
-
shreyas-goenka 9629032
-
shreyas-goenka e9a309e
removes not a directory error
shreyas-goenka 74cb87f
-
shreyas-goenka 59081f7
Merge remote-tracking branch 'origin' into import_dir
shreyas-goenka 58acf64
some cleanup
shreyas-goenka f1e99d3
Merge remote-tracking branch 'origin' into import_dir
shreyas-goenka 764d9e9
Merge remote-tracking branch 'origin' into import_dir
shreyas-goenka 8166aed
revert changes to reposfile
shreyas-goenka f0f75ff
-
shreyas-goenka 43aadba
made events work and moved validation outside sync object
shreyas-goenka File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| package workspace | ||
|
|
||
| import ( | ||
| "github.com/databricks/cli/cmd/root" | ||
| "github.com/databricks/cli/libs/cmdio" | ||
| "github.com/databricks/cli/libs/sync" | ||
| "github.com/spf13/cobra" | ||
| "golang.org/x/sync/errgroup" | ||
| ) | ||
|
|
||
| // TODO: check whether we need mutex for any events been emitted since they are accessing | ||
| // state | ||
| // TODO: Error: path must be nested under /Users/shreyas.goenka@databricks.com or /Repos/shreyas.goenka@databricks.com. Should this validation be | ||
| // removed? Yes | ||
| var importDirCmd = &cobra.Command{ | ||
| Use: "import-dir SOURCE_PATH TARGET_PATH", | ||
| Short: `Import directory to a Databricks workspace.`, | ||
| Long: ` | ||
| Recursively imports a directory from the local filesystem to a Databricks workspace. | ||
|
|
||
| This command respects your git ignore configuration. Notebooks with extensions | ||
| .scala, .py, .sql, .r, .R, .ipynb are stripped of their extensions. | ||
| `, | ||
|
|
||
| PreRunE: root.MustWorkspaceClient, | ||
| Args: cobra.ExactArgs(2), | ||
| RunE: func(cmd *cobra.Command, args []string) (err error) { | ||
| ctx := cmd.Context() | ||
| sourcePath := args[0] | ||
| targetPath := args[1] | ||
|
|
||
| // Initialize syncer to do a full sync with the correct from source to target. | ||
| // This will upload the local files | ||
| opts := sync.SyncOptions{ | ||
| LocalPath: sourcePath, | ||
| RemotePath: targetPath, | ||
| Full: true, | ||
| WorkspaceClient: root.WorkspaceClient(ctx), | ||
|
|
||
| AllowOverwrites: importDirOverwrite, | ||
| PersistSnapshot: false, | ||
| } | ||
| s, err := sync.New(ctx, opts) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Initialize error wait group, and spawn the progress event emitter inside | ||
| // the error wait group | ||
| group, ctx := errgroup.WithContext(ctx) | ||
| eventsChannel := s.Events() | ||
| group.Go( | ||
| func() error { | ||
| return renderSyncEvents(ctx, eventsChannel, s) | ||
| }) | ||
|
|
||
| // Start Uploading local files | ||
| err = cmdio.RenderWithTemplate(ctx, newImportStartedEvent(sourcePath, targetPath), "Starting import {{.SourcePath}} -> {{.TargetPath}}\n") | ||
| if err != nil { | ||
| return err | ||
| } | ||
| err = s.RunOnce(ctx) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| // Upload completed, close the syncer | ||
| s.Close() | ||
|
|
||
| // Wait for any inflight progress events to be emitted | ||
| if err := group.Wait(); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Render import completetion event | ||
| return cmdio.RenderWithTemplate(ctx, newImportCompleteEvent(sourcePath, targetPath), "Completed import. Files available at {{.TargetPath}}\n") | ||
| }, | ||
| } | ||
|
|
||
| var importDirOverwrite bool | ||
|
|
||
| func init() { | ||
| importDirCmd.Flags().BoolVar(&importDirOverwrite, "overwrite", false, "Overwrite if file already exists in the workspace") | ||
| Cmd.AddCommand(importDirCmd) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| package workspace | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/databricks/cli/libs/cmdio" | ||
| "github.com/databricks/cli/libs/sync" | ||
| ) | ||
|
|
||
| // TODO: do not emit target directory in upload complete events. | ||
|
|
||
| type fileIOEvent struct { | ||
| SourcePath string `json:"source_path,omitempty"` | ||
| TargetPath string `json:"target_path,omitempty"` | ||
| Type string `json:"type"` | ||
| } | ||
|
|
||
| const ( | ||
| EventTypeImportStarted = "IMPORT_STARTED" | ||
| EventTypeImportComplete = "IMPORT_COMPLETE" | ||
| EventTypeUploadComplete = "UPLOAD_COMPLETE" | ||
| ) | ||
|
|
||
| func newImportStartedEvent(sourcePath, targetPath string) fileIOEvent { | ||
| return fileIOEvent{ | ||
| SourcePath: sourcePath, | ||
| TargetPath: targetPath, | ||
| Type: EventTypeImportStarted, | ||
| } | ||
| } | ||
|
|
||
| func newImportCompleteEvent(sourcePath, targetPath string) fileIOEvent { | ||
| return fileIOEvent{ | ||
| Type: EventTypeImportComplete, | ||
| TargetPath: targetPath, | ||
| } | ||
| } | ||
|
|
||
| func newUploadCompleteEvent(sourcePath string) fileIOEvent { | ||
| return fileIOEvent{ | ||
| SourcePath: sourcePath, | ||
| Type: EventTypeUploadComplete, | ||
| } | ||
| } | ||
|
|
||
| func renderSyncEvents(ctx context.Context, eventChannel <-chan sync.Event, syncer *sync.Sync) error { | ||
| for { | ||
| select { | ||
| case <-ctx.Done(): | ||
| return nil | ||
| case e, ok := <-eventChannel: | ||
| if !ok { | ||
| return nil | ||
| } | ||
| if e.String() == "" { | ||
| continue | ||
| } | ||
| switch v := e.(type) { | ||
| case *sync.EventSyncProgress: | ||
| // TODO: only emit this event if the the sync event has progress 1.o0 | ||
| // File upload has been completed. This renders the event for that | ||
| // on the console | ||
| err := cmdio.RenderWithTemplate(ctx, newUploadCompleteEvent(v.Path), "Uploaded {{.SourcePath}}\n") | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| hello, world |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| package internal | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "context" | ||
| "io" | ||
| "path" | ||
| "regexp" | ||
| "testing" | ||
|
|
||
| "github.com/databricks/cli/libs/filer" | ||
| "github.com/databricks/databricks-sdk-go" | ||
| "github.com/databricks/databricks-sdk-go/service/workspace" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestWorkspaceImportDir(t *testing.T) { | ||
| t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) | ||
|
|
||
| ctx := context.Background() | ||
| w := databricks.Must(databricks.NewWorkspaceClient()) | ||
| tmpdir := temporaryWorkspaceDir(t, w) | ||
|
|
||
| // run import-dir command | ||
| RequireSuccessfulRun(t, "workspace", "import-dir", "./testdata/import_dir/default", tmpdir) | ||
|
|
||
| // assert files are uploaded | ||
| f, err := filer.NewWorkspaceFilesClient(w, tmpdir) | ||
| require.NoError(t, err) | ||
| assertFileContains(t, ctx, f, "foo.txt", "hello, world") | ||
| assertFileContains(t, ctx, f, ".gitignore", ".databricks") | ||
| assertFileContains(t, ctx, f, "bar/apple.py", "print(1)") | ||
| assertNotebookExists(t, ctx, w, path.Join(tmpdir, "bar/mango")) | ||
| } | ||
|
|
||
| func TestWorkspaceImportDirOverwriteFlag(t *testing.T) { | ||
| // t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) | ||
|
|
||
| // ctx := context.Background() | ||
| w := databricks.Must(databricks.NewWorkspaceClient()) | ||
| tmpdir := temporaryWorkspaceDir(t, w) | ||
|
|
||
| // run import-dir command | ||
| RequireSuccessfulRun(t, "workspace", "import-dir", "./testdata/import_dir/override/a", tmpdir) | ||
|
|
||
| // // assert files are uploaded | ||
| // f, err := filer.NewWorkspaceFilesClient(w, tmpdir) | ||
| // require.NoError(t, err) | ||
| // assertFileContains(t, ctx, f, "bar.txt", "from directory A") | ||
|
|
||
| // Assert another run fails with path already exists error from the server | ||
| _, _, err := RequireErrorRun(t, "workspace", "import-dir", "./testdata/import_dir/override/b", tmpdir) | ||
| assert.Regexp(t, regexp.MustCompile("Path (.*) already exists."), err.Error()) | ||
|
|
||
| // // Succeeds with the overwrite flag | ||
| // RequireSuccessfulRun(t, "workspace", "import-dir", "./testdata/import_dir/override/b", tmpdir, "--overwrite") | ||
| // require.NoError(t, err) | ||
| // assertFileContains(t, ctx, f, "bar.txt", "from directory B") | ||
| } | ||
|
|
||
| func assertFileContains(t *testing.T, ctx context.Context, f filer.Filer, name, contents string) { | ||
| r, err := f.Read(ctx, name) | ||
| require.NoError(t, err) | ||
|
|
||
| var b bytes.Buffer | ||
| _, err = io.Copy(&b, r) | ||
| require.NoError(t, err) | ||
|
|
||
| assert.Contains(t, b.String(), contents) | ||
| } | ||
|
|
||
| func assertNotebookExists(t *testing.T, ctx context.Context, w *databricks.WorkspaceClient, path string) { | ||
| info, err := w.Workspace.ListAll(ctx, workspace.ListWorkspaceRequest{ | ||
| Path: path, | ||
| }) | ||
| require.NoError(t, err) | ||
| assert.Len(t, info, 1) | ||
| assert.Equal(t, info[0].ObjectType, workspace.ObjectTypeNotebook) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
|
|
||
| .databricks |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| print(1) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| hello, world |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| #Databricks notebook source | ||
| print(2) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
|
|
||
| .databricks |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| #Databricks notebook source | ||
| print("from dir A") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
|
|
||
| .databricks |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| #Databricks notebook source | ||
| print("from dir B") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the behavior of the returned context?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The returned context is cancelled if there's an error in any of the subroutines. see: https://pkg.go.dev/golang.org/x/sync/errgroup#WithContext