Define translation mode and options

This commit is contained in:
Pieter Noordhuis 2025-01-13 10:33:38 +01:00
parent aa9226446b
commit 9c8c85ddc1
No known key found for this signature in database
GPG Key ID: 12ACCCC104CF2930
5 changed files with 81 additions and 31 deletions

View File

@ -17,6 +17,34 @@ import (
"github.com/databricks/cli/libs/notebook"
)
// TranslateMode specifies how a path should be translated.
type TranslateMode int
const (
// TranslateModeNotebook translates a path to a remote notebook.
TranslateModeNotebook TranslateMode = iota
// TranslateModeFile translates a path to a remote regular file.
TranslateModeFile
// TranslateModeDirectory translates a path to a remote directory.
TranslateModeDirectory
// TranslateModeRetainLocalAbsoluteFilePath translates a path to the local absolute file path.
TranslateModeRetainLocalAbsoluteFilePath
// TranslateModeNoOp does not translate the path.
TranslateModeNoOp
// TranslateModeNoOpWithPrefix does not translate the path, but adds a prefix to it.
TranslateModeNoOpWithPrefix
)
// translateOptions specifies how a path should be translated.
type translateOptions struct {
Mode TranslateMode
}
type ErrIsNotebook struct {
path string
}
@ -44,8 +72,6 @@ func (m *translatePaths) Name() string {
return "TranslatePaths"
}
type rewriteFunc func(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error)
// translateContext is a context for rewriting paths in a config.
// It is freshly instantiated on every mutator apply call.
// It provides access to the underlying bundle object such that
@ -64,8 +90,8 @@ type translateContext struct {
// - The context in which the function is called.
// - The argument `dir` is the directory relative to which the relative path should be interpreted.
// - The argument `input` is the relative path to rewrite.
// - The argument `fn` is a function that performs the actual rewriting logic.
// This logic is different between regular files or notebooks.
// - The argument `opts` is a struct that specifies how the path should be rewritten.
// It contains a `Mode` field that specifies how the path should be rewritten.
//
// The function returns the rewritten path if successful, or an error if the path could not be rewritten.
// The returned path is an empty string if the path was not rewritten.
@ -73,7 +99,7 @@ func (t *translateContext) rewritePath(
ctx context.Context,
dir string,
input string,
fn rewriteFunc,
opts translateOptions,
) (string, error) {
// We assume absolute paths point to a location in the workspace
if path.IsAbs(input) {
@ -115,7 +141,23 @@ func (t *translateContext) rewritePath(
remotePath := path.Join(workspacePath, filepath.ToSlash(localRelPath))
// Convert local path into workspace path via specified function.
interp, err := fn(ctx, input, localPath, localRelPath, remotePath)
var interp string
switch opts.Mode {
case TranslateModeNotebook:
interp, err = t.translateNotebookPath(ctx, input, localPath, localRelPath, remotePath)
case TranslateModeFile:
interp, err = t.translateFilePath(ctx, input, localPath, localRelPath, remotePath)
case TranslateModeDirectory:
interp, err = t.translateDirectoryPath(ctx, input, localPath, localRelPath, remotePath)
case TranslateModeRetainLocalAbsoluteFilePath:
interp, err = t.retainLocalAbsoluteFilePath(ctx, input, localPath, localRelPath, remotePath)
case TranslateModeNoOp:
interp, err = t.translateNoOp(ctx, input, localPath, localRelPath, remotePath)
case TranslateModeNoOpWithPrefix:
interp, err = t.translateNoOpWithPrefix(ctx, input, localPath, localRelPath, remotePath)
default:
return "", fmt.Errorf("unsupported translate mode: %d", opts.Mode)
}
if err != nil {
return "", err
}
@ -191,10 +233,6 @@ func (t *translateContext) translateDirectoryPath(ctx context.Context, literal,
return remotePath, nil
}
func (t *translateContext) translateNoOp(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error) {
return localRelPath, nil
}
func (t *translateContext) retainLocalAbsoluteFilePath(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error) {
info, err := t.b.SyncRoot.Stat(filepath.ToSlash(localRelPath))
if errors.Is(err, fs.ErrNotExist) {
@ -209,6 +247,10 @@ func (t *translateContext) retainLocalAbsoluteFilePath(ctx context.Context, lite
return localFullPath, nil
}
func (t *translateContext) translateNoOp(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error) {
return localRelPath, nil
}
func (t *translateContext) translateNoOpWithPrefix(ctx context.Context, literal, localFullPath, localRelPath, remotePath string) (string, error) {
if !strings.HasPrefix(localRelPath, ".") {
localRelPath = "." + string(filepath.Separator) + localRelPath
@ -216,8 +258,8 @@ func (t *translateContext) translateNoOpWithPrefix(ctx context.Context, literal,
return localRelPath, nil
}
func (t *translateContext) rewriteValue(ctx context.Context, p dyn.Path, v dyn.Value, fn rewriteFunc, dir string) (dyn.Value, error) {
out, err := t.rewritePath(ctx, dir, v.MustString(), fn)
func (t *translateContext) rewriteValue(ctx context.Context, p dyn.Path, v dyn.Value, dir string, opts translateOptions) (dyn.Value, error) {
out, err := t.rewritePath(ctx, dir, v.MustString(), opts)
if err != nil {
if target := (&ErrIsNotebook{}); errors.As(err, target) {
return dyn.InvalidValue, fmt.Errorf(`expected a file for "%s" but got a notebook: %w`, p, target)

View File

@ -9,7 +9,7 @@ import (
type artifactRewritePattern struct {
pattern dyn.Pattern
fn rewriteFunc
opts translateOptions
}
func (t *translateContext) artifactRewritePatterns() []artifactRewritePattern {
@ -23,7 +23,7 @@ func (t *translateContext) artifactRewritePatterns() []artifactRewritePattern {
return []artifactRewritePattern{
{
base.Append(dyn.Key("path")),
t.translateNoOp,
translateOptions{Mode: TranslateModeNoOp},
},
}
}
@ -39,7 +39,7 @@ func (t *translateContext) applyArtifactTranslations(ctx context.Context, v dyn.
return dyn.InvalidValue, fmt.Errorf("unable to determine directory for artifact %s: %w", key, err)
}
return t.rewriteValue(ctx, p, v, rewritePattern.fn, dir)
return t.rewriteValue(ctx, p, v, dir, rewritePattern.opts)
})
if err != nil {
return dyn.InvalidValue, err

View File

@ -17,6 +17,10 @@ func (t *translateContext) applyDashboardTranslations(ctx context.Context, v dyn
dyn.Key("file_path"),
)
opts := translateOptions{
Mode: TranslateModeRetainLocalAbsoluteFilePath,
}
return dyn.MapByPattern(v, pattern, func(p dyn.Path, v dyn.Value) (dyn.Value, error) {
key := p[2].Key()
dir, err := v.Location().Directory()
@ -24,6 +28,6 @@ func (t *translateContext) applyDashboardTranslations(ctx context.Context, v dyn
return dyn.InvalidValue, fmt.Errorf("unable to determine directory for dashboard %s: %w", key, err)
}
return t.rewriteValue(ctx, p, v, t.retainLocalAbsoluteFilePath, dir)
return t.rewriteValue(ctx, p, v, dir, opts)
})
}

View File

@ -39,13 +39,17 @@ func (t *translateContext) applyJobTranslations(ctx context.Context, v dyn.Value
return dyn.InvalidValue, fmt.Errorf("unable to determine directory for job %s: %w", key, err)
}
rewritePatternFn, err := t.getRewritePatternFn(kind)
mode, err := getJobTranslateMode(kind)
if err != nil {
return dyn.InvalidValue, err
}
opts := translateOptions{
Mode: mode,
}
// Try to rewrite the path relative to the directory of the configuration file where the value was defined.
nv, err := t.rewriteValue(ctx, p, v, rewritePatternFn, dir)
nv, err := t.rewriteValue(ctx, p, v, dir, opts)
if err == nil {
return nv, nil
}
@ -53,7 +57,7 @@ func (t *translateContext) applyJobTranslations(ctx context.Context, v dyn.Value
// If we failed to rewrite the path, try to rewrite it relative to the fallback directory.
// We only do this for jobs and pipelines because of the comment in [gatherFallbackPaths].
if fallback[key] != "" {
nv, nerr := t.rewriteValue(ctx, p, v, rewritePatternFn, fallback[key])
nv, nerr := t.rewriteValue(ctx, p, v, fallback[key], opts)
if nerr == nil {
// TODO: Emit a warning that this path should be rewritten.
return nv, nil
@ -64,19 +68,19 @@ func (t *translateContext) applyJobTranslations(ctx context.Context, v dyn.Value
})
}
func (t *translateContext) getRewritePatternFn(kind paths.PathKind) (rewriteFunc, error) {
func getJobTranslateMode(kind paths.PathKind) (TranslateMode, error) {
switch kind {
case paths.PathKindLibrary:
return t.translateNoOp, nil
return TranslateModeNoOp, nil
case paths.PathKindNotebook:
return t.translateNotebookPath, nil
return TranslateModeNotebook, nil
case paths.PathKindWorkspaceFile:
return t.translateFilePath, nil
return TranslateModeFile, nil
case paths.PathKindDirectory:
return t.translateDirectoryPath, nil
return TranslateModeDirectory, nil
case paths.PathKindWithPrefix:
return t.translateNoOpWithPrefix, nil
return TranslateModeNoOpWithPrefix, nil
}
return nil, fmt.Errorf("unsupported path kind: %d", kind)
return TranslateMode(0), fmt.Errorf("unsupported path kind: %d", kind)
}

View File

@ -9,7 +9,7 @@ import (
type pipelineRewritePattern struct {
pattern dyn.Pattern
fn rewriteFunc
opts translateOptions
}
func (t *translateContext) pipelineRewritePatterns() []pipelineRewritePattern {
@ -26,11 +26,11 @@ func (t *translateContext) pipelineRewritePatterns() []pipelineRewritePattern {
return []pipelineRewritePattern{
{
base.Append(dyn.Key("notebook"), dyn.Key("path")),
t.translateNotebookPath,
translateOptions{Mode: TranslateModeNotebook},
},
{
base.Append(dyn.Key("file"), dyn.Key("path")),
t.translateFilePath,
translateOptions{Mode: TranslateModeFile},
},
}
}
@ -52,7 +52,7 @@ func (t *translateContext) applyPipelineTranslations(ctx context.Context, v dyn.
}
// Try to rewrite the path relative to the directory of the configuration file where the value was defined.
nv, err := t.rewriteValue(ctx, p, v, rewritePattern.fn, dir)
nv, err := t.rewriteValue(ctx, p, v, dir, rewritePattern.opts)
if err == nil {
return nv, nil
}
@ -60,7 +60,7 @@ func (t *translateContext) applyPipelineTranslations(ctx context.Context, v dyn.
// If we failed to rewrite the path, try to rewrite it relative to the fallback directory.
// We only do this for jobs and pipelines because of the comment in [gatherFallbackPaths].
if fallback[key] != "" {
nv, nerr := t.rewriteValue(ctx, p, v, rewritePattern.fn, fallback[key])
nv, nerr := t.rewriteValue(ctx, p, v, fallback[key], rewritePattern.opts)
if nerr == nil {
// TODO: Emit a warning that this path should be rewritten.
return nv, nil