Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit d7e1fee

Browse files
sona-tarmcuadros
sona-tar
authored andcommitted
Support non packed objects (#68)
* Support non packed git objects * Support non packed git objects for Iterator * Fix error handling from Writer() in FillObject() * Fix format in func (r *Reader) FillObject(obj core.Object) error * Fix to return d.addRefsFromPackedRefs() error And if packed-refs dosen't exist not to return error in d.addRefsFromPackedRefs * Remove debug code * Add GoDoc for func (d *DotGit) Objectfile(h core.Hash) (fs.FS, string, error) * Add GoDoc for func (r *Reader) FillObject(obj core.Object) error * Add GoDoc for func (d *DotGit) Objectfiles() (fs.FS, []core.Hash, error) * Fix format in func (d *DotGit) Objectfile(h core.Hash) (fs.FS, string, error) * Rename value dotGitobjcts -> objsDir * Change regexp.Compile -> regexp.MustCompile * Move regexp to variable initialization * Rename regexp value to be more coherent * Fix object directory name and object file name to correct character * Faster Objectfiles func * Add test for FillObject * Add GoDoc for func (s *ObjectStorage) Get(h core.Hash) (core.Object, error) * defer Close() * Return name values for defer function overwrite the error value. * Fix error handling in func (s *ObjectStorage) Get() Return error that gets error except for ErrObjfileNotFound from getFromUnpacked() * Rename getFromObject -> getFromUnpacked * Add test for func (d *DotGit) Objectfile(h core.Hash) (fs.FS, string, error) * Add test for func (d *DotGit) Objectfiles() (fs.FS, []core.Hash, error) * Faster check git object name * Faster dotgit_test.go * Fix Godoc for Objectfiles func * Refactor variable name in Objectfiles func * Fix GoDoc for objectfile func * Fix TestObjectfile func and TestObjectfiles func * Rename fixobj -> fixObj in Test Objectfile func * Fix test compare method * Refactor Get func in object.go * Refactor getFromUnpacked func in object.go * Fix GoDoc for ErrObjfileNotFound * Fix TestObjectfiles for not guarantee the slice order * Change error no such file or directory to target file not found * Change spec func (s *ObjectStorage) Get(h core.Hash) (core.Object, error) return core.ErrObjectNotFound, if index pointer is nil. * Add space * storage: Add object type hint parameter to ObjectStorage.getFromUnpacked
1 parent f6011d6 commit d7e1fee

File tree

8 files changed

+324
-8
lines changed

8 files changed

+324
-8
lines changed

formats/objfile/reader.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,16 @@ func (r *Reader) Close() (err error) {
121121

122122
return
123123
}
124+
125+
// FillObject fills the given object from an object entry
126+
func (r *Reader) FillObject(obj core.Object) error {
127+
obj.SetType(r.header.t)
128+
obj.SetSize(r.header.size)
129+
w, err := obj.Writer()
130+
if err != nil {
131+
return err
132+
}
133+
_, err = io.Copy(w, r.r)
134+
135+
return err
136+
}

formats/objfile/reader_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,35 @@ func (s *SuiteReader) TestReadCorruptZLib(c *C) {
6969
_, err := NewReader(source)
7070
c.Assert(err, NotNil)
7171
}
72+
73+
func (s *SuiteReader) TestFillObject(c *C) {
74+
for k, fixture := range objfileFixtures {
75+
com := fmt.Sprintf("test %d: ", k)
76+
hash := core.NewHash(fixture.hash)
77+
content, _ := base64.StdEncoding.DecodeString(fixture.content)
78+
data, _ := base64.StdEncoding.DecodeString(fixture.data)
79+
80+
testFillObject(c, bytes.NewReader(data), hash, fixture.t, content, com)
81+
}
82+
}
83+
84+
func testFillObject(c *C, source io.Reader, hash core.Hash, typ core.ObjectType, content []byte, com string) {
85+
var o core.Object = &core.MemoryObject{}
86+
r, err := NewReader(source)
87+
c.Assert(err, IsNil)
88+
err = r.FillObject(o)
89+
c.Assert(err, IsNil)
90+
c.Assert(o.Type(), Equals, typ)
91+
c.Assert(o.Size(), Equals, int64(len(content)))
92+
c.Assert(o.Hash(), Equals, hash)
93+
or, err := o.Reader()
94+
c.Assert(err, IsNil)
95+
rc, err := ioutil.ReadAll(or)
96+
c.Assert(err, IsNil)
97+
c.Assert(rc, DeepEquals, content, Commentf("%scontent=%s, expected=%s", base64.StdEncoding.EncodeToString(rc), base64.StdEncoding.EncodeToString(content)))
98+
c.Assert(or.Close(), IsNil)
99+
_, err = or.Read(make([]byte, 0, 1))
100+
c.Assert(err, Equals, nil)
101+
ow, err := o.Writer()
102+
c.Assert(ow, Equals, o)
103+
}

storage/filesystem/internal/dotgit/dotgit.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ var (
2222
ErrIdxNotFound = errors.New("idx file not found")
2323
// ErrPackfileNotFound is returned by Packfile when the packfile is not found
2424
ErrPackfileNotFound = errors.New("packfile not found")
25+
// ErrObjfileNotFound is returned by Objectfile when the objectffile is not found
26+
ErrObjfileNotFound = errors.New("object file not found")
2527
// ErrConfigNotFound is returned by Config when the config is not found
2628
ErrConfigNotFound = errors.New("config file not found")
2729
)
@@ -74,6 +76,10 @@ func (d *DotGit) Packfile() (fs.FS, string, error) {
7476
packDir := d.fs.Join(d.path, "objects", "pack")
7577
files, err := d.fs.ReadDir(packDir)
7678
if err != nil {
79+
if os.IsNotExist(err) {
80+
return nil, "", ErrPackfileNotFound
81+
}
82+
7783
return nil, "", err
7884
}
7985

@@ -93,6 +99,10 @@ func (d *DotGit) Idxfile() (fs.FS, string, error) {
9399
packDir := d.fs.Join(d.path, "objects", "pack")
94100
files, err := d.fs.ReadDir(packDir)
95101
if err != nil {
102+
if os.IsNotExist(err) {
103+
return nil, "", ErrIdxNotFound
104+
}
105+
96106
return nil, "", err
97107
}
98108

@@ -118,3 +128,75 @@ func (d *DotGit) Config() (fs.FS, string, error) {
118128

119129
return d.fs, configFile, nil
120130
}
131+
132+
// Objectfiles returns a slice with the hashes of objects found under the
133+
// .git/objects/ directory.
134+
func (dg *DotGit) Objectfiles() (fs.FS, []core.Hash, error) {
135+
objsDir := dg.fs.Join(dg.path, "objects")
136+
137+
files, err := dg.fs.ReadDir(objsDir)
138+
if err != nil {
139+
if os.IsNotExist(err) {
140+
return nil, nil, ErrObjfileNotFound
141+
}
142+
143+
return nil, nil, err
144+
}
145+
146+
var objects []core.Hash
147+
for _, f := range files {
148+
if f.IsDir() && len(f.Name()) == 2 && isHex(f.Name()) {
149+
objDir := f.Name()
150+
d, err := dg.fs.ReadDir(dg.fs.Join(objsDir, objDir))
151+
if err != nil {
152+
return nil, nil, err
153+
}
154+
155+
for _, o := range d {
156+
objects = append(objects, core.NewHash(objDir+o.Name()))
157+
}
158+
}
159+
}
160+
161+
return dg.fs, objects, nil
162+
}
163+
164+
func isHex(s string) bool {
165+
for _, b := range []byte(s) {
166+
if isNum(b) {
167+
continue
168+
}
169+
if isHexAlpha(b) {
170+
continue
171+
}
172+
173+
return false
174+
}
175+
176+
return true
177+
}
178+
179+
func isNum(b byte) bool {
180+
return b >= '0' && b <= '9'
181+
}
182+
183+
func isHexAlpha(b byte) bool {
184+
return b >= 'a' && b <= 'f' || b >= 'A' && b <= 'F'
185+
}
186+
187+
// Objectfile returns the path of the object file for a given hash
188+
// *if the file exists*, otherwise returns an ErrObjfileNotFound error.
189+
func (d *DotGit) Objectfile(h core.Hash) (fs.FS, string, error) {
190+
hash := h.String()
191+
objFile := d.fs.Join(d.path, "objects", hash[0:2], hash[2:40])
192+
193+
if _, err := d.fs.Stat(objFile); err != nil {
194+
if os.IsNotExist(err) {
195+
return nil, "", ErrObjfileNotFound
196+
}
197+
198+
return nil, "", err
199+
}
200+
201+
return d.fs, objFile, nil
202+
}

storage/filesystem/internal/dotgit/dotgit_test.go

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ var initFixtures = [...]struct {
2222
capabilities [][2]string
2323
packfile string
2424
idxfile string
25+
objectfiles []fixtureObject
2526
}{
2627
{
2728
name: "spinnaker",
@@ -37,7 +38,47 @@ var initFixtures = [...]struct {
3738
}, {
3839
name: "empty",
3940
tgz: "fixtures/empty-gitdir.tgz",
41+
}, {
42+
name: "unpacked",
43+
tgz: "fixtures/unpacked-objects-no-packfile-no-idx.tgz",
44+
objectfiles: []fixtureObject{
45+
fixtureObject{
46+
path: "objects/1e/0304e3cb54d0ad612ad70f1f15a285a65a4b8e",
47+
hash: "1e0304e3cb54d0ad612ad70f1f15a285a65a4b8e",
48+
},
49+
fixtureObject{
50+
path: "objects/5e/fb9bc29c482e023e40e0a2b3b7e49cec842034",
51+
hash: "5efb9bc29c482e023e40e0a2b3b7e49cec842034",
52+
},
53+
fixtureObject{
54+
path: "objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391",
55+
hash: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
56+
},
57+
},
4058
},
59+
{
60+
name: "unpacked-dummy",
61+
tgz: "fixtures/unpacked-objects-exist-one-dummy-object-no-packfile-no-idx.tgz",
62+
objectfiles: []fixtureObject{
63+
fixtureObject{
64+
path: "objects/1e/0304e3cb54d0ad612ad70f1f15a285a65a4b8e",
65+
hash: "1e0304e3cb54d0ad612ad70f1f15a285a65a4b8e",
66+
},
67+
fixtureObject{
68+
path: "objects/5e/fb9bc29c482e023e40e0a2b3b7e49cec842034",
69+
hash: "5efb9bc29c482e023e40e0a2b3b7e49cec842034",
70+
},
71+
fixtureObject{
72+
path: "objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391",
73+
hash: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
74+
},
75+
},
76+
},
77+
}
78+
79+
type fixtureObject struct {
80+
path string
81+
hash string
4182
}
4283

4384
type fixture struct {
@@ -47,6 +88,7 @@ type fixture struct {
4788
capabilities *common.Capabilities // expected capabilities
4889
packfile string // path of the packfile
4990
idxfile string // path of the idxfile
91+
objectfiles []fixtureObject // path and hash of the object files
5092
}
5193

5294
type SuiteDotGit struct {
@@ -77,6 +119,7 @@ func (s *SuiteDotGit) SetUpSuite(c *C) {
77119

78120
f.packfile = init.packfile
79121
f.idxfile = init.idxfile
122+
f.objectfiles = init.objectfiles
80123

81124
s.fixtures[init.name] = f
82125
}
@@ -193,11 +236,11 @@ func (s *SuiteDotGit) TestPackfile(c *C) {
193236
}, {
194237
fixture: "empty",
195238
fn: packfile,
196-
err: ".* no such file or directory",
239+
err: "packfile not found",
197240
}, {
198241
fixture: "empty",
199242
fn: idxfile,
200-
err: ".* no such file or directory",
243+
err: "idx file not found",
201244
}, {
202245
fixture: "no-packfile-no-idx",
203246
fn: packfile,
@@ -224,9 +267,87 @@ func (s *SuiteDotGit) TestPackfile(c *C) {
224267
}
225268
}
226269

270+
func (s *SuiteDotGit) TestObjectfiles(c *C) {
271+
for _, test := range [...]struct {
272+
fixture string
273+
err error
274+
}{
275+
{
276+
fixture: "unpacked",
277+
},
278+
{
279+
fixture: "unpacked-dummy",
280+
}, {
281+
fixture: "empty",
282+
err: ErrObjfileNotFound,
283+
}, {
284+
fixture: "no-packfile-no-idx",
285+
},
286+
} {
287+
com := Commentf("fixture = %s", test.fixture)
288+
289+
fix, dir := s.newFixtureDir(c, test.fixture)
290+
291+
_, hashes, err := dir.Objectfiles()
292+
293+
if test.err != nil {
294+
c.Assert(err, Equals, test.err, com)
295+
} else {
296+
c.Assert(err, IsNil, com)
297+
c.Assert(len(hashes), Equals, len(fix.objectfiles), com)
298+
299+
for _, hash := range hashes {
300+
c.Assert(containsObject(fix.objectfiles, hash), Equals, true, com)
301+
}
302+
}
303+
}
304+
}
305+
306+
func (s *SuiteDotGit) TestObjectfile(c *C) {
307+
for _, test := range [...]struct {
308+
fixture string
309+
err error
310+
}{
311+
{
312+
fixture: "unpacked",
313+
}, {
314+
fixture: "empty",
315+
err: ErrObjfileNotFound,
316+
}, {
317+
fixture: "no-packfile-no-idx",
318+
err: ErrObjfileNotFound,
319+
},
320+
} {
321+
com := Commentf("fixture = %s", test.fixture)
322+
323+
fix, dir := s.newFixtureDir(c, test.fixture)
324+
325+
for _, fixObj := range fix.objectfiles {
326+
_, path, err := dir.Objectfile(core.NewHash(fixObj.hash))
327+
328+
if test.err != nil {
329+
c.Assert(err, Equals, test.err, com)
330+
} else {
331+
c.Assert(err, IsNil, com)
332+
c.Assert(strings.HasSuffix(path, fixObj.path),
333+
Equals, true, com)
334+
}
335+
}
336+
}
337+
}
338+
227339
type getPathFn func(*DotGit) (fs.FS, string, error)
228340

229341
func noExt(path string) string {
230342
ext := filepath.Ext(path)
231343
return path[0 : len(path)-len(ext)]
232344
}
345+
346+
func containsObject(objs []fixtureObject, hash core.Hash) bool {
347+
for _, o := range objs {
348+
if strings.ToLower(o.hash) == strings.ToLower(hash.String()) {
349+
return true
350+
}
351+
}
352+
return false
353+
}

storage/filesystem/internal/dotgit/refs.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,9 @@ func (d *DotGit) addRefsFromPackedRefs(refs *[]*core.Reference) (err error) {
3232
path := d.fs.Join(d.path, packedRefsPath)
3333
f, err := d.fs.Open(path)
3434
if err != nil {
35-
if err == os.ErrNotExist {
35+
if os.IsNotExist(err) {
3636
return nil
3737
}
38-
3938
return err
4039
}
4140

@@ -44,7 +43,6 @@ func (d *DotGit) addRefsFromPackedRefs(refs *[]*core.Reference) (err error) {
4443
err = errClose
4544
}
4645
}()
47-
4846
s := bufio.NewScanner(f)
4947
for s.Scan() {
5048
ref, err := d.processLine(s.Text())

0 commit comments

Comments
 (0)