forked from tangled.org/core
this repo has no description
at fork-pulls 3.1 kB view raw
1package git 2 3import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/bluekeyes/go-gitdiff/gitdiff" 9 "github.com/go-git/go-git/v5/plumbing" 10 "github.com/go-git/go-git/v5/plumbing/object" 11 "tangled.sh/tangled.sh/core/types" 12) 13 14func (g *GitRepo) Diff() (*types.NiceDiff, error) { 15 c, err := g.r.CommitObject(g.h) 16 if err != nil { 17 return nil, fmt.Errorf("commit object: %w", err) 18 } 19 20 patch := &object.Patch{} 21 commitTree, err := c.Tree() 22 parent := &object.Commit{} 23 if err == nil { 24 parentTree := &object.Tree{} 25 if c.NumParents() != 0 { 26 parent, err = c.Parents().Next() 27 if err == nil { 28 parentTree, err = parent.Tree() 29 if err == nil { 30 patch, err = parentTree.Patch(commitTree) 31 if err != nil { 32 return nil, fmt.Errorf("patch: %w", err) 33 } 34 } 35 } 36 } else { 37 patch, err = parentTree.Patch(commitTree) 38 if err != nil { 39 return nil, fmt.Errorf("patch: %w", err) 40 } 41 } 42 } 43 44 diffs, _, err := gitdiff.Parse(strings.NewReader(patch.String())) 45 if err != nil { 46 log.Println(err) 47 } 48 49 nd := types.NiceDiff{} 50 for _, d := range diffs { 51 ndiff := types.Diff{} 52 ndiff.Name.New = d.NewName 53 ndiff.Name.Old = d.OldName 54 ndiff.IsBinary = d.IsBinary 55 ndiff.IsNew = d.IsNew 56 ndiff.IsDelete = d.IsDelete 57 ndiff.IsCopy = d.IsCopy 58 ndiff.IsRename = d.IsRename 59 60 for _, tf := range d.TextFragments { 61 ndiff.TextFragments = append(ndiff.TextFragments, *tf) 62 for _, l := range tf.Lines { 63 switch l.Op { 64 case gitdiff.OpAdd: 65 nd.Stat.Insertions += 1 66 case gitdiff.OpDelete: 67 nd.Stat.Deletions += 1 68 } 69 } 70 } 71 72 nd.Diff = append(nd.Diff, ndiff) 73 } 74 75 nd.Stat.FilesChanged = len(diffs) 76 nd.Commit.This = c.Hash.String() 77 78 if parent.Hash.IsZero() { 79 nd.Commit.Parent = "" 80 } else { 81 nd.Commit.Parent = parent.Hash.String() 82 } 83 nd.Commit.Author = c.Author 84 nd.Commit.Message = c.Message 85 86 return &nd, nil 87} 88 89func (g *GitRepo) DiffTree(rev1, rev2 string) (*types.DiffTree, error) { 90 commit1, err := g.resolveRevision(rev1) 91 if err != nil { 92 return nil, fmt.Errorf("Invalid revision: %s", rev1) 93 } 94 95 commit2, err := g.resolveRevision(rev2) 96 if err != nil { 97 return nil, fmt.Errorf("Invalid revision: %s", rev2) 98 } 99 100 tree1, err := commit1.Tree() 101 if err != nil { 102 return nil, err 103 } 104 105 tree2, err := commit2.Tree() 106 if err != nil { 107 return nil, err 108 } 109 110 diff, err := object.DiffTree(tree1, tree2) 111 if err != nil { 112 return nil, err 113 } 114 115 patch, err := diff.Patch() 116 if err != nil { 117 return nil, err 118 } 119 120 diffs, _, err := gitdiff.Parse(strings.NewReader(patch.String())) 121 if err != nil { 122 return nil, err 123 } 124 125 return &types.DiffTree{ 126 Rev1: commit1.Hash.String(), 127 Rev2: commit2.Hash.String(), 128 Patch: patch.String(), 129 Diff: diffs, 130 }, nil 131} 132 133func (g *GitRepo) resolveRevision(revStr string) (*object.Commit, error) { 134 rev, err := g.r.ResolveRevision(plumbing.Revision(revStr)) 135 if err != nil { 136 return nil, fmt.Errorf("resolving revision %s: %w", revStr, err) 137 } 138 139 commit, err := g.r.CommitObject(*rev) 140 if err != nil { 141 142 return nil, fmt.Errorf("getting commit for %s: %w", revStr, err) 143 } 144 145 return commit, nil 146}