mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-14 16:14:28 +00:00
Compare commits
1 Commits
fix/browse
...
fix/patch-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e83d3a670 |
@@ -1,8 +1,12 @@
|
||||
BINARY := browseros-patch
|
||||
PREFIX ?= /usr/local/bin
|
||||
GOBIN := $(shell go env GOBIN)
|
||||
ifeq ($(GOBIN),)
|
||||
GOBIN := $(shell go env GOPATH)/bin
|
||||
endif
|
||||
PREFIX ?= $(GOBIN)
|
||||
VERSION ?= dev
|
||||
|
||||
.PHONY: build install clean test fmt
|
||||
.PHONY: build install uninstall clean test fmt
|
||||
|
||||
build:
|
||||
go build -ldflags "-X github.com/browseros-ai/BrowserOS/packages/browseros/tools/patch/cmd.Version=$(VERSION)" -o $(BINARY) .
|
||||
@@ -17,6 +21,10 @@ else
|
||||
endif
|
||||
@echo "Installed $(BINARY) to $(PREFIX)/$(BINARY)"
|
||||
|
||||
uninstall:
|
||||
rm -f $(PREFIX)/$(BINARY)
|
||||
@echo "Removed $(PREFIX)/$(BINARY)"
|
||||
|
||||
test:
|
||||
go test ./...
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package workspace
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -15,21 +16,21 @@ func Detect(reg *Registry, cwd string) (Entry, error) {
|
||||
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)
|
||||
if clean == base || strings.HasPrefix(clean, base+string(filepath.Separator)) {
|
||||
if len(base) > bestLen {
|
||||
realBase := canonicalPath(base)
|
||||
if containsPath(clean, base) || containsPath(realClean, realBase) {
|
||||
if len(realBase) > bestLen {
|
||||
best = ws
|
||||
bestLen = len(base)
|
||||
bestLen = len(realBase)
|
||||
}
|
||||
}
|
||||
}
|
||||
if bestLen == -1 {
|
||||
return Entry{}, fmt.Errorf(
|
||||
`not inside a registered workspace; run "browseros-patch list" to inspect workspaces or pass one by name`,
|
||||
)
|
||||
return Entry{}, detectError(clean, realClean, reg.Workspaces)
|
||||
}
|
||||
return best, nil
|
||||
}
|
||||
@@ -47,3 +48,43 @@ func Resolve(reg *Registry, name string, cwd string, src string) (Entry, error)
|
||||
}
|
||||
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())
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func NormalizeWorkspacePath(raw string) (string, error) {
|
||||
if _, err := os.Stat(filepath.Join(clean, ".git")); err != nil {
|
||||
return "", fmt.Errorf("workspace is not a git checkout: %s", clean)
|
||||
}
|
||||
return clean, nil
|
||||
return canonicalPath(clean), nil
|
||||
}
|
||||
|
||||
func (r *Registry) Get(name string) (Entry, error) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package workspace
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -36,6 +37,10 @@ func TestRegistryDetectsLongestMatchingWorkspace(t *testing.T) {
|
||||
t.Fatalf("mkdir: %v", err)
|
||||
}
|
||||
}
|
||||
detectedPath := filepath.Join(child, "chrome", "browser")
|
||||
if err := os.MkdirAll(detectedPath, 0o755); err != nil {
|
||||
t.Fatalf("mkdir detected path: %v", err)
|
||||
}
|
||||
|
||||
reg := &Registry{Version: 1}
|
||||
if _, err := reg.Add("parent", parent); err != nil {
|
||||
@@ -45,7 +50,7 @@ func TestRegistryDetectsLongestMatchingWorkspace(t *testing.T) {
|
||||
t.Fatalf("add child: %v", err)
|
||||
}
|
||||
|
||||
ws, err := Detect(reg, filepath.Join(child, "chrome", "browser"))
|
||||
ws, err := Detect(reg, detectedPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Detect: %v", err)
|
||||
}
|
||||
@@ -53,3 +58,86 @@ func TestRegistryDetectsLongestMatchingWorkspace(t *testing.T) {
|
||||
t.Fatalf("expected child workspace, got %q", ws.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectMatchesSymlinkedWorkingDirectory(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
workspacePath := filepath.Join(root, "chromium-1", "src")
|
||||
if err := os.MkdirAll(filepath.Join(workspacePath, ".git"), 0o755); err != nil {
|
||||
t.Fatalf("mkdir workspace: %v", err)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Join(workspacePath, "chrome", "browser"), 0o755); err != nil {
|
||||
t.Fatalf("mkdir workspace child: %v", err)
|
||||
}
|
||||
linkPath := filepath.Join(root, "ch-1")
|
||||
if err := os.Symlink(workspacePath, linkPath); err != nil {
|
||||
t.Fatalf("symlink workspace: %v", err)
|
||||
}
|
||||
|
||||
reg := &Registry{Version: 1}
|
||||
if _, err := reg.Add("ch1", workspacePath); err != nil {
|
||||
t.Fatalf("add workspace: %v", err)
|
||||
}
|
||||
|
||||
ws, err := Detect(reg, filepath.Join(linkPath, "chrome", "browser"))
|
||||
if err != nil {
|
||||
t.Fatalf("Detect: %v", err)
|
||||
}
|
||||
if ws.Name != "ch1" {
|
||||
t.Fatalf("expected ch1 workspace, got %q", ws.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryAddStoresCanonicalWorkspacePath(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
workspacePath := filepath.Join(root, "chromium-1", "src")
|
||||
if err := os.MkdirAll(filepath.Join(workspacePath, ".git"), 0o755); err != nil {
|
||||
t.Fatalf("mkdir workspace: %v", err)
|
||||
}
|
||||
linkPath := filepath.Join(root, "ch-1")
|
||||
if err := os.Symlink(workspacePath, linkPath); err != nil {
|
||||
t.Fatalf("symlink workspace: %v", err)
|
||||
}
|
||||
|
||||
reg := &Registry{Version: 1}
|
||||
entry, err := reg.Add("ch1", linkPath)
|
||||
if err != nil {
|
||||
t.Fatalf("add workspace: %v", err)
|
||||
}
|
||||
expectedPath := canonicalPath(workspacePath)
|
||||
if entry.Path != expectedPath {
|
||||
t.Fatalf("expected canonical path %q, got %q", expectedPath, entry.Path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectErrorIncludesPathContextAndWorkspaceHint(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
workspacePath := filepath.Join(root, "chromium-1", "src")
|
||||
if err := os.MkdirAll(filepath.Join(workspacePath, ".git"), 0o755); err != nil {
|
||||
t.Fatalf("mkdir workspace: %v", err)
|
||||
}
|
||||
outsidePath := filepath.Join(root, "outside")
|
||||
if err := os.MkdirAll(outsidePath, 0o755); err != nil {
|
||||
t.Fatalf("mkdir outside: %v", err)
|
||||
}
|
||||
|
||||
reg := &Registry{Version: 1}
|
||||
if _, err := reg.Add("ch1", workspacePath); err != nil {
|
||||
t.Fatalf("add workspace: %v", err)
|
||||
}
|
||||
|
||||
_, err := Detect(reg, outsidePath)
|
||||
if err == nil {
|
||||
t.Fatalf("expected Detect to fail")
|
||||
}
|
||||
message := err.Error()
|
||||
for _, want := range []string{
|
||||
"cwd: " + outsidePath,
|
||||
"registered workspaces:",
|
||||
"ch1 " + canonicalPath(workspacePath),
|
||||
"example: browseros-patch diff ch1",
|
||||
} {
|
||||
if !strings.Contains(message, want) {
|
||||
t.Fatalf("expected error to contain %q, got:\n%s", want, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user