Skip to content

Commit 67c4825

Browse files
committed
object_db: add support for multiple hash algorithms
Currently, our object DB has support for one major type of option: alternates. However, we also need to deal with the Git SHA-256 transition as well so we can support objects in repositories using SHA-256. Since we have multiple types of options, let's switch to an options-style initializer as well. This is a breaking API change, so we'll need to bump the major version and update go.mod and our package declarations accordingly. Create a Hasher method which tells us which hash algorithm is in use in this repository. We can then either hash our objects or query our hasher for properties such as the size. Because we'll also want to look up a hash algorithm before we have an object DB opened, let's make that Hasher method a wrapper around an internal function that we can use in this case to instantiate a hash algorithm based on its ID and use it in our object DB method. Note that this doesn't intrinsically add support for parsing these objects, which will come in a future commit, but it does lay the groundwork for that.
1 parent b4f6b4d commit 67c4825

8 files changed

+88
-30
lines changed

backend.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99
"strconv"
1010
"strings"
1111

12-
"github.com/git-lfs/gitobj/pack"
13-
"github.com/git-lfs/gitobj/storage"
12+
"github.com/git-lfs/gitobj/v2/pack"
13+
"github.com/git-lfs/gitobj/v2/storage"
1414
)
1515

1616
// NewFilesystemBackend initializes a new filesystem-based backend.

file_storer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"os"
99
"path/filepath"
1010

11-
"github.com/git-lfs/gitobj/errors"
11+
"github.com/git-lfs/gitobj/v2/errors"
1212
)
1313

1414
// fileStorer implements the storer interface by writing to the .git/objects

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module github.com/git-lfs/gitobj
1+
module github.com/git-lfs/gitobj/v2
22

33
require (
44
github.com/davecgh/go-spew v1.1.1 // indirect

memory_storer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"io"
77
"sync"
88

9-
"github.com/git-lfs/gitobj/errors"
9+
"github.com/git-lfs/gitobj/v2/errors"
1010
)
1111

1212
// memoryStorer is an implementation of the storer interface that holds data for

memory_storer_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"strings"
99
"testing"
1010

11-
"github.com/git-lfs/gitobj/errors"
11+
"github.com/git-lfs/gitobj/v2/errors"
1212
"github.com/stretchr/testify/assert"
1313
)
1414

object_db.go

+80-22
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ package gitobj
22

33
import (
44
"bytes"
5+
"crypto/sha1"
6+
"crypto/sha256"
57
"fmt"
8+
"hash"
69
"io"
710
"io/ioutil"
811
"os"
912
"sync/atomic"
1013

11-
"github.com/git-lfs/gitobj/storage"
14+
"github.com/git-lfs/gitobj/v2/storage"
1215
)
1316

1417
// ObjectDatabase enables the reading and writing of objects against a storage
@@ -29,41 +32,80 @@ type ObjectDatabase struct {
2932

3033
// temp directory, defaults to os.TempDir
3134
tmp string
35+
36+
// objectFormat is the object format (hash algorithm)
37+
objectFormat ObjectFormatAlgorithm
38+
}
39+
40+
type options struct {
41+
alternates string
42+
objectFormat ObjectFormatAlgorithm
43+
}
44+
45+
type Option func(*options)
46+
47+
type ObjectFormatAlgorithm string
48+
49+
const (
50+
ObjectFormatSHA1 = ObjectFormatAlgorithm("sha1")
51+
ObjectFormatSHA256 = ObjectFormatAlgorithm("sha256")
52+
)
53+
54+
// Alternates is an Option to specify the string of alternate repositories that
55+
// are searched for objects. The format is the same as for
56+
// GIT_ALTERNATE_OBJECT_DIRECTORIES.
57+
func Alternates(alternates string) Option {
58+
return func(args *options) {
59+
args.alternates = alternates
60+
}
61+
}
62+
63+
// ObjectFormat is an Option to specify the hash algorithm (object format) in
64+
// use in Git. If not specified, it defaults to ObjectFormatSHA1.
65+
func ObjectFormat(algo ObjectFormatAlgorithm) Option {
66+
return func(args *options) {
67+
args.objectFormat = algo
68+
}
3269
}
3370

