databricks-cli/bundle/config/mutator/populate_locations.go

74 lines
2.0 KiB
Go

package mutator
import (
"context"
"path/filepath"
"github.com/databricks/cli/bundle"
"github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn"
)
type populateLocations struct{}
// PopulateLocations collects location information for the entire configuration tree
// and includes this as the [config.Root.Locations] property.
func PopulateLocations() bundle.Mutator {
return &populateLocations{}
}
func (m *populateLocations) Name() string {
return "PopulateLocations"
}
func computeRelativeLocations(base string, v dyn.Value) []dyn.Location {
// Skip values that don't have locations.
// Examples include defaults or values that are set by the program itself.
locs := v.Locations()
if len(locs) == 0 {
return nil
}
// Convert absolute paths to relative paths.
for i := range locs {
rel, err := filepath.Rel(base, locs[i].File)
if err != nil {
return nil
}
// Convert the path separator to forward slashes.
// This makes it possible to compare output across platforms.
locs[i].File = filepath.ToSlash(rel)
}
return locs
}
func (m *populateLocations) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
loc := make(map[string][]dyn.Location)
_, err := dyn.Walk(b.Config.Value(), func(p dyn.Path, v dyn.Value) (dyn.Value, error) {
// Skip the root value.
if len(p) == 0 {
return v, nil
}
// Skip values that don't have locations.
// Examples include defaults or values that are set by the program itself.
locs := computeRelativeLocations(b.BundleRootPath, v)
if len(locs) > 0 {
// Semantics for a value having multiple locations can be found in [merge.Merge].
// We don't need to externalize these at the moment, so we limit the number
// of locations to 1 while still using a slice for the output. This allows us
// to include multiple entries in the future if we need to.
loc[p.String()] = locs[0:1]
}
return v, nil
})
if err != nil {
return diag.FromErr(err)
}
b.Config.Locations = loc
return nil
}