59 lines
1.4 KiB
Go
59 lines
1.4 KiB
Go
package artifacts
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// ResolveSessionLocalPathForRead resolves manifest/local artifact paths for read use-cases.
|
|
// Invariants for stage consumers:
|
|
// - local paths may be absolute, workspace-root qualified, or session-workdir relative.
|
|
// - callers should resolve through this helper instead of manually joining session/workdir roots.
|
|
func ResolveSessionLocalPathForRead(paths SessionPaths, localPath string) string {
|
|
p := filepath.Clean(strings.TrimSpace(localPath))
|
|
if p == "" {
|
|
return ""
|
|
}
|
|
if filepath.IsAbs(p) {
|
|
return p
|
|
}
|
|
|
|
// Already qualified against known roots.
|
|
if underRoot(p, paths.WorkspaceRoot) || underRoot(p, paths.Root) {
|
|
return p
|
|
}
|
|
|
|
candidates := []string{
|
|
p,
|
|
filepath.Clean(filepath.Join(paths.WorkspaceRoot, p)),
|
|
filepath.Clean(filepath.Join(paths.Root, p)),
|
|
}
|
|
for _, c := range candidates {
|
|
if c == "" {
|
|
continue
|
|
}
|
|
if _, err := os.Stat(c); err == nil {
|
|
return c
|
|
}
|
|
}
|
|
|
|
// Deterministic fallback for ambiguous relative values.
|
|
if strings.TrimSpace(paths.WorkspaceRoot) != "" {
|
|
return candidates[1]
|
|
}
|
|
return candidates[2]
|
|
}
|
|
|
|
func underRoot(path, root string) bool {
|
|
p := filepath.Clean(strings.TrimSpace(path))
|
|
r := filepath.Clean(strings.TrimSpace(root))
|
|
if p == "" || r == "" {
|
|
return false
|
|
}
|
|
if p == r {
|
|
return true
|
|
}
|
|
return strings.HasPrefix(p, r+string(filepath.Separator))
|
|
}
|