Switch to prefixed IDs and tell agents which Mac a message came from

This commit is contained in:
Ian Gulliver
2026-10-20 23:15:19 -07:00
parent f1296ba13d
commit 59bf17189d
42 changed files with 770 additions and 145 deletions
+195
View File
@@ -0,0 +1,195 @@
package git
import (
"bufio"
"context"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"strings"
)
func RenameRefs(repo string, rename func(string) string) error {
branches, err := run(repo, "for-each-ref", "--format=%(refname:short)", "refs/heads/byre/")
if err != nil {
return err
}
for _, b := range splitLines(branches) {
if rename(b) == b {
continue
}
_, err = run(repo, "branch", "-m", b, rename(b))
if err != nil {
return err
}
}
snaps, err := run(repo, "for-each-ref", "--format=%(objectname) %(refname)", "refs/byre/tasks/")
if err != nil {
return err
}
b := &strings.Builder{}
for _, l := range splitLines(snaps) {
sha, ref, _ := strings.Cut(l, " ")
if rename(ref) == ref {
continue
}
fmt.Fprintf(b, "create %s %s\ndelete %s %s\n", rename(ref), sha, ref, sha)
}
if b.Len() == 0 {
return nil
}
_, err = runInput(repo, nil, b.String(), "update-ref", "--stdin")
return err
}
func RepairWorktrees(repo string, paths []string) error {
if len(paths) == 0 {
return nil
}
_, err := run(repo, append([]string{"worktree", "repair"}, paths...)...)
return err
}
func RewriteNotes(repo string, rewrite func(string) string) error {
parent, stderr, code, err := runCode(repo, nil, "rev-parse", "--verify", "--quiet", NotesRef)
if err != nil {
return err
}
if code == 1 {
return nil
}
if code != 0 {
return fmt.Errorf("git rev-parse %s: exit status %d: %s", NotesRef, code, stderr)
}
listing, err := run(repo, "ls-tree", "-r", parent)
if err != nil {
return err
}
paths := map[string]string{}
shas := []string{}
for _, l := range splitLines(listing) {
meta, path, _ := strings.Cut(l, "\t")
fields := strings.Fields(meta)
paths[fields[2]] = path
shas = append(shas, fields[2])
}
if len(shas) == 0 {
return nil
}
contents, err := catBlobs(repo, shas)
if err != nil {
return err
}
dir, err := os.MkdirTemp("", "byre-notes-*")
if err != nil {
return err
}
defer os.RemoveAll(dir)
changed := []string{}
files := []string{}
for _, sha := range shas {
text := rewrite(contents[sha])
if text == contents[sha] {
continue
}
file := filepath.Join(dir, sha)
err = os.WriteFile(file, []byte(text), 0o644)
if err != nil {
return err
}
changed = append(changed, sha)
files = append(files, file)
}
if len(changed) == 0 {
return nil
}
blobs, err := runInput(repo, nil, strings.Join(files, "\n")+"\n", "hash-object", "-w", "--stdin-paths")
if err != nil {
return err
}
index := []string{"GIT_INDEX_FILE=" + filepath.Join(dir, "index")}
_, err = runEnv(repo, index, "read-tree", parent)
if err != nil {
return err
}
b := &strings.Builder{}
for i, blob := range splitLines(blobs) {
fmt.Fprintf(b, "100644 %s\t%s\n", blob, paths[changed[i]])
}
_, err = runInput(repo, index, b.String(), "update-index", "--index-info")
if err != nil {
return err
}
tree, err := runEnv(repo, index, "write-tree")
if err != nil {
return err
}
who, err := run(repo, "log", "-1", "--format=%cn%n%ce", parent)
if err != nil {
return err
}
name, email, _ := strings.Cut(who, "\n")
env := []string{"GIT_AUTHOR_NAME=" + name, "GIT_AUTHOR_EMAIL=" + email, "GIT_COMMITTER_NAME=" + name, "GIT_COMMITTER_EMAIL=" + email}
commit, err := runEnv(repo, env, "commit-tree", "-p", parent, "-m", "Rewrite byre ids in notes", tree)
if err != nil {
return err
}
_, err = run(repo, "update-ref", NotesRef, commit, parent)
return err
}
func catBlobs(repo string, shas []string) (map[string]string, error) {
out, err := runRaw(repo, strings.Join(shas, "\n")+"\n", "cat-file", "--batch")
if err != nil {
return nil, err
}
r := bufio.NewReader(strings.NewReader(out))
contents := map[string]string{}
for range shas {
header, err := r.ReadString('\n')
if err != nil {
return nil, err
}
fields := strings.Fields(header)
if len(fields) != 3 {
return nil, fmt.Errorf("git cat-file --batch: unexpected header %q", header)
}
size, err := strconv.Atoi(fields[2])
if err != nil {
return nil, err
}
body := make([]byte, size+1)
_, err = io.ReadFull(r, body)
if err != nil {
return nil, err
}
contents[fields[0]] = string(body[:size])
}
return contents, nil
}
func splitLines(out string) []string {
if out == "" {
return []string{}
}
return strings.Split(out, "\n")
}
func runRaw(dir, input string, args ...string) (string, error) {
out, stderr, code, err := runCodeInput(context.Background(), dir, nil, strings.NewReader(input), args...)
if err != nil {
return "", err
}
if code != 0 {
return "", fmt.Errorf("git %s: exit status %d: %s", strings.Join(args, " "), code, stderr)
}
return out, nil
}