mirror of https://github.com/databricks/cli.git
Add read-only mode for extension aware workspace filer (#1609)
## Changes By default, construct a read/write instance. If constructed in read-only mode, the underlying filer is wrapped in a readahead cache. ## Tests * Filer integration tests pass. * Manual test that caching is enabled when running on WSFS.
This commit is contained in:
parent
5b65358146
commit
6953a5d5af
|
@ -39,7 +39,7 @@ func (m *configureWSFS) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagno
|
||||||
// If so, swap out vfs.Path instance of the sync root with one that
|
// If so, swap out vfs.Path instance of the sync root with one that
|
||||||
// makes all Workspace File System interactions extension aware.
|
// makes all Workspace File System interactions extension aware.
|
||||||
p, err := vfs.NewFilerPath(ctx, root, func(path string) (filer.Filer, error) {
|
p, err := vfs.NewFilerPath(ctx, root, func(path string) (filer.Filer, error) {
|
||||||
return filer.NewWorkspaceFilesExtensionsClient(b.WorkspaceClient(), path)
|
return filer.NewReadOnlyWorkspaceFilesExtensionsClient(b.WorkspaceClient(), path)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return diag.FromErr(err)
|
return diag.FromErr(err)
|
||||||
|
|
|
@ -18,8 +18,9 @@ import (
|
||||||
type workspaceFilesExtensionsClient struct {
|
type workspaceFilesExtensionsClient struct {
|
||||||
workspaceClient *databricks.WorkspaceClient
|
workspaceClient *databricks.WorkspaceClient
|
||||||
|
|
||||||
wsfs Filer
|
wsfs Filer
|
||||||
root string
|
root string
|
||||||
|
readonly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionsToLanguages = map[string]workspace.Language{
|
var extensionsToLanguages = map[string]workspace.Language{
|
||||||
|
@ -143,6 +144,14 @@ func (e DuplicatePathError) Error() string {
|
||||||
return fmt.Sprintf("failed to read files from the workspace file system. Duplicate paths encountered. Both %s at %s and %s at %s resolve to the same name %s. Changing the name of one of these objects will resolve this issue", e.oi1.ObjectType, e.oi1.Path, e.oi2.ObjectType, e.oi2.Path, e.commonName)
|
return fmt.Sprintf("failed to read files from the workspace file system. Duplicate paths encountered. Both %s at %s and %s at %s resolve to the same name %s. Changing the name of one of these objects will resolve this issue", e.oi1.ObjectType, e.oi1.Path, e.oi2.ObjectType, e.oi2.Path, e.commonName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReadOnlyError struct {
|
||||||
|
op string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ReadOnlyError) Error() string {
|
||||||
|
return fmt.Sprintf("failed to %s: filer is in read-only mode", e.op)
|
||||||
|
}
|
||||||
|
|
||||||
// This is a filer for the workspace file system that allows you to pretend the
|
// This is a filer for the workspace file system that allows you to pretend the
|
||||||
// workspace file system is a traditional file system. It allows you to list, read, write,
|
// workspace file system is a traditional file system. It allows you to list, read, write,
|
||||||
// delete, and stat notebooks (and files in general) in the workspace, using their paths
|
// delete, and stat notebooks (and files in general) in the workspace, using their paths
|
||||||
|
@ -157,17 +166,30 @@ func (e DuplicatePathError) Error() string {
|
||||||
// errors for namespace clashes (e.g. a file and a notebook or a directory and a notebook).
|
// errors for namespace clashes (e.g. a file and a notebook or a directory and a notebook).
|
||||||
// Thus users of these methods should be careful to avoid such clashes.
|
// Thus users of these methods should be careful to avoid such clashes.
|
||||||
func NewWorkspaceFilesExtensionsClient(w *databricks.WorkspaceClient, root string) (Filer, error) {
|
func NewWorkspaceFilesExtensionsClient(w *databricks.WorkspaceClient, root string) (Filer, error) {
|
||||||
|
return newWorkspaceFilesExtensionsClient(w, root, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReadOnlyWorkspaceFilesExtensionsClient(w *databricks.WorkspaceClient, root string) (Filer, error) {
|
||||||
|
return newWorkspaceFilesExtensionsClient(w, root, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWorkspaceFilesExtensionsClient(w *databricks.WorkspaceClient, root string, readonly bool) (Filer, error) {
|
||||||
filer, err := NewWorkspaceFilesClient(w, root)
|
filer, err := NewWorkspaceFilesClient(w, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache := newWorkspaceFilesReadaheadCache(filer)
|
if readonly {
|
||||||
|
// Wrap in a readahead cache to avoid making unnecessary calls to the workspace.
|
||||||
|
filer = newWorkspaceFilesReadaheadCache(filer)
|
||||||
|
}
|
||||||
|
|
||||||
return &workspaceFilesExtensionsClient{
|
return &workspaceFilesExtensionsClient{
|
||||||
workspaceClient: w,
|
workspaceClient: w,
|
||||||
|
|
||||||
wsfs: cache,
|
wsfs: filer,
|
||||||
root: root,
|
root: root,
|
||||||
|
readonly: readonly,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,6 +236,10 @@ func (w *workspaceFilesExtensionsClient) ReadDir(ctx context.Context, name strin
|
||||||
// (e.g. a file and a notebook or a directory and a notebook). Thus users of this
|
// (e.g. a file and a notebook or a directory and a notebook). Thus users of this
|
||||||
// method should be careful to avoid such clashes.
|
// method should be careful to avoid such clashes.
|
||||||
func (w *workspaceFilesExtensionsClient) Write(ctx context.Context, name string, reader io.Reader, mode ...WriteMode) error {
|
func (w *workspaceFilesExtensionsClient) Write(ctx context.Context, name string, reader io.Reader, mode ...WriteMode) error {
|
||||||
|
if w.readonly {
|
||||||
|
return ReadOnlyError{"write"}
|
||||||
|
}
|
||||||
|
|
||||||
return w.wsfs.Write(ctx, name, reader, mode...)
|
return w.wsfs.Write(ctx, name, reader, mode...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,6 +273,10 @@ func (w *workspaceFilesExtensionsClient) Read(ctx context.Context, name string)
|
||||||
|
|
||||||
// Try to delete the file as a regular file. If the file is not found, try to delete it as a notebook.
|
// Try to delete the file as a regular file. If the file is not found, try to delete it as a notebook.
|
||||||
func (w *workspaceFilesExtensionsClient) Delete(ctx context.Context, name string, mode ...DeleteMode) error {
|
func (w *workspaceFilesExtensionsClient) Delete(ctx context.Context, name string, mode ...DeleteMode) error {
|
||||||
|
if w.readonly {
|
||||||
|
return ReadOnlyError{"delete"}
|
||||||
|
}
|
||||||
|
|
||||||
err := w.wsfs.Delete(ctx, name, mode...)
|
err := w.wsfs.Delete(ctx, name, mode...)
|
||||||
|
|
||||||
// If the file is not found, it might be a notebook.
|
// If the file is not found, it might be a notebook.
|
||||||
|
@ -293,5 +323,9 @@ func (w *workspaceFilesExtensionsClient) Stat(ctx context.Context, name string)
|
||||||
// (e.g. a file and a notebook or a directory and a notebook). Thus users of this
|
// (e.g. a file and a notebook or a directory and a notebook). Thus users of this
|
||||||
// method should be careful to avoid such clashes.
|
// method should be careful to avoid such clashes.
|
||||||
func (w *workspaceFilesExtensionsClient) Mkdir(ctx context.Context, name string) error {
|
func (w *workspaceFilesExtensionsClient) Mkdir(ctx context.Context, name string) error {
|
||||||
|
if w.readonly {
|
||||||
|
return ReadOnlyError{"mkdir"}
|
||||||
|
}
|
||||||
|
|
||||||
return w.wsfs.Mkdir(ctx, name)
|
return w.wsfs.Mkdir(ctx, name)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue