From 349e2aff40110353a7a6af70a57b76fb75799df0 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Wed, 31 May 2023 18:47:00 +0000 Subject: [PATCH] Allow equivalence checking of filer errors to fs errors (#416) ## Changes The pattern `errors.Is(err, fs.ErrNotExist)` is common to check for an error type. Errors can implement `Is(error) bool` with a custom equivalence checker. ## Tests New asserts all pass in the integration test. --- bundle/deploy/terraform/state_pull.go | 5 +++-- internal/filer_test.go | 5 +++++ libs/filer/filer.go | 12 ++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/bundle/deploy/terraform/state_pull.go b/bundle/deploy/terraform/state_pull.go index cfdeef80..e5a42d89 100644 --- a/bundle/deploy/terraform/state_pull.go +++ b/bundle/deploy/terraform/state_pull.go @@ -2,14 +2,15 @@ package terraform import ( "context" + "errors" "io" + "io/fs" "os" "path/filepath" "github.com/databricks/cli/bundle" "github.com/databricks/cli/libs/filer" "github.com/databricks/cli/libs/log" - "github.com/databricks/databricks-sdk-go/apierr" ) type statePull struct{} @@ -34,7 +35,7 @@ func (l *statePull) Apply(ctx context.Context, b *bundle.Bundle) error { remote, err := f.Read(ctx, TerraformStateFileName) if err != nil { // On first deploy this state file doesn't yet exist. - if apierr.IsMissing(err) { + if errors.Is(err, fs.ErrNotExist) { log.Infof(ctx, "Remote state file does not exist") return nil } diff --git a/internal/filer_test.go b/internal/filer_test.go index 29d08b3e..b8fd6365 100644 --- a/internal/filer_test.go +++ b/internal/filer_test.go @@ -46,10 +46,12 @@ func runFilerReadWriteTest(t *testing.T, ctx context.Context, f filer.Filer) { // Write should fail because the root path doesn't yet exist. err = f.Write(ctx, "/foo/bar", strings.NewReader(`hello world`)) assert.True(t, errors.As(err, &filer.NoSuchDirectoryError{})) + assert.True(t, errors.Is(err, fs.ErrNotExist)) // Read should fail because the root path doesn't yet exist. _, err = f.Read(ctx, "/foo/bar") assert.True(t, errors.As(err, &filer.FileDoesNotExistError{})) + assert.True(t, errors.Is(err, fs.ErrNotExist)) // Write with CreateParentDirectories flag should succeed. err = f.Write(ctx, "/foo/bar", strings.NewReader(`hello world`), filer.CreateParentDirectories) @@ -59,6 +61,7 @@ func runFilerReadWriteTest(t *testing.T, ctx context.Context, f filer.Filer) { // Write should fail because there is an existing file at the specified path. err = f.Write(ctx, "/foo/bar", strings.NewReader(`hello universe`)) assert.True(t, errors.As(err, &filer.FileAlreadyExistsError{})) + assert.True(t, errors.Is(err, fs.ErrExist)) // Write with OverwriteIfExists should succeed. err = f.Write(ctx, "/foo/bar", strings.NewReader(`hello universe`), filer.OverwriteIfExists) @@ -68,6 +71,7 @@ func runFilerReadWriteTest(t *testing.T, ctx context.Context, f filer.Filer) { // Delete should fail if the file doesn't exist. err = f.Delete(ctx, "/doesnt_exist") assert.True(t, errors.As(err, &filer.FileDoesNotExistError{})) + assert.True(t, errors.Is(err, fs.ErrNotExist)) // Delete should succeed for file that does exist. err = f.Delete(ctx, "/foo/bar") @@ -102,6 +106,7 @@ func runFilerReadDirTest(t *testing.T, ctx context.Context, f filer.Filer) { // Expect an error if the path doesn't exist. _, err = f.ReadDir(ctx, "/dir/a/b/c/d/e") assert.True(t, errors.As(err, &filer.NoSuchDirectoryError{}), err) + assert.True(t, errors.Is(err, fs.ErrNotExist)) // Expect two entries in the root. entries, err = f.ReadDir(ctx, ".") diff --git a/libs/filer/filer.go b/libs/filer/filer.go index 61412b97..e54efb96 100644 --- a/libs/filer/filer.go +++ b/libs/filer/filer.go @@ -22,10 +22,18 @@ func (err FileAlreadyExistsError) Error() string { return fmt.Sprintf("file already exists: %s", err.path) } +func (err FileAlreadyExistsError) Is(other error) bool { + return other == fs.ErrExist +} + type FileDoesNotExistError struct { path string } +func (err FileDoesNotExistError) Is(other error) bool { + return other == fs.ErrNotExist +} + func (err FileDoesNotExistError) Error() string { return fmt.Sprintf("file does not exist: %s", err.path) } @@ -38,6 +46,10 @@ func (err NoSuchDirectoryError) Error() string { return fmt.Sprintf("no such directory: %s", err.path) } +func (err NoSuchDirectoryError) Is(other error) bool { + return other == fs.ErrNotExist +} + // Filer is used to access files in a workspace. // It has implementations for accessing files in WSFS and in DBFS. type Filer interface {