3471
// FromFilesystem constructs an *ObjectDatabase instance that is backed by a
3572
// directory on the filesystem. Specifically, this should point to:
3673
//
3774
// /absolute/repo/path/.git/objects
38-
func FromFilesystem(root, tmp string) (*ObjectDatabase, error) {
39-
return FromFilesystemWithAlternates(root, tmp, "")
40-
}
75+
func FromFilesystem(root, tmp string, setters ...Option) (*ObjectDatabase, error) {
76+
args := &options{objectFormat: ObjectFormatSHA1}
4177

42-
// FromFilesystemWithAlternates constructs an *ObjectDatabase instance that is
43-
// backed by a directory on the filesystem, optionally with one or more
44-
// alternates. Specifically, this should point to:
45-
//
46-
// /absolute/repo/path/.git/objects
47-
func FromFilesystemWithAlternates(root, tmp, alternates string) (*ObjectDatabase, error) {
48-
b, err := NewFilesystemBackendWithAlternates(root, tmp, alternates)
78+
for _, setter := range setters {
79+
setter(args)
80+
}
81+
82+
b, err := NewFilesystemBackendWithAlternates(root, tmp, args.alternates)
4983
if err != nil {
5084
return nil, err
5185
}
5286

53-
ro, rw := b.Storage()
54-
return &ObjectDatabase{
55-
tmp: tmp,
56-
ro: ro,
57-
rw: rw,
58-
}, nil
87+
odb, err := FromBackend(b, setters...)
88+
if err != nil {
89+
return nil, err
90+
}
91+
odb.tmp = tmp
92+
return odb, nil
5993
}
6094

61-
func FromBackend(b storage.Backend) (*ObjectDatabase, error) {
95+
func FromBackend(b storage.Backend, setters ...Option) (*ObjectDatabase, error) {
96+
args := &options{objectFormat: ObjectFormatSHA1}
97+
98+
for _, setter := range setters {
99+
setter(args)
100+
}
101+
62102
ro, rw := b.Storage()
63-
return &ObjectDatabase{
64-
ro: ro,
65-
rw: rw,
66-
}, nil
103+
odb := &ObjectDatabase{
104+
ro: ro,
105+
rw: rw,
106+
objectFormat: args.objectFormat,
107+
}
108+
return odb, nil
67109
}
68110

69111
// Close closes the *ObjectDatabase, freeing any open resources (namely: the
@@ -227,6 +269,11 @@ func (o *ObjectDatabase) Root() (string, bool) {
227269
return "", false
228270
}
229271

272+
// Hasher returns a new hash instance suitable for this object database.
273+
func (o *ObjectDatabase) Hasher() hash.Hash {
274+
return hasher(o.objectFormat)
275+
}
276+
230277
// encode encodes and saves an object to the storage backend and uses an
231278
// in-memory buffer to calculate the object's encoded body.
232279
func (d *ObjectDatabase) encode(object Object) (sha []byte, n int64, err error) {
@@ -337,3 +384,14 @@ func (o *ObjectDatabase) cleanup(f *os.File) {
337384
f.Close()
338385
os.Remove(f.Name())
339386
}
387+
388+
func hasher(algo ObjectFormatAlgorithm) hash.Hash {
389+
switch algo {
390+
case ObjectFormatSHA1:
391+
return sha1.New()
392+
case ObjectFormatSHA256:
393+
return sha256.New()
394+
default:
395+
return nil
396+
}
397+
}

pack/set.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"sort"
99
"strings"
1010

11-
"github.com/git-lfs/gitobj/errors"
11+
"github.com/git-lfs/gitobj/v2/errors"
1212
)
1313

1414
// Set allows access of objects stored across a set of packfiles.

storage/multi_storage.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package storage
33
import (
44
"io"
55

6-
"github.com/git-lfs/gitobj/errors"
6+
"github.com/git-lfs/gitobj/v2/errors"
77
)
88

99
// Storage implements an interface for reading, but not writing, objects in an

0 commit comments

Comments
 (0)