arche / internal/cli/cmd_diff.go

commit 154431fd
 1package cli
 2
 3import (
 4	"fmt"
 5
 6	"arche/internal/diff"
 7
 8	"github.com/spf13/cobra"
 9)
10
11var diffCmd = &cobra.Command{
12	Use:   "diff [commit-id]",
13	Short: "Diff working copy against HEAD, or two commits",
14	Long: `With no arguments, diffs the current working copy against its parent commit.
15With one argument, diffs that commit against its first parent.
16With two arguments, diffs from the first commit to the second.`,
17	Args: cobra.MaximumNArgs(2),
18	RunE: func(cmd *cobra.Command, args []string) error {
19		r := openRepo()
20		defer r.Close()
21
22		var treeA, treeB [0x20]byte
23
24		switch len(args) {
25		case 0:
26			head, _, err := r.HeadCommit()
27			if err != nil {
28				return err
29			}
30			treeB = head.TreeID
31			if len(head.Parents) > 0 {
32				parent, err := r.ReadCommit(head.Parents[0])
33				if err != nil {
34					return err
35				}
36				treeA = parent.TreeID
37			}
38
39		case 1:
40			id, err := resolveRef(r, args[0])
41			if err != nil {
42				return err
43			}
44			c, err := r.ReadCommit(id)
45			if err != nil {
46				return err
47			}
48			treeB = c.TreeID
49			if len(c.Parents) > 0 {
50				parent, err := r.ReadCommit(c.Parents[0])
51				if err != nil {
52					return err
53				}
54				treeA = parent.TreeID
55			}
56
57		case 2:
58			idA, err := resolveRef(r, args[0])
59			if err != nil {
60				return err
61			}
62			idB, err := resolveRef(r, args[1])
63			if err != nil {
64				return err
65			}
66			cA, err := r.ReadCommit(idA)
67			if err != nil {
68				return err
69			}
70			cB, err := r.ReadCommit(idB)
71			if err != nil {
72				return err
73			}
74			treeA = cA.TreeID
75			treeB = cB.TreeID
76		}
77
78		diffs, err := diff.TreeDiff(r, treeA, treeB)
79		if err != nil {
80			return err
81		}
82		if len(diffs) == 0 {
83			fmt.Println("(no changes)")
84			return nil
85		}
86		for _, d := range diffs {
87			fmt.Print(d.Patch)
88		}
89		return nil
90	},
91}