diff --git a/bundle/config/mutator/translate_paths.go b/bundle/config/mutator/translate_paths.go index 096d9292d..abac65bf4 100644 --- a/bundle/config/mutator/translate_paths.go +++ b/bundle/config/mutator/translate_paths.go @@ -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) diff --git a/bundle/config/mutator/translate_paths_artifacts.go b/bundle/config/mutator/translate_paths_artifacts.go index f09d153d6..80190b8cb 100644 --- a/bundle/config/mutator/translate_paths_artifacts.go +++ b/bundle/config/mutator/translate_paths_artifacts.go @@ -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 diff --git a/bundle/config/mutator/translate_paths_dashboards.go b/bundle/config/mutator/translate_paths_dashboards.go index 65f10dc31..0dfcfd37e 100644 --- a/bundle/config/mutator/translate_paths_dashboards.go +++ b/bundle/config/mutator/translate_paths_dashboards.go @@ -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) }) } diff --git a/bundle/config/mutator/translate_paths_jobs.go b/bundle/config/mutator/translate_paths_jobs.go index 4da81b032..59b5c009b 100644 --- a/bundle/config/mutator/translate_paths_jobs.go +++ b/bundle/config/mutator/translate_paths_jobs.go @@ -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) } diff --git a/bundle/config/mutator/translate_paths_pipelines.go b/bundle/config/mutator/translate_paths_pipelines.go index 2ed42d445..204808ff5 100644 --- a/bundle/config/mutator/translate_paths_pipelines.go +++ b/bundle/config/mutator/translate_paths_pipelines.go @@ -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