Provide passive per-source resource contexts
This commit is contained in:
112
internal/engine/source_context.go
Normal file
112
internal/engine/source_context.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func contextsForAcquiredSources(source Source, context *FilesystemContext, baseSource *SourceInfo, sources []SourceInfo) (map[string]ResourceContext, *Diagnostic) {
|
||||
if len(sources) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
var rootPath, basePath string
|
||||
var filesystem fs.FS
|
||||
if source.kind == sourceFilesystem {
|
||||
filesystem = source.namespace.filesystem
|
||||
rootPath, basePath = ".", path.Dir(source.path)
|
||||
if context != nil && context.Root != "" {
|
||||
rootPath = context.Root
|
||||
}
|
||||
} else if context != nil && context.FS != nil {
|
||||
filesystem = context.FS.namespace.filesystem
|
||||
rootPath, basePath = context.Root, context.BaseDir
|
||||
} else if source.kind == sourceFile {
|
||||
filePath := sources[0].Path
|
||||
if baseSource != nil {
|
||||
filePath = baseSource.Path
|
||||
}
|
||||
basePath = filepath.Dir(filePath)
|
||||
rootPath = basePath
|
||||
if context != nil && context.Root != "" {
|
||||
canonical, err := canonicalExistingPath(context.Root)
|
||||
if err != nil {
|
||||
value := importDiagnostic(CodeImportInvalid, "configuration root could not be canonicalized", nil)
|
||||
return nil, &value
|
||||
}
|
||||
rootPath = canonical
|
||||
}
|
||||
} else if context != nil {
|
||||
var err error
|
||||
rootPath, err = canonicalExistingPath(context.Root)
|
||||
if err != nil {
|
||||
value := importDiagnostic(CodeImportInvalid, "configuration root could not be canonicalized", nil)
|
||||
return nil, &value
|
||||
}
|
||||
basePath, err = canonicalExistingPath(context.BaseDir)
|
||||
if err != nil {
|
||||
value := importDiagnostic(CodeImportInvalid, "import base directory could not be canonicalized", nil)
|
||||
return nil, &value
|
||||
}
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
var rooted fs.FS
|
||||
if filesystem != nil {
|
||||
rooted = rootedNativeFS{filesystem: filesystem, root: rootPath}
|
||||
} else {
|
||||
rooted = rootedHostFS{root: rootPath}
|
||||
}
|
||||
result := make(map[string]ResourceContext, len(sources))
|
||||
for _, acquired := range sources {
|
||||
base := basePath
|
||||
if acquired.Path != "" {
|
||||
if filesystem != nil {
|
||||
base = path.Dir(acquired.Path)
|
||||
} else {
|
||||
base = filepath.Dir(acquired.Path)
|
||||
}
|
||||
}
|
||||
var relative string
|
||||
if filesystem != nil {
|
||||
if !fs.ValidPath(rootPath) || !fs.ValidPath(base) || rootPath != "." && base != rootPath && !strings.HasPrefix(base, rootPath+"/") {
|
||||
value := importDiagnostic(CodeImportOutsideRoot, "source base is outside the configuration root", nil)
|
||||
return nil, &value
|
||||
}
|
||||
relative = base
|
||||
if rootPath != "." {
|
||||
relative = strings.TrimPrefix(strings.TrimPrefix(base, rootPath), "/")
|
||||
if relative == "" {
|
||||
relative = "."
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !containedPath(rootPath, base) {
|
||||
value := importDiagnostic(CodeImportOutsideRoot, "source base is outside the configuration root", nil)
|
||||
return nil, &value
|
||||
}
|
||||
var err error
|
||||
relative, err = filepath.Rel(rootPath, base)
|
||||
if err != nil {
|
||||
value := importDiagnostic(CodeImportInvalid, "source base could not be addressed in the configuration root", nil)
|
||||
return nil, &value
|
||||
}
|
||||
relative = filepath.ToSlash(relative)
|
||||
}
|
||||
result[acquired.ID] = ResourceContext{FS: rooted, BaseDir: relative}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func mergeResourceContexts(target *map[string]ResourceContext, incoming map[string]ResourceContext) {
|
||||
if len(incoming) == 0 {
|
||||
return
|
||||
}
|
||||
if *target == nil {
|
||||
*target = make(map[string]ResourceContext, len(incoming))
|
||||
}
|
||||
for id, context := range incoming {
|
||||
(*target)[id] = context
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user