A library for working with Pijul repositories in Go
// The tijo-cat command prints the content of the specified file or files to
// standard output.
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)
		}
		pijul.OutputFile(os.Stdout, dirEntry.Inode)
	}
}

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
}