124 lines
3.6 KiB
Go
124 lines
3.6 KiB
Go
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 := source.path
|
|
if baseSource != nil {
|
|
filePath = baseSource.Path
|
|
} else {
|
|
canonical, err := canonicalExistingPath(filePath)
|
|
if err != nil {
|
|
value := importDiagnostic(CodeImportInvalid, "selected source could not be canonicalized", nil)
|
|
return nil, &value
|
|
}
|
|
filePath = canonical
|
|
}
|
|
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
|
|
}
|
|
if source.kind == sourceNone && context.BaseDir == "" {
|
|
basePath = rootPath
|
|
} else {
|
|
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
|
|
}
|
|
}
|