Add tijo-conflicts command

andybalholm
Apr 11, 2023, 10:18 PM
Z6CD2LYKHVX2CBSKVA74CLDKIAVQFHHGFXAYFTDUZO4OGTHPKFGAC

Dependencies

  • [2] EYPCPIP7 Apply changes and build a graph
  • [3] AYLFNM5C Add the ability to output the contents of a file.
  • [4] 4JR6O4JT Try a new approach to deletion
  • [5] FWGMIVUZ Add tijo-cat command

Change contents

  • edit in output.go at line 41
    [3.794]
    [3.794]
    }
    type Conflict struct {
    Start int
    Center int
    End int
  • replacement in output.go at line 49
    [3.797][3.797:851]()
    func OutputFile(dest io.Writer, inode *Block) error {
    [3.797]
    [3.851]
    func FindConflicts(inode *Block) ([]*Block, []Conflict) {
  • edit in output.go at line 55
    [3.1090]
    [3.1090]
    var conflicts []Conflict
  • edit in output.go at line 57
    [3.1091][3.1091:1305]()
    // These maps tell us how many conflicts begin (etc.) directly before the
    // specified index of blocks.
    conflictStart := make(map[int]int)
    conflictCenter := make(map[int]int)
    conflictEnd := make(map[int]int)
  • replacement in output.go at line 109
    [3.2507][3.2507:2600]()
    conflictStart[closestParent+1]++
    conflictCenter[i]++
    conflictEnd[closestChild]++
    [3.2507]
    [3.2600]
    conflicts = append(conflicts, Conflict{
    Start: closestParent + 1,
    Center: i,
    End: closestChild,
    })
  • edit in output.go at line 116
    [3.2609]
    [3.2609]
    }
    return blocks, conflicts
    }
    func OutputFile(dest io.Writer, inode *Block) error {
    blocks, conflicts := FindConflicts(inode)
    // These maps tell us how many conflicts begin (etc.) directly before the
    // specified index of blocks.
    conflictStart := make(map[int]int)
    conflictCenter := make(map[int]int)
    conflictEnd := make(map[int]int)
    for _, c := range conflicts {
    conflictStart[c.Start]++
    conflictCenter[c.Center]++
    conflictEnd[c.End]++
  • file addition: tijo-conflicts (d--r------)
    [2.12919]
  • file addition: main.go (----------)
    [0.758]
    // The tijo-conflicts command prints detailed information about the conflicts
    // in the specified file(s).
    package main
    import (
    "fmt"
    "os"
    "os/exec"
    "strings"
    "pijul-go"
    )
    func printErrorAndExit(description string, err error) {
    msg := err.Error()
    if err, ok := err.(*exec.ExitError); ok && len(err.Stderr) > 0 {
    msg = string(err.Stderr)
    }
    fmt.Fprintln(os.Stderr, description, msg)
    os.Exit(2)
    }
    func main() {
    hashLog, err := exec.Command("pijul", "log", "--hash-only").Output()
    if err != nil {
    printErrorAndExit("error listing changes:", err)
    }
    hashes := strings.Fields(string(hashLog))
    parsedHashes := make([]pijul.Hash, 0, len(hashes))
    for i := len(hashes) - 1; i >= 0; i-- {
    h, err := pijul.HashFromBase32(hashes[i])
    if err != nil {
    printErrorAndExit("", fmt.Errorf("error parsing hash %q: %v", hashes[i], err))
    }
    parsedHashes = append(parsedHashes, h)
    }
    pristine, err := loadChanges(parsedHashes)
    if err != nil {
    printErrorAndExit("error loading changes:", err)
    }
    for _, filename := range os.Args[1:] {
    dirEntry, err := pijul.FollowPath(pristine, filename)
    if err != nil {
    printErrorAndExit("error finding file:", err)
    }
    blocks, conflicts := pijul.FindConflicts(dirEntry.Inode)
    for _, c := range conflicts {
    fmt.Println(">>>>>>>")
    for i := c.Start; i < c.End; i++ {
    if i == c.Center {
    fmt.Println("=======")
    }
    b := blocks[i]
    fmt.Printf("block %v:%d:%d\n", b.Change, b.Start, b.End)
    for _, h := range b.DeletedBy {
    fmt.Printf("deleted-by %v\n", h)
    }
    for _, e := range b.ReverseEdges {
    fmt.Printf("up %v:%d %d %v\n", e.From.Change, e.From.End, e.Flag, e.Change)
    }
    os.Stdout.Write(b.Content)
    for _, e := range b.Edges {
    fmt.Printf("down %v:%d %d %v\n", e.To.Change, e.To.Start, e.Flag, e.Change)
    }
    fmt.Println()
    }
    fmt.Println("<<<<<<<")
    }
    }
    }
    func loadChanges(hashes []pijul.Hash) (*pijul.Graph, error) {
    pristine := pijul.NewGraph()
    for _, h := range hashes {
    hs := h.String()
    data, err := os.ReadFile(fmt.Sprintf(".pijul/changes/%s/%s.change", hs[:2], hs[2:]))
    if err != nil {
    return nil, fmt.Errorf("error reading change %s: %w", hs, err)
    }
    c, err := pijul.DeserializeChange(data)
    if err != nil {
    return nil, fmt.Errorf("error deserializing change %s: %w", hs, err)
    }
    err = pristine.ApplyChange(h, c)
    if err != nil {
    return nil, fmt.Errorf("error applying change %s: %w", hs, err)
    }
    }
    return pristine, nil
    }