Resolve ConfigKit paths from declaration origins
This commit is contained in:
165
internal/core/config/document_paths.go
Normal file
165
internal/core/config/document_paths.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||
)
|
||||
|
||||
func normalizeDocumentPaths(document *Document, resolution *configkit.Resolution, state *documentLoadState) {
|
||||
if document == nil {
|
||||
return
|
||||
}
|
||||
initializeDocumentMainDirectory(resolution, state)
|
||||
if document.PromptKit != nil {
|
||||
normalizeDocumentPath(resolution, state, configkit.Keys("promptkit", "profile_dir"), &document.PromptKit.ProfileDir, false, "resolved PromptKit profile directory")
|
||||
normalizeDocumentPath(resolution, state, configkit.Keys("promptkit", "profile_file"), &document.PromptKit.ProfileFile, false, "resolved PromptKit profile file")
|
||||
}
|
||||
if document.Output != nil {
|
||||
normalizeDocumentPath(resolution, state, configkit.Keys("output", "directory"), &document.Output.Directory, false, "resolved output directory")
|
||||
}
|
||||
if document.Cache != nil {
|
||||
if document.Cache.ChunkPlans != nil {
|
||||
normalizeDocumentPath(resolution, state, configkit.Keys("cache", "chunk_plans", "directory"), &document.Cache.ChunkPlans.Directory, true, "resolved chunk-plan cache directory")
|
||||
}
|
||||
if document.Cache.Checkpoints != nil {
|
||||
normalizeDocumentPath(resolution, state, configkit.Keys("cache", "checkpoints", "directory"), &document.Cache.Checkpoints.Directory, true, "resolved checkpoint cache directory")
|
||||
}
|
||||
}
|
||||
if document.Debug != nil {
|
||||
normalizeDocumentPath(resolution, state, configkit.Keys("debug", "directory"), &document.Debug.Directory, false, "resolved debug directory")
|
||||
}
|
||||
for _, id := range sortedPipelineDocumentKeys(document.Pipelines) {
|
||||
profile := document.Pipelines[id]
|
||||
path := configkit.Keys("pipelines").Key(id)
|
||||
normalizeDocumentReferencePaths(profile.References, path.Key("references"), resolution, state)
|
||||
normalizeDocumentBindingReferencePaths(&profile.Input, path.Key("input"), resolution, state)
|
||||
if profile.Chunk != nil {
|
||||
normalizeDocumentBindingReferencePaths(profile.Chunk, path.Key("chunk"), resolution, state)
|
||||
}
|
||||
if profile.Output != nil {
|
||||
normalizeDocumentBindingReferencePaths(profile.Output, path.Key("output"), resolution, state)
|
||||
}
|
||||
for laneID, lane := range profile.Artifacts {
|
||||
normalizeDocumentLaneReferencePaths(&lane, path.Key("artifacts").Key(laneID), resolution, state)
|
||||
profile.Artifacts[laneID] = lane
|
||||
}
|
||||
for index := range profile.Steps {
|
||||
step := &profile.Steps[index]
|
||||
stepPath := path.Key("steps").Index(index)
|
||||
normalizeDocumentReferencePaths(step.References, stepPath.Key("references"), resolution, state)
|
||||
for laneID, lane := range step.Artifacts {
|
||||
normalizeDocumentLaneReferencePaths(&lane, stepPath.Key("artifacts").Key(laneID), resolution, state)
|
||||
step.Artifacts[laneID] = lane
|
||||
}
|
||||
}
|
||||
document.Pipelines[id] = profile
|
||||
}
|
||||
}
|
||||
|
||||
func initializeDocumentMainDirectory(resolution *configkit.Resolution, state *documentLoadState) {
|
||||
if state == nil || state.mainDirectory != "" {
|
||||
return
|
||||
}
|
||||
info, ok := resolution.InputInfo(configkit.Keys("version"))
|
||||
if ok && len(info.Origin.Locations) == 1 {
|
||||
if source, sourceOK := resolution.Source(info.Origin.Locations[0].SourceID); sourceOK && source.Path != "" {
|
||||
state.mainDirectory = filepath.Dir(source.Path)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Byte and reader sources are test-oriented private entry points. They have
|
||||
// no declaring file, so preserve their established invocation-directory
|
||||
// semantics without extending that fallback to file-backed production loads.
|
||||
state.mainDirectory = cleanInvocationDirectory(".")
|
||||
}
|
||||
|
||||
func normalizeDocumentBindingReferencePaths(binding *BindingDocument, path configkit.Path, resolution *configkit.Resolution, state *documentLoadState) {
|
||||
if binding != nil {
|
||||
normalizeDocumentReferencePaths(binding.References, path.Key("references"), resolution, state)
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeDocumentLaneReferencePaths(lane *ArtifactLaneDocument, path configkit.Path, resolution *configkit.Resolution, state *documentLoadState) {
|
||||
if lane == nil {
|
||||
return
|
||||
}
|
||||
normalizeDocumentBindingReferencePaths(&lane.Extract, path.Key("extract"), resolution, state)
|
||||
normalizeDocumentBindingReferencePaths(lane.Merge, path.Key("merge"), resolution, state)
|
||||
normalizeDocumentBindingReferencePaths(lane.Normalize, path.Key("normalize"), resolution, state)
|
||||
}
|
||||
|
||||
func normalizeDocumentReferencePaths(references map[string]ReferenceDocument, path configkit.Path, resolution *configkit.Resolution, state *documentLoadState) {
|
||||
for _, name := range sortedReferenceDocumentKeys(references) {
|
||||
source := references[name]
|
||||
sourcePath := path.Key(name).Key("path")
|
||||
if source.Path != nil && *source.Path != "" && !filepath.IsAbs(*source.Path) {
|
||||
base, ok := documentPathBase(resolution, state, sourcePath)
|
||||
if !ok {
|
||||
resolution.Error(sourcePath, "relative path has no unambiguous source base")
|
||||
} else {
|
||||
value := filepath.Clean(filepath.Join(base, *source.Path))
|
||||
if value != *source.Path {
|
||||
resolution.Record(sourcePath, configkit.ChangeNormalization, "resolved external reference path")
|
||||
source.Path = documentValue(value)
|
||||
}
|
||||
}
|
||||
references[name] = source
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeDocumentPath(resolution *configkit.Resolution, state *documentLoadState, path configkit.Path, target **string, optional bool, reason string) {
|
||||
if target == nil || *target == nil || **target == "" || filepath.IsAbs(**target) {
|
||||
return
|
||||
}
|
||||
base, ok := documentPathBase(resolution, state, path)
|
||||
if !ok {
|
||||
resolution.Error(path, "relative path has no unambiguous source base")
|
||||
return
|
||||
}
|
||||
value := filepath.Clean(filepath.Join(base, **target))
|
||||
if optional && **target == "" {
|
||||
return
|
||||
}
|
||||
if *target != nil && **target != value {
|
||||
configkit.Normalize(resolution, path, target, documentValue(value), reason)
|
||||
}
|
||||
}
|
||||
|
||||
func documentPathBase(resolution *configkit.Resolution, state *documentLoadState, path configkit.Path) (string, bool) {
|
||||
original := path
|
||||
if state != nil {
|
||||
original = state.originalPath(path)
|
||||
}
|
||||
info, ok := resolution.InputInfo(original)
|
||||
if !ok {
|
||||
if state != nil && state.mainDirectory != "" {
|
||||
return state.mainDirectory, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
switch info.Origin.Layer {
|
||||
case configkit.LayerCLI:
|
||||
if state != nil && state.invocationDirectory != "" {
|
||||
return state.invocationDirectory, true
|
||||
}
|
||||
case configkit.LayerDefault:
|
||||
if state != nil && state.mainDirectory != "" {
|
||||
return state.mainDirectory, true
|
||||
}
|
||||
default:
|
||||
if len(info.Origin.Locations) != 1 {
|
||||
return "", false
|
||||
}
|
||||
source, ok := resolution.Source(info.Origin.Locations[0].SourceID)
|
||||
if !ok || source.Path == "" {
|
||||
if state != nil && state.mainDirectory != "" {
|
||||
return state.mainDirectory, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
return filepath.Dir(source.Path), true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
Reference in New Issue
Block a user