aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/object/commitnode_graph.go
blob: 9fc28a27a097a614ff7403a283a4cfce48d6ae06 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package object

import (
	"fmt"
	"time"

	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph"
	"gopkg.in/src-d/go-git.v4/plumbing/storer"
)

// graphCommitNode is a reduced representation of Commit as presented in the commit

// graph file (commitgraph.Node). It is merely useful as an optimization for walking

// the commit graphs.

//

// graphCommitNode implements the CommitNode interface.

type graphCommitNode struct {
	// Hash for the Commit object

	hash plumbing.Hash
	// Index of the node in the commit graph file

	index int

	node *commitgraph.Node
	gci  *graphCommitNodeIndex
}

// graphCommitNodeIndex is an index that can load CommitNode objects from both the commit

// graph files and the object store.

//

// graphCommitNodeIndex implements the CommitNodeIndex interface

type graphCommitNodeIndex struct {
	commitGraph commitgraph.Index
	s           storer.EncodedObjectStorer
}

// NewGraphCommitNodeIndex returns CommitNodeIndex implementation that uses commit-graph

// files as backing storage and falls back to object storage when necessary

func NewGraphCommitNodeIndex(commitGraph commitgraph.Index, s storer.EncodedObjectStorer) CommitNodeIndex {
	return &graphCommitNodeIndex{commitGraph, s}
}

func (gci *graphCommitNodeIndex) Get(hash plumbing.Hash) (CommitNode, error) {
	// Check the commit graph first

	parentIndex, err := gci.commitGraph.GetIndexByHash(hash)
	if err == nil {
		parent, err := gci.commitGraph.GetNodeByIndex(parentIndex)
		if err != nil {
			return nil, err
		}

		return &graphCommitNode{
			hash:  hash,
			index: parentIndex,
			node:  parent,
			gci:   gci,
		}, nil
	}

	// Fallback to loading full commit object

	commit, err := GetCommit(gci.s, hash)
	if err != nil {
		return nil, err
	}

	return &objectCommitNode{
		nodeIndex: gci,
		commit:    commit,
	}, nil
}

func (c *graphCommitNode) ID() plumbing.Hash {
	return c.hash
}

func (c *graphCommitNode) Tree() (*Tree, error) {
	return GetTree(c.gci.s, c.node.TreeHash)
}

func (c *graphCommitNode) CommitTime() time.Time {
	return c.node.When
}

func (c *graphCommitNode) NumParents() int {
	return len(c.node.ParentIndexes)
}

func (c *graphCommitNode) ParentNodes() CommitNodeIter {
	return newParentgraphCommitNodeIter(c)
}

func (c *graphCommitNode) ParentNode(i int) (CommitNode, error) {
	if i < 0 || i >= len(c.node.ParentIndexes) {
		return nil, ErrParentNotFound
	}

	parent, err := c.gci.commitGraph.GetNodeByIndex(c.node.ParentIndexes[i])
	if err != nil {
		return nil, err
	}

	return &graphCommitNode{
		hash:  c.node.ParentHashes[i],
		index: c.node.ParentIndexes[i],
		node:  parent,
		gci:   c.gci,
	}, nil
}

func (c *graphCommitNode) ParentHashes() []plumbing.Hash {
	return c.node.ParentHashes
}

func (c *graphCommitNode) Commit() (*Commit, error) {
	return GetCommit(c.gci.s, c.hash)
}

func (c *graphCommitNode) String() string {
	return fmt.Sprintf(
		"%s %s\nDate:   %s",
		plumbing.CommitObject, c.ID(),
		c.CommitTime().Format(DateFormat),
	)
}