+ // 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
+ }