add trail worktree path helpers · Entire
add trail worktree path helpers
5e630a9→main·
pfleidi·1w ago·2 files·+96 added/-0 removed
Pure helpers for the upcoming 'trail checkout --worktree' flag: worktree directory naming under .entire/worktrees and POSIX shell quoting for the printed cd hint.
Sessions
01KX4MMNK7MGR9MZY812HXNJ44View transcript
[?
Add trail checkout --worktree SupportClaude Code·Fable 5·3 steps](/content/gh/entireio/cli/session/c5215fe7-28db-4a83-9d2e-482217df292d#timeline-01KX4MMNK7MGR9MZY812HXNJ44/index.html)
Changes
2
cmd/entire/cli
Atrail_checkout_worktree.go+38
Atrail_checkout_worktree_test.go+58
package cli
import (
"fmt"
"path/filepath"
"strings"
)
const (
trailWorktreesRelDir = ".entire/worktrees"
trailWorktreeFallbackName = "branch"
)
func defaultTrailWorktreePath(repoRoot, branch string, trailNumber int) string {
name := sanitizeTrailWorktreeName(branch)
if trailNumber > 0 {
name = fmt.Sprintf("trail-%d-%s", trailNumber, name)
}
return filepath.Join(repoRoot, filepath.FromSlash(trailWorktreesRelDir), name)
}
func sanitizeTrailWorktreeName(branch string) string {
name := strings.Map(func(r rune) rune {
if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' || r == '-' || r == '_' || r == '.' {
return r
}
return '-'
}, strings.TrimSpace(branch))
name = strings.Trim(name, "-.")
if name == "" {
return trailWorktreeFallbackName
}
return name
}
func shellQuotePath(path string) string {
return "'" + strings.ReplaceAll(path, "'", `\'`) + "'"
}
package cli
import (
"path/filepath"
"testing"
)
func TestDefaultTrailWorktreePath(t *testing.T) {
t.Parallel()
tests := []struct {
name string
branch string
trailNumber int
want string
}{
{"with number", "peter/feature.auth", 123, filepath.Join("/repo", ".entire", "worktrees", "trail-123-peter-feature.auth")},
{"without number", "feature/other", 0, filepath.Join("/repo", ".entire", "worktrees", "feature-other")},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := defaultTrailWorktreePath("/repo", tt.branch, tt.trailNumber); got != tt.want {
t.Fatalf("defaultTrailWorktreePath() = %q, want %q", got, tt.want)
}
})
}
}
func TestSanitizeTrailWorktreeName(t *testing.T) {
t.Parallel()
tests := []struct {
in string
want string
}{
{"feature/test", "feature-test"},
{"Feat_1.2-x", "Feat_1.2-x"},
{"weird name!", "weird-name"},
{"---", trailWorktreeFallbackName},
{" spaced ", "spaced"},
}
for _, tt := range tests {
if got := sanitizeTrailWorktreeName(tt.in); got != tt.want {
t.Fatalf("sanitizeTrailWorktreeName(%q) = %q, want %q", tt.in, got, tt.want)
}
}
}
func TestShellQuotePath(t *testing.T) {
t.Parallel()
got := shellQuotePath("/tmp/it's here")
want := `'/tmp/it'\''s here'`
if got != want {
t.Fatalf("shellQuotePath() = %q, want %q", got, want)
}
}