-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlayout.go
More file actions
62 lines (57 loc) · 1.95 KB
/
Copy pathlayout.go
File metadata and controls
62 lines (57 loc) · 1.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main
import (
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
)
// maxNameAttempts bounds the redraws in chooseWorktreeDir. Collisions on a
// 32-bit name are practically nonexistent, so exhausting the attempts means
// the environment is broken and is reported as an error.
const maxNameAttempts = 4
// randomDirName returns a random 8-character lowercase hex string. It is a
// variable so tests can substitute a deterministic sequence.
var randomDirName = func() (string, error) {
var b [4]byte
if _, err := rand.Read(b[:]); err != nil {
return "", fmt.Errorf("generate worktree directory name: %w", err)
}
return hex.EncodeToString(b[:]), nil
}
// worktreeBase returns the directory that holds all worktrees of the repo
// identified by its primary checkout path.
func worktreeBase(root, primaryPath string) string {
return filepath.Join(root, strings.TrimPrefix(primaryPath, string(filepath.Separator)))
}
// chooseWorktreeDir draws a random directory name under base. The name is
// meaningless on purpose: the branch <-> path mapping always lives in git
// (worktree list --porcelain), so nothing may depend on the directory name.
// A candidate is redrawn when it is registered as a worktree (including
// prunable leftovers) or already exists on disk.
func chooseWorktreeDir(base string, entries []worktreeEntry) (string, error) {
registered := make(map[string]bool, len(entries))
for _, e := range entries {
registered[e.Path] = true
}
for range maxNameAttempts {
name, err := randomDirName()
if err != nil {
return "", err
}
dir := filepath.Join(base, name)
if registered[dir] {
continue
}
if _, err := os.Lstat(dir); err == nil {
continue
} else if !errors.Is(err, fs.ErrNotExist) {
return "", fmt.Errorf("check worktree directory %s: %w", dir, err)
}
return dir, nil
}
return "", fmt.Errorf("no available worktree directory under %s after %d attempts", base, maxNameAttempts)
}