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

Commit a42a12f

Browse files
committed
storage: filessytem read multiple packfiles support and index decoding
1 parent e8788ad commit a42a12f

File tree

12 files changed

+315
-2953
lines changed

12 files changed

+315
-2953
lines changed
Binary file not shown.
Binary file not shown.

fixtures/fixtures.go

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,32 @@ import (
66
"os"
77
"path/filepath"
88

9+
"github.com/alcortesm/tgz"
10+
911
check "gopkg.in/check.v1"
1012
"gopkg.in/src-d/go-git.v4/core"
13+
"gopkg.in/src-d/go-git.v4/utils/fs"
1114
)
1215

1316
var RootFolder = ""
1417

1518
const DataFolder = "data"
1619

1720
var fixtures = []*Fixture{{
18-
Tags: []string{"ofs-delta"},
21+
Tags: []string{"ofs-delta", ".git"},
1922
URL: "https://github.com/git-fixtures/basic",
2023
Head: core.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
2124
PackfileHash: core.NewHash("a3fed42da1e8189a077c0e6846c040dcf73fc9dd"),
25+
DotGitHash: core.NewHash("0a00a25543e6d732dbf4e8e9fec55c8e65fc4e8d"),
2226
}, {
2327
Tags: []string{"ref-delta"},
2428
URL: "https://github.com/git-fixtures/basic",
2529
Head: core.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
2630
PackfileHash: core.NewHash("c544593473465e6315ad4182d04d366c4592b829"),
31+
}, {
32+
Tags: []string{".git", "unpacked", "multi-packfile"},
33+
URL: "https://github.com/src-d/go-git.git",
34+
DotGitHash: core.NewHash("174be6bd4292c18160542ae6dc6704b877b8a01a"),
2735
}, {
2836
URL: "https://github.com/spinnaker/spinnaker",
2937
Head: core.NewHash("06ce06d0fc49646c4de733c45b7788aabad98a6f"),
@@ -49,11 +57,25 @@ func ByURL(url string) Fixtures {
4957
return r
5058
}
5159

60+
func ByTag(tag string) Fixtures {
61+
r := make(Fixtures, 0)
62+
for _, f := range fixtures {
63+
for _, t := range f.Tags {
64+
if t == tag {
65+
r = append(r, f)
66+
}
67+
}
68+
}
69+
70+
return r
71+
}
72+
5273
type Fixture struct {
5374
URL string
5475
Tags []string
5576
Head core.Hash
5677
PackfileHash core.Hash
78+
DotGitHash core.Hash
5779
}
5880

5981
func (f *Fixture) Packfile() io.ReadSeeker {
@@ -76,6 +98,15 @@ func (f *Fixture) Idx() io.ReadSeeker {
7698
return file
7799
}
78100

101+
func (f *Fixture) DotGit() fs.Filesystem {
102+
fn := filepath.Join(RootFolder, DataFolder, fmt.Sprintf("git-%s.tgz", f.DotGitHash))
103+
path, err := tgz.Extract(fn)
104+
if err != nil {
105+
panic(err)
106+
}
107+
return fs.NewOS(path)
108+
}
109+
79110
type Fixtures []*Fixture
80111

81112
func (g Fixtures) Test(c *check.C, test func(*Fixture)) {

formats/packfile/decoder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func (d *Decoder) recallByOffset(o int64) (core.Object, error) {
188188
return d.recallByHash(h)
189189
}
190190

191-
return nil, ErrCannotRecall.AddDetails("no object found at offset %d", o)
191+
return d.ReadObjectAt(o)
192192
}
193193

194194
func (d *Decoder) recallByHash(h core.Hash) (core.Object, error) {

formats/packfile/decoder_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,21 @@ func (s *ReaderSuite) TestDecodeCRCs(c *C) {
8383
}
8484

8585
c.Assert(int(sum), Equals, 78022211966)
86+
}
87+
88+
func (s *ReaderSuite) TestReadObjectAt(c *C) {
89+
f := fixtures.Basic().One()
90+
91+
scanner := NewScanner(f.Packfile())
92+
storage := memory.NewStorage()
93+
94+
d := NewDecoder(scanner, storage.ObjectStorage())
8695

96+
// the objects at reference 186, is a delta, so should be recall, without
97+
// being read before.
98+
obj, err := d.ReadObjectAt(186)
99+
c.Assert(err, IsNil)
100+
c.Assert(obj.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
87101
}
88102

89103
func AssertObjects(c *C, s *memory.Storage, expects []string) {

storage/filesystem/internal/dotgit/dotgit.go

Lines changed: 75 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import (
1111
"time"
1212

1313
"gopkg.in/src-d/go-git.v4/core"
14-
"gopkg.in/src-d/go-git.v4/storage/filesystem/internal/index"
14+
"gopkg.in/src-d/go-git.v4/formats/idxfile"
15+
"gopkg.in/src-d/go-git.v4/formats/packfile"
16+
"gopkg.in/src-d/go-git.v4/storage/memory"
1517
"gopkg.in/src-d/go-git.v4/utils/fs"
1618
)
1719

@@ -34,8 +36,6 @@ var (
3436
ErrIdxNotFound = errors.New("idx file not found")
3537
// ErrPackfileNotFound is returned by Packfile when the packfile is not found
3638
ErrPackfileNotFound = errors.New("packfile not found")
37-
// ErrObjfileNotFound is returned by Objectfile when the objectffile is not found
38-
ErrObjfileNotFound = errors.New("object file not found")
3939
// ErrConfigNotFound is returned by Config when the config is not found
4040
ErrConfigNotFound = errors.New("config file not found")
4141
)
@@ -77,12 +77,14 @@ func (d *DotGit) Refs() ([]*core.Reference, error) {
7777
return refs, nil
7878
}
7979

80+
// NewObjectPack return a writer for a new packfile, it saves the packfile to
81+
// disk and also generates and save the index for the given packfile.
8082
func (d *DotGit) NewObjectPack() (*PackWriter, error) {
8183
return newPackWrite(d.fs)
8284
}
8385

84-
// ObjectsPacks returns the list of availables packfiles
85-
func (d *DotGit) ObjectsPacks() ([]fs.FileInfo, error) {
86+
// ObjectPacks returns the list of availables packfiles
87+
func (d *DotGit) ObjectPacks() ([]core.Hash, error) {
8688
packDir := d.fs.Join(objectsPath, packPath)
8789
files, err := d.fs.ReadDir(packDir)
8890
if err != nil {
@@ -93,43 +95,51 @@ func (d *DotGit) ObjectsPacks() ([]fs.FileInfo, error) {
9395
return nil, err
9496
}
9597

96-
var packs []fs.FileInfo
98+
var packs []core.Hash
9799
for _, f := range files {
98-
if strings.HasSuffix(f.Name(), packExt) {
99-
packs = append(packs, f)
100+
if !strings.HasSuffix(f.Name(), packExt) {
101+
continue
100102
}
103+
104+
n := f.Name()
105+
h := core.NewHash(n[5 : len(n)-5]) //pack-(hash).pack
106+
packs = append(packs, h)
107+
101108
}
102109

103110
return packs, nil
104111
}
105112

106-
// ObjectPack returns the requested packfile and his idx
107-
func (d *DotGit) ObjectPack(filename string) (pack, idx fs.File, err error) {
108-
if !strings.HasSuffix(filename, packExt) {
109-
return nil, nil, fmt.Errorf("a .pack file should be provided")
110-
}
113+
// ObjectPack returns a fs.File of the given packfile
114+
func (d *DotGit) ObjectPack(hash core.Hash) (fs.File, error) {
115+
file := d.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s.pack", hash.String()))
111116

112-
pack, err = d.fs.Open(d.fs.Join(objectsPath, packPath, filename))
117+
pack, err := d.fs.Open(file)
113118
if err != nil {
114119
if os.IsNotExist(err) {
115-
return nil, nil, ErrPackfileNotFound
120+
return nil, ErrPackfileNotFound
116121
}
117122

118-
return
123+
return nil, err
119124
}
120125

121-
idxfile := filename[0:len(filename)-len(packExt)] + idxExt
122-
idxpath := d.fs.Join(objectsPath, packPath, idxfile)
123-
idx, err = d.fs.Open(idxpath)
126+
return pack, nil
127+
}
128+
129+
// ObjectPackIdx returns a fs.File of the index file for a given packfile
130+
func (d *DotGit) ObjectPackIdx(hash core.Hash) (fs.File, error) {
131+
file := d.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s.idx", hash.String()))
132+
133+
idx, err := d.fs.Open(file)
124134
if err != nil {
125135
if os.IsNotExist(err) {
126-
return nil, nil, ErrIdxNotFound
136+
return nil, ErrPackfileNotFound
127137
}
128138

129-
return
139+
return nil, err
130140
}
131141

132-
return
142+
return idx, nil
133143
}
134144

135145
// Objects returns a slice with the hashes of objects found under the
@@ -194,14 +204,15 @@ func isHexAlpha(b byte) bool {
194204
}
195205

196206
type PackWriter struct {
197-
fs fs.Filesystem
198-
sr io.ReadCloser
199-
sw io.WriteCloser
200-
fw fs.File
201-
mw io.Writer
202-
hash core.Hash
203-
index index.Index
204-
result chan error
207+
fs fs.Filesystem
208+
sr io.ReadCloser
209+
sw io.WriteCloser
210+
fw fs.File
211+
mw io.Writer
212+
213+
checksum core.Hash
214+
index idxfile.Idxfile
215+
result chan error
205216
}
206217

207218
func newPackWrite(fs fs.Filesystem) (*PackWriter, error) {
@@ -230,12 +241,23 @@ func newPackWrite(fs fs.Filesystem) (*PackWriter, error) {
230241

231242
func (w *PackWriter) buildIndex() {
232243
defer w.sr.Close()
233-
index, hash, err := index.NewFromPackfile(w.sr)
244+
o := memory.NewStorage().ObjectStorage()
245+
s := packfile.NewScannerFromReader(w.sr)
246+
d := packfile.NewDecoder(s, o)
247+
248+
checksum, err := d.Decode()
249+
if err != nil {
250+
w.result <- err
251+
return
252+
}
234253

235-
w.index = index
236-
w.hash = hash
254+
w.checksum = checksum
255+
w.index.PackfileChecksum = checksum
237256

238-
fmt.Println(hash, w.index)
257+
offsets := d.Offsets()
258+
for h, crc := range d.CRCs() {
259+
w.index.Add(h, uint64(offsets[h]), crc)
260+
}
239261

240262
w.result <- err
241263
}
@@ -265,9 +287,26 @@ func (w *PackWriter) Close() error {
265287
}
266288

267289
func (w *PackWriter) save() error {
268-
base := w.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s", w.hash))
290+
base := w.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s", w.checksum))
291+
292+
idx, err := w.fs.Create(fmt.Sprintf("%s.idx", base))
293+
if err != nil {
294+
return err
295+
}
269296

270-
//idx, err := w.fs.Create(fmt.Sprintf("%s.idx", base))
297+
if err := w.encodeIdx(idx); err != nil {
298+
return err
299+
}
300+
301+
if err := idx.Close(); err != nil {
302+
return err
303+
}
271304

272305
return w.fs.Rename(w.fw.Filename(), fmt.Sprintf("%s.pack", base))
273306
}
307+
308+
func (w *PackWriter) encodeIdx(writer io.Writer) error {
309+
e := idxfile.NewEncoder(writer)
310+
_, err := e.Encode(&w.index)
311+
return err
312+
}

0 commit comments

Comments
 (0)