Files
BrowserOS/packages/browseros/tools/patch/internal/workspace/detect.go
2026-05-04 18:03:36 -07:00

91 lines
2.3 KiB
Go

package workspace
import (
"fmt"
"path/filepath"
"slices"
"strings"
)
func Detect(reg *Registry, cwd string) (Entry, error) {
if len(reg.Workspaces) == 0 {
return Entry{}, fmt.Errorf("no workspaces registered yet")
}
abs, err := filepath.Abs(cwd)
if err != nil {
return Entry{}, err
}
clean := filepath.Clean(abs)
realClean := canonicalPath(clean)
var best Entry
bestLen := -1
for _, ws := range reg.Workspaces {
base := filepath.Clean(ws.Path)
realBase := canonicalPath(base)
if containsPath(clean, base) || containsPath(realClean, realBase) {
if len(realBase) > bestLen {
best = ws
bestLen = len(realBase)
}
}
}
if bestLen == -1 {
return Entry{}, detectError(clean, realClean, reg.Workspaces)
}
return best, nil
}
func Resolve(reg *Registry, name string, cwd string, src string) (Entry, error) {
if src != "" {
path, err := NormalizeWorkspacePath(src)
if err != nil {
return Entry{}, err
}
return Entry{Name: filepath.Base(path), Path: path}, nil
}
if name != "" {
return reg.Get(name)
}
return Detect(reg, cwd)
}
func canonicalPath(path string) string {
realPath, err := filepath.EvalSymlinks(path)
if err != nil {
return filepath.Clean(path)
}
return filepath.Clean(realPath)
}
func containsPath(path string, base string) bool {
return path == base || strings.HasPrefix(path, base+string(filepath.Separator))
}
func detectError(cwd string, resolvedCWD string, workspaces []Entry) error {
var builder strings.Builder
builder.WriteString(`not inside a registered workspace; run "browseros-patch list" to inspect workspaces or pass one by name`)
builder.WriteString("\n")
builder.WriteString("cwd: ")
builder.WriteString(cwd)
if resolvedCWD != cwd {
builder.WriteString("\nresolved cwd: ")
builder.WriteString(resolvedCWD)
}
if len(workspaces) > 0 {
builder.WriteString("\nregistered workspaces:")
sorted := append([]Entry(nil), workspaces...)
slices.SortFunc(sorted, func(a, b Entry) int {
return strings.Compare(a.Name, b.Name)
})
for _, ws := range sorted {
builder.WriteString("\n ")
builder.WriteString(ws.Name)
builder.WriteString(" ")
builder.WriteString(ws.Path)
}
builder.WriteString("\nexample: browseros-patch diff ")
builder.WriteString(sorted[0].Name)
}
return fmt.Errorf("%s", builder.String())
}