From 9fab5ebbfe8fb6c23d5c0c1eb9a68c2e9e5c38c2 Mon Sep 17 00:00:00 2001 From: Mike McRill Date: Sat, 23 Sep 2023 22:13:49 -0500 Subject: [PATCH 1/2] Change FindDependencies to optionally follow symlinks --- cmd/jsonnet-deps/cmd.go | 2 +- vm.go | 35 +++++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/cmd/jsonnet-deps/cmd.go b/cmd/jsonnet-deps/cmd.go index 24421327f..85d3ed0cc 100644 --- a/cmd/jsonnet-deps/cmd.go +++ b/cmd/jsonnet-deps/cmd.go @@ -193,7 +193,7 @@ func main() { } } - dependencies, err := vm.FindDependencies("", conf.inputFiles) + dependencies, err := vm.FindDependencies("", conf.inputFiles, true) if err != nil { fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) diff --git a/vm.go b/vm.go index f9402ba29..e7873c06a 100644 --- a/vm.go +++ b/vm.go @@ -237,8 +237,11 @@ func (vm *VM) evaluateSnippet(diagnosticFileName ast.DiagnosticFileName, filenam return output, nil } -func getAbsPath(path string) (string, error) { +func getAbsPath(path string, followSymlinks bool) (string, error) { var absPath string + + var err error + if filepath.IsAbs(path) { absPath = path } else { @@ -248,14 +251,18 @@ func getAbsPath(path string) (string, error) { } absPath = strings.Join([]string{wd, path}, string(filepath.Separator)) } - cleanedAbsPath, err := filepath.EvalSymlinks(absPath) - if err != nil { - return "", err + + if followSymlinks { + absPath, err = filepath.EvalSymlinks(absPath) + if err != nil { + return "", err + } } - return cleanedAbsPath, nil + + return absPath, nil } -func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map[string]struct{}, stackTrace *[]TraceFrame) (err error) { +func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map[string]struct{}, stackTrace *[]TraceFrame, followSymlinks bool) (err error) { var cleanedAbsPath string switch i := (*node).(type) { case *ast.Import: @@ -266,7 +273,7 @@ func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map } cleanedAbsPath = foundAt if _, isFileImporter := vm.importer.(*FileImporter); isFileImporter { - cleanedAbsPath, err = getAbsPath(foundAt) + cleanedAbsPath, err = getAbsPath(foundAt, followSymlinks) if err != nil { *stackTrace = append([]TraceFrame{{Loc: *i.Loc()}}, *stackTrace...) return err @@ -277,7 +284,7 @@ func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map return nil } dependencies[cleanedAbsPath] = struct{}{} - err = vm.findDependencies(foundAt, &node, dependencies, stackTrace) + err = vm.findDependencies(foundAt, &node, dependencies, stackTrace, followSymlinks) if err != nil { *stackTrace = append([]TraceFrame{{Loc: *i.Loc()}}, *stackTrace...) return err @@ -290,7 +297,7 @@ func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map } cleanedAbsPath = foundAt if _, isFileImporter := vm.importer.(*FileImporter); isFileImporter { - cleanedAbsPath, err = getAbsPath(foundAt) + cleanedAbsPath, err = getAbsPath(foundAt, followSymlinks) if err != nil { *stackTrace = append([]TraceFrame{{Loc: *i.Loc()}}, *stackTrace...) return err @@ -305,7 +312,7 @@ func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map } cleanedAbsPath = foundAt if _, isFileImporter := vm.importer.(*FileImporter); isFileImporter { - cleanedAbsPath, err = getAbsPath(foundAt) + cleanedAbsPath, err = getAbsPath(foundAt, followSymlinks) if err != nil { *stackTrace = append([]TraceFrame{{Loc: *i.Loc()}}, *stackTrace...) return err @@ -314,7 +321,7 @@ func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map dependencies[cleanedAbsPath] = struct{}{} default: for _, node := range parser.Children(i) { - err = vm.findDependencies(filePath, &node, dependencies, stackTrace) + err = vm.findDependencies(filePath, &node, dependencies, stackTrace, followSymlinks) if err != nil { return err } @@ -458,7 +465,7 @@ func (vm *VM) EvaluateFileMulti(filename string) (files map[string]string, forma // FindDependencies returns a sorted array of unique transitive dependencies (via import/importstr/importbin) // from all the given `importedPaths` which are themselves excluded from the returned array. // The `importedPaths` are parsed as if they were imported from a Jsonnet file located at `importedFrom`. -func (vm *VM) FindDependencies(importedFrom string, importedPaths []string) ([]string, error) { +func (vm *VM) FindDependencies(importedFrom string, importedPaths []string, followSymlinks bool) ([]string, error) { var nodes []*ast.Node var stackTrace []TraceFrame filePaths := make([]string, len(importedPaths)) @@ -472,7 +479,7 @@ func (vm *VM) FindDependencies(importedFrom string, importedPaths []string) ([]s } cleanedAbsPath := foundAt if _, isFileImporter := vm.importer.(*FileImporter); isFileImporter { - cleanedAbsPath, err = getAbsPath(foundAt) + cleanedAbsPath, err = getAbsPath(foundAt, followSymlinks) if err != nil { return nil, err } @@ -487,7 +494,7 @@ func (vm *VM) FindDependencies(importedFrom string, importedPaths []string) ([]s } for i, filePath := range filePaths { - err := vm.findDependencies(filePath, nodes[i], deps, &stackTrace) + err := vm.findDependencies(filePath, nodes[i], deps, &stackTrace, followSymlinks) if err != nil { err = makeRuntimeError(err.Error(), stackTrace) return nil, errors.New(vm.ErrorFormatter.Format(err)) From 264982b4cda2b363d60fbc56c2a00d08abc525f9 Mon Sep 17 00:00:00 2001 From: Mike McRill Date: Mon, 2 Feb 2026 12:03:26 -0600 Subject: [PATCH 2/2] Change FindDependencies to use functional options --- cmd/jsonnet-deps/cmd.go | 2 +- vm.go | 40 +++++++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/cmd/jsonnet-deps/cmd.go b/cmd/jsonnet-deps/cmd.go index 85d3ed0cc..24421327f 100644 --- a/cmd/jsonnet-deps/cmd.go +++ b/cmd/jsonnet-deps/cmd.go @@ -193,7 +193,7 @@ func main() { } } - dependencies, err := vm.FindDependencies("", conf.inputFiles, true) + dependencies, err := vm.FindDependencies("", conf.inputFiles) if err != nil { fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) diff --git a/vm.go b/vm.go index e7873c06a..08013d2c7 100644 --- a/vm.go +++ b/vm.go @@ -237,7 +237,7 @@ func (vm *VM) evaluateSnippet(diagnosticFileName ast.DiagnosticFileName, filenam return output, nil } -func getAbsPath(path string, followSymlinks bool) (string, error) { +func getAbsPath(path string, canonicalPaths bool) (string, error) { var absPath string var err error @@ -252,7 +252,7 @@ func getAbsPath(path string, followSymlinks bool) (string, error) { absPath = strings.Join([]string{wd, path}, string(filepath.Separator)) } - if followSymlinks { + if canonicalPaths { absPath, err = filepath.EvalSymlinks(absPath) if err != nil { return "", err @@ -262,7 +262,7 @@ func getAbsPath(path string, followSymlinks bool) (string, error) { return absPath, nil } -func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map[string]struct{}, stackTrace *[]TraceFrame, followSymlinks bool) (err error) { +func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map[string]struct{}, stackTrace *[]TraceFrame, canonicalPaths bool) (err error) { var cleanedAbsPath string switch i := (*node).(type) { case *ast.Import: @@ -273,7 +273,7 @@ func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map } cleanedAbsPath = foundAt if _, isFileImporter := vm.importer.(*FileImporter); isFileImporter { - cleanedAbsPath, err = getAbsPath(foundAt, followSymlinks) + cleanedAbsPath, err = getAbsPath(foundAt, canonicalPaths) if err != nil { *stackTrace = append([]TraceFrame{{Loc: *i.Loc()}}, *stackTrace...) return err @@ -284,7 +284,7 @@ func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map return nil } dependencies[cleanedAbsPath] = struct{}{} - err = vm.findDependencies(foundAt, &node, dependencies, stackTrace, followSymlinks) + err = vm.findDependencies(foundAt, &node, dependencies, stackTrace, canonicalPaths) if err != nil { *stackTrace = append([]TraceFrame{{Loc: *i.Loc()}}, *stackTrace...) return err @@ -297,7 +297,7 @@ func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map } cleanedAbsPath = foundAt if _, isFileImporter := vm.importer.(*FileImporter); isFileImporter { - cleanedAbsPath, err = getAbsPath(foundAt, followSymlinks) + cleanedAbsPath, err = getAbsPath(foundAt, canonicalPaths) if err != nil { *stackTrace = append([]TraceFrame{{Loc: *i.Loc()}}, *stackTrace...) return err @@ -312,7 +312,7 @@ func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map } cleanedAbsPath = foundAt if _, isFileImporter := vm.importer.(*FileImporter); isFileImporter { - cleanedAbsPath, err = getAbsPath(foundAt, followSymlinks) + cleanedAbsPath, err = getAbsPath(foundAt, canonicalPaths) if err != nil { *stackTrace = append([]TraceFrame{{Loc: *i.Loc()}}, *stackTrace...) return err @@ -321,7 +321,7 @@ func (vm *VM) findDependencies(filePath string, node *ast.Node, dependencies map dependencies[cleanedAbsPath] = struct{}{} default: for _, node := range parser.Children(i) { - err = vm.findDependencies(filePath, &node, dependencies, stackTrace, followSymlinks) + err = vm.findDependencies(filePath, &node, dependencies, stackTrace, canonicalPaths) if err != nil { return err } @@ -462,10 +462,28 @@ func (vm *VM) EvaluateFileMulti(filename string) (files map[string]string, forma return output, nil } +type findDepsConfig struct { + canonicalPaths bool +} + +type FindDepsOption func(c *findDepsConfig) + +func WithCanonicalPaths(canonicalize bool) FindDepsOption { + return func(c *findDepsConfig) { c.canonicalPaths = canonicalize } +} + // FindDependencies returns a sorted array of unique transitive dependencies (via import/importstr/importbin) // from all the given `importedPaths` which are themselves excluded from the returned array. // The `importedPaths` are parsed as if they were imported from a Jsonnet file located at `importedFrom`. -func (vm *VM) FindDependencies(importedFrom string, importedPaths []string, followSymlinks bool) ([]string, error) { +func (vm *VM) FindDependencies(importedFrom string, importedPaths []string, opts ...FindDepsOption) ([]string, error) { + config := findDepsConfig{ + canonicalPaths: true, + } + + for _, f := range opts { + f(&config) + } + var nodes []*ast.Node var stackTrace []TraceFrame filePaths := make([]string, len(importedPaths)) @@ -479,7 +497,7 @@ func (vm *VM) FindDependencies(importedFrom string, importedPaths []string, foll } cleanedAbsPath := foundAt if _, isFileImporter := vm.importer.(*FileImporter); isFileImporter { - cleanedAbsPath, err = getAbsPath(foundAt, followSymlinks) + cleanedAbsPath, err = getAbsPath(foundAt, config.canonicalPaths) if err != nil { return nil, err } @@ -494,7 +512,7 @@ func (vm *VM) FindDependencies(importedFrom string, importedPaths []string, foll } for i, filePath := range filePaths { - err := vm.findDependencies(filePath, nodes[i], deps, &stackTrace, followSymlinks) + err := vm.findDependencies(filePath, nodes[i], deps, &stackTrace, config.canonicalPaths) if err != nil { err = makeRuntimeError(err.Error(), stackTrace) return nil, errors.New(vm.ErrorFormatter.Format(err))