Files
holos/internal/util/util.go
Jeff McCune 85238710ac core: unify data files into config (#376)
Previously there isn't a good way to unify json and yaml files with the
cue configuration.  This is a problem for use cases where data can be
generated idempotentialy prior to rendering the platform configuration.

The first use case is to explore unifying configuration with decrypted
sops values, which isn't typical since Holos is designed to handle
secrets with ExternalSecret resources, but does fit into the use case of
executing a command to produce data idempotently, then make the data
available to the platform configuration.

Other use cases this feature is intended to support are the prior
experiment where we fetch top level platform configuration from an rpc
service, and the future goal of integrating with data provided by
Terraform.
2024-12-19 08:34:05 -08:00

72 lines
1.8 KiB
Go

package util
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/holos-run/holos/internal/errors"
)
// EnsureNewline adds a trailing newline if not already there.
func EnsureNewline(b []byte) []byte {
if len(b) > 0 && b[len(b)-1] != '\n' {
b = append(b, '\n')
}
return b
}
// FindCueMod returns the root module location containing the cue.mod.
func FindCueMod(path string) (root string, err error) {
origPath := path
if path, err = filepath.Abs(path); err != nil {
return "", errors.Wrap(err)
}
for {
if _, err := os.Stat(filepath.Join(path, "cue.mod")); err == nil {
if root != "" && root != path {
return "", fmt.Errorf("multiple modules not supported: %v is not %v", root, path)
}
root = path
break
} else if !os.IsNotExist(err) {
return "", errors.Wrap(err)
}
parent := filepath.Dir(path)
if parent == path {
return "", fmt.Errorf("no cue.mod from root to leaf: %v", origPath)
}
path = parent
}
return root, nil
}
// FindRootLeaf returns the root path containing the cue.mod and the leaf path
// relative to the root for the given target path. FindRootLeaf calls
// [filepath.Clean] on the returned paths.
func FindRootLeaf(target string) (root string, leaf string, err error) {
if root, err = FindCueMod(target); err != nil {
return "", "", err
}
absPath, err := filepath.Abs(target)
if err != nil {
return "", "", err
}
if leaf, err = filepath.Rel(root, absPath); err != nil {
return "", "", err
}
// Needed for CUE to load the path properly.
leaf = DotSlash(leaf)
return
}
// DotSlash ensures a relative path has a leading ./ needed for CUE loading.
func DotSlash(path string) string {
clean := filepath.Clean(path)
if filepath.IsAbs(clean) || strings.HasPrefix(clean, ".") || strings.HasPrefix(clean, string(filepath.Separator)) {
return clean
}
return "." + string(filepath.Separator) + clean
}