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
|
package furgit
import (
"bytes"
"errors"
"fmt"
"strconv"
)
// ObjectType mirrors Git's object type tags.
type ObjectType uint8
const (
ObjInvalid ObjectType = 0
ObjCommit ObjectType = 1
ObjTree ObjectType = 2
ObjBlob ObjectType = 3
ObjTag ObjectType = 4
ObjFuture ObjectType = 5
ObjOfsDelta ObjectType = 6
ObjRefDelta ObjectType = 7
)
const (
objNameBlob = "blob"
objNameTree = "tree"
objNameCommit = "commit"
objNameTag = "tag"
)
// Object describes any Git object variant.
type Object interface {
ObjectType() ObjectType
}
func headerForType(ty ObjectType, body []byte) ([]byte, error) {
var tyStr string
switch ty {
case ObjBlob:
tyStr = objNameBlob
case ObjTree:
tyStr = objNameTree
case ObjCommit:
tyStr = objNameCommit
case ObjTag:
tyStr = objNameTag
case ObjInvalid, ObjFuture, ObjOfsDelta, ObjRefDelta:
return nil, fmt.Errorf("furgit: object: unsupported type %d", ty)
default:
return nil, fmt.Errorf("furgit: object: unsupported type %d", ty)
}
size := strconv.Itoa(len(body))
var buf bytes.Buffer
buf.Grow(len(tyStr) + len(size) + 1)
buf.WriteString(tyStr)
buf.WriteByte(' ')
buf.WriteString(size)
buf.WriteByte(0)
return buf.Bytes(), nil
}
func parseObjectBody(ty ObjectType, id Hash, body []byte, repo *Repository) (Object, error) {
switch ty {
case ObjBlob:
return parseBlob(id, body)
case ObjTree:
return parseTree(id, body, repo)
case ObjCommit:
return parseCommit(id, body, repo)
case ObjTag:
return parseTag(id, body, repo)
case ObjInvalid, ObjFuture, ObjOfsDelta, ObjRefDelta:
return nil, fmt.Errorf("furgit: object: unsupported type %d", ty)
default:
return nil, fmt.Errorf("furgit: object: unknown type %d", ty)
}
}
// ReadObject resolves an ID by consulting loose then packed storage.
func (repo *Repository) ReadObject(id Hash) (Object, error) {
obj, err := repo.looseRead(id)
if err == nil {
return obj, nil
}
if !errors.Is(err, ErrNotFound) {
return nil, err
}
obj, err = repo.packRead(id)
if errors.Is(err, ErrNotFound) {
return nil, ErrInvalidObject
}
return obj, err
}
// ReadObjectTypeSize reports the object type and size without inflating the body.
func (repo *Repository) ReadObjectTypeSize(id Hash) (ObjectType, int64, error) {
ty, size, err := repo.looseTypeSize(id)
if err == nil {
return ty, size, nil
}
if !errors.Is(err, ErrNotFound) {
return ObjInvalid, 0, err
}
loc, err := repo.packIndexFind(id)
if err != nil {
if errors.Is(err, ErrNotFound) {
return ObjInvalid, 0, ErrInvalidObject
}
return ObjInvalid, 0, err
}
return repo.packTypeSizeAtLocation(loc, nil)
}
|