Pass along context during path translation

This commit is contained in:
Pieter Noordhuis 2025-01-13 09:10:41 +01:00
parent d525ff67be
commit ef2853e21d
No known key found for this signature in database
GPG Key ID: 12ACCCC104CF2930
5 changed files with 29 additions and 24 deletions

View File

@ -44,7 +44,7 @@ func (m *translatePaths) Name() string {
return "TranslatePaths" return "TranslatePaths"
} }
type rewriteFunc func(literal, localFullPath, localRelPath, remotePath string) (string, error) type rewriteFunc func(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error)
// translateContext is a context for rewriting paths in a config. // translateContext is a context for rewriting paths in a config.
// It is freshly instantiated on every mutator apply call. // It is freshly instantiated on every mutator apply call.
@ -68,6 +68,7 @@ type translateContext struct {
// //
// The function returns an error if it is impossible to rewrite the given relative path. // The function returns an error if it is impossible to rewrite the given relative path.
func (t *translateContext) rewritePath( func (t *translateContext) rewritePath(
ctx context.Context,
dir string, dir string,
p *string, p *string,
fn rewriteFunc, fn rewriteFunc,
@ -113,7 +114,7 @@ func (t *translateContext) rewritePath(
remotePath := path.Join(workspacePath, filepath.ToSlash(localRelPath)) remotePath := path.Join(workspacePath, filepath.ToSlash(localRelPath))
// Convert local path into workspace path via specified function. // Convert local path into workspace path via specified function.
interp, err := fn(*p, localPath, localRelPath, remotePath) interp, err := fn(ctx, *p, localPath, localRelPath, remotePath)
if err != nil { if err != nil {
return err return err
} }
@ -123,7 +124,7 @@ func (t *translateContext) rewritePath(
return nil return nil
} }
func (t *translateContext) translateNotebookPath(literal, localFullPath, localRelPath, remotePath string) (string, error) { func (t *translateContext) translateNotebookPath(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error) {
nb, _, err := notebook.DetectWithFS(t.b.SyncRoot, filepath.ToSlash(localRelPath)) nb, _, err := notebook.DetectWithFS(t.b.SyncRoot, filepath.ToSlash(localRelPath))
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, fs.ErrNotExist) {
if filepath.Ext(localFullPath) != notebook.ExtensionNone { if filepath.Ext(localFullPath) != notebook.ExtensionNone {
@ -165,7 +166,7 @@ to contain one of the following file extensions: [%s]`, literal, strings.Join(ex
return strings.TrimSuffix(remotePath, filepath.Ext(localFullPath)), nil return strings.TrimSuffix(remotePath, filepath.Ext(localFullPath)), nil
} }
func (t *translateContext) translateFilePath(literal, localFullPath, localRelPath, remotePath string) (string, error) { func (t *translateContext) translateFilePath(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error) {
nb, _, err := notebook.DetectWithFS(t.b.SyncRoot, filepath.ToSlash(localRelPath)) nb, _, err := notebook.DetectWithFS(t.b.SyncRoot, filepath.ToSlash(localRelPath))
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, fs.ErrNotExist) {
return "", fmt.Errorf("file %s not found", literal) return "", fmt.Errorf("file %s not found", literal)
@ -179,7 +180,7 @@ func (t *translateContext) translateFilePath(literal, localFullPath, localRelPat
return remotePath, nil return remotePath, nil
} }
func (t *translateContext) translateDirectoryPath(literal, localFullPath, localRelPath, remotePath string) (string, error) { func (t *translateContext) translateDirectoryPath(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error) {
info, err := t.b.SyncRoot.Stat(filepath.ToSlash(localRelPath)) info, err := t.b.SyncRoot.Stat(filepath.ToSlash(localRelPath))
if err != nil { if err != nil {
return "", err return "", err
@ -190,11 +191,11 @@ func (t *translateContext) translateDirectoryPath(literal, localFullPath, localR
return remotePath, nil return remotePath, nil
} }
func (t *translateContext) translateNoOp(literal, localFullPath, localRelPath, remotePath string) (string, error) { func (t *translateContext) translateNoOp(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error) {
return localRelPath, nil return localRelPath, nil
} }
func (t *translateContext) retainLocalAbsoluteFilePath(literal, localFullPath, localRelPath, remotePath string) (string, error) { func (t *translateContext) retainLocalAbsoluteFilePath(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error) {
info, err := t.b.SyncRoot.Stat(filepath.ToSlash(localRelPath)) info, err := t.b.SyncRoot.Stat(filepath.ToSlash(localRelPath))
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, fs.ErrNotExist) {
return "", fmt.Errorf("file %s not found", literal) return "", fmt.Errorf("file %s not found", literal)
@ -208,16 +209,16 @@ func (t *translateContext) retainLocalAbsoluteFilePath(literal, localFullPath, l
return localFullPath, nil return localFullPath, nil
} }
func (t *translateContext) translateNoOpWithPrefix(literal, localFullPath, localRelPath, remotePath string) (string, error) { func (t *translateContext) translateNoOpWithPrefix(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error) {
if !strings.HasPrefix(localRelPath, ".") { if !strings.HasPrefix(localRelPath, ".") {
localRelPath = "." + string(filepath.Separator) + localRelPath localRelPath = "." + string(filepath.Separator) + localRelPath
} }
return localRelPath, nil return localRelPath, nil
} }
func (t *translateContext) rewriteValue(p dyn.Path, v dyn.Value, fn rewriteFunc, dir string) (dyn.Value, error) { func (t *translateContext) rewriteValue(ctx context.Context, p dyn.Path, v dyn.Value, fn rewriteFunc, dir string) (dyn.Value, error) {
out := v.MustString() out := v.MustString()
err := t.rewritePath(dir, &out, fn) err := t.rewritePath(ctx, dir, &out, fn)
if err != nil { if err != nil {
if target := (&ErrIsNotebook{}); errors.As(err, target) { if target := (&ErrIsNotebook{}); errors.As(err, target) {
return dyn.InvalidValue, fmt.Errorf(`expected a file for "%s" but got a notebook: %w`, p, target) return dyn.InvalidValue, fmt.Errorf(`expected a file for "%s" but got a notebook: %w`, p, target)
@ -231,15 +232,15 @@ func (t *translateContext) rewriteValue(p dyn.Path, v dyn.Value, fn rewriteFunc,
return dyn.NewValue(out, v.Locations()), nil return dyn.NewValue(out, v.Locations()), nil
} }
func (t *translateContext) rewriteRelativeTo(p dyn.Path, v dyn.Value, fn rewriteFunc, dir, fallback string) (dyn.Value, error) { func (t *translateContext) rewriteRelativeTo(ctx context.Context, p dyn.Path, v dyn.Value, fn rewriteFunc, dir, fallback string) (dyn.Value, error) {
nv, err := t.rewriteValue(p, v, fn, dir) nv, err := t.rewriteValue(ctx, p, v, fn, dir)
if err == nil { if err == nil {
return nv, nil return nv, nil
} }
// If we failed to rewrite the path, try to rewrite it relative to the fallback directory. // If we failed to rewrite the path, try to rewrite it relative to the fallback directory.
if fallback != "" { if fallback != "" {
nv, nerr := t.rewriteValue(p, v, fn, fallback) nv, nerr := t.rewriteValue(ctx, p, v, fn, fallback)
if nerr == nil { if nerr == nil {
// TODO: Emit a warning that this path should be rewritten. // TODO: Emit a warning that this path should be rewritten.
return nv, nil return nv, nil
@ -249,7 +250,7 @@ func (t *translateContext) rewriteRelativeTo(p dyn.Path, v dyn.Value, fn rewrite
return dyn.InvalidValue, err return dyn.InvalidValue, err
} }
func (m *translatePaths) Apply(_ context.Context, b *bundle.Bundle) diag.Diagnostics { func (m *translatePaths) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
t := &translateContext{ t := &translateContext{
b: b, b: b,
seen: make(map[string]string), seen: make(map[string]string),
@ -257,13 +258,13 @@ func (m *translatePaths) Apply(_ context.Context, b *bundle.Bundle) diag.Diagnos
err := b.Config.Mutate(func(v dyn.Value) (dyn.Value, error) { err := b.Config.Mutate(func(v dyn.Value) (dyn.Value, error) {
var err error var err error
for _, fn := range []func(dyn.Value) (dyn.Value, error){ for _, fn := range []func(context.Context, dyn.Value) (dyn.Value, error){
t.applyJobTranslations, t.applyJobTranslations,
t.applyPipelineTranslations, t.applyPipelineTranslations,
t.applyArtifactTranslations, t.applyArtifactTranslations,
t.applyDashboardTranslations, t.applyDashboardTranslations,
} { } {
v, err = fn(v) v, err = fn(ctx, v)
if err != nil { if err != nil {
return dyn.InvalidValue, err return dyn.InvalidValue, err
} }

View File

@ -1,6 +1,7 @@
package mutator package mutator
import ( import (
"context"
"fmt" "fmt"
"github.com/databricks/cli/libs/dyn" "github.com/databricks/cli/libs/dyn"
@ -27,7 +28,7 @@ func (t *translateContext) artifactRewritePatterns() []artifactRewritePattern {
} }
} }
func (t *translateContext) applyArtifactTranslations(v dyn.Value) (dyn.Value, error) { func (t *translateContext) applyArtifactTranslations(ctx context.Context, v dyn.Value) (dyn.Value, error) {
var err error var err error
for _, rewritePattern := range t.artifactRewritePatterns() { for _, rewritePattern := range t.artifactRewritePatterns() {
@ -38,7 +39,7 @@ func (t *translateContext) applyArtifactTranslations(v dyn.Value) (dyn.Value, er
return dyn.InvalidValue, fmt.Errorf("unable to determine directory for artifact %s: %w", key, err) return dyn.InvalidValue, fmt.Errorf("unable to determine directory for artifact %s: %w", key, err)
} }
return t.rewriteRelativeTo(p, v, rewritePattern.fn, dir, "") return t.rewriteRelativeTo(ctx, p, v, rewritePattern.fn, dir, "")
}) })
if err != nil { if err != nil {
return dyn.InvalidValue, err return dyn.InvalidValue, err

View File

@ -1,12 +1,13 @@
package mutator package mutator
import ( import (
"context"
"fmt" "fmt"
"github.com/databricks/cli/libs/dyn" "github.com/databricks/cli/libs/dyn"
) )
func (t *translateContext) applyDashboardTranslations(v dyn.Value) (dyn.Value, error) { func (t *translateContext) applyDashboardTranslations(ctx context.Context, v dyn.Value) (dyn.Value, error) {
// Convert the `file_path` field to a local absolute path. // Convert the `file_path` field to a local absolute path.
// We load the file at this path and use its contents for the dashboard contents. // We load the file at this path and use its contents for the dashboard contents.
pattern := dyn.NewPattern( pattern := dyn.NewPattern(
@ -23,6 +24,6 @@ func (t *translateContext) applyDashboardTranslations(v dyn.Value) (dyn.Value, e
return dyn.InvalidValue, fmt.Errorf("unable to determine directory for dashboard %s: %w", key, err) return dyn.InvalidValue, fmt.Errorf("unable to determine directory for dashboard %s: %w", key, err)
} }
return t.rewriteRelativeTo(p, v, t.retainLocalAbsoluteFilePath, dir, "") return t.rewriteRelativeTo(ctx, p, v, t.retainLocalAbsoluteFilePath, dir, "")
}) })
} }

View File

@ -1,6 +1,7 @@
package mutator package mutator
import ( import (
"context"
"fmt" "fmt"
"slices" "slices"
@ -9,7 +10,7 @@ import (
"github.com/databricks/cli/libs/dyn" "github.com/databricks/cli/libs/dyn"
) )
func (t *translateContext) applyJobTranslations(v dyn.Value) (dyn.Value, error) { func (t *translateContext) applyJobTranslations(ctx context.Context, v dyn.Value) (dyn.Value, error) {
var err error var err error
fallback, err := gatherFallbackPaths(v, "jobs") fallback, err := gatherFallbackPaths(v, "jobs")
@ -43,7 +44,7 @@ func (t *translateContext) applyJobTranslations(v dyn.Value) (dyn.Value, error)
return dyn.InvalidValue, err return dyn.InvalidValue, err
} }
return t.rewriteRelativeTo(p, v, rewritePatternFn, dir, fallback[key]) return t.rewriteRelativeTo(ctx, p, v, rewritePatternFn, dir, fallback[key])
}) })
} }

View File

@ -1,6 +1,7 @@
package mutator package mutator
import ( import (
"context"
"fmt" "fmt"
"github.com/databricks/cli/libs/dyn" "github.com/databricks/cli/libs/dyn"
@ -34,7 +35,7 @@ func (t *translateContext) pipelineRewritePatterns() []pipelineRewritePattern {
} }
} }
func (t *translateContext) applyPipelineTranslations(v dyn.Value) (dyn.Value, error) { func (t *translateContext) applyPipelineTranslations(ctx context.Context, v dyn.Value) (dyn.Value, error) {
var err error var err error
fallback, err := gatherFallbackPaths(v, "pipelines") fallback, err := gatherFallbackPaths(v, "pipelines")
@ -50,7 +51,7 @@ func (t *translateContext) applyPipelineTranslations(v dyn.Value) (dyn.Value, er
return dyn.InvalidValue, fmt.Errorf("unable to determine directory for pipeline %s: %w", key, err) return dyn.InvalidValue, fmt.Errorf("unable to determine directory for pipeline %s: %w", key, err)
} }
return t.rewriteRelativeTo(p, v, rewritePattern.fn, dir, fallback[key]) return t.rewriteRelativeTo(ctx, p, v, rewritePattern.fn, dir, fallback[key])
}) })
if err != nil { if err != nil {
return dyn.InvalidValue, err return dyn.InvalidValue, err