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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
package localrepo
import (
"bytes"
"context"
"fmt"
"gitlab.com/gitlab-org/gitaly/v15/internal/git"
"gitlab.com/gitlab-org/gitaly/v15/internal/helper/text"
)
// ObjectType is an Enum for the type of object of
// the ls-tree entry, which can be can be tree, blob or commit
type ObjectType int
// Entries holds every ls-tree Entry
type Entries []TreeEntry
// Enum values for ObjectType
const (
Unknown ObjectType = iota
Tree
Blob
Submodule
)
func (e Entries) Len() int {
return len(e)
}
func (e Entries) Swap(i, j int) {
e[i], e[j] = e[j], e[i]
}
// Less sorts entries by type in the order [*tree *blobs *submodules]
func (e Entries) Less(i, j int) bool {
return e[i].Type < e[j].Type
}
// ToEnum translates a string representation of the object type into an
// ObjectType enum.
func ToEnum(s string) ObjectType {
switch s {
case "tree":
return Tree
case "blob":
return Blob
case "commit":
return Submodule
default:
return Unknown
}
}
func fromEnum(t ObjectType) string {
switch t {
case Tree:
return "tree"
case Blob:
return "blob"
case Submodule:
return "commit"
default:
return "unknown"
}
}
// TreeEntry represents an entry of a git tree object.
type TreeEntry struct {
// OID is the object ID the tree entry refers to.
OID git.ObjectID
// Mode is the file mode of the tree entry.
Mode string
// Path is the full path of the tree entry.
Path string
// Type is the type of the tree entry.
Type ObjectType
}
// IsBlob returns whether or not the TreeEntry is a blob.
func (t *TreeEntry) IsBlob() bool {
return t.Type == Blob
}
// WriteTree writes a new tree object to the given path. This function does not verify whether OIDs
// referred to by tree entries actually exist in the repository.
func (repo *Repo) WriteTree(ctx context.Context, entries []TreeEntry) (git.ObjectID, error) {
var tree bytes.Buffer
for _, entry := range entries {
entryType := entry.Type
if entryType == Unknown {
switch entry.Mode {
case "100644":
fallthrough
case "100755":
fallthrough
case "120000":
entryType = Blob
case "040000":
entryType = Tree
case "160000":
entryType = Submodule
}
}
oid := entry.OID
formattedEntry := fmt.Sprintf("%s %s %s\t%s\000", entry.Mode, fromEnum(entryType), oid.String(), entry.Path)
if _, err := tree.WriteString(formattedEntry); err != nil {
return "", err
}
}
options := []git.Option{
git.Flag{Name: "-z"},
git.Flag{Name: "--missing"},
}
var stdout, stderr bytes.Buffer
if err := repo.ExecAndWait(ctx,
git.Command{
Name: "mktree",
Flags: options,
},
git.WithStdout(&stdout),
git.WithStderr(&stderr),
git.WithStdin(&tree),
); err != nil {
return "", err
}
objectHash, err := repo.ObjectHash(ctx)
if err != nil {
return "", fmt.Errorf("detecting object hash: %w", err)
}
treeOID, err := objectHash.FromHex(text.ChompBytes(stdout.Bytes()))
if err != nil {
return "", err
}
return treeOID, nil
}
|