diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2016-11-07 20:29:58 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-07 20:29:58 +0100 |
commit | 0ff9ef2b44c53e557c78bde0fd9c29847e5f0e23 (patch) | |
tree | b9c7485fe99e6e89fa736ceb0223aeb2ecddb77c | |
parent | f6ed7424cbf33c7013332d7e95b4262a4bc4a523 (diff) | |
download | go-git-0ff9ef2b44c53e557c78bde0fd9c29847e5f0e23.tar.gz |
global storage interface refactor (#112)
* core: ObjectStorage, ReferenceStorage renamed to ObjectStorer and
ReferenceStorer
* rebase
* general, changes request by @alcortes
* general, changes request by @alcortes
37 files changed, 548 insertions, 730 deletions
@@ -60,7 +60,7 @@ func (b *Blob) Encode(o core.Object) error { } // Reader returns a reader allow the access to the content of the blob -func (b *Blob) Reader() (core.ObjectReader, error) { +func (b *Blob) Reader() (io.ReadCloser, error) { return b.obj.Reader() } diff --git a/clients/common/common.go b/clients/common/common.go index 8e8b2e2..c7cac00 100644 --- a/clients/common/common.go +++ b/clients/common/common.go @@ -110,10 +110,9 @@ func (i *GitUploadPackInfo) Decode(r io.Reader) error { } func (i *GitUploadPackInfo) addRefs(ar *advrefs.AdvRefs) error { - i.Refs = make(memory.ReferenceStorage, 0) for name, hash := range ar.References { ref := core.NewReferenceFromStrings(name, hash.String()) - i.Refs.Set(ref) + i.Refs.SetReference(ref) } return i.addSymbolicRefs(ar) @@ -133,7 +132,7 @@ func (i *GitUploadPackInfo) addSymbolicRefs(ar *advrefs.AdvRefs) error { name := core.ReferenceName(chunks[0]) target := core.ReferenceName(chunks[1]) ref := core.NewSymbolicReference(name, target) - i.Refs.Set(ref) + i.Refs.SetReference(ref) } return nil @@ -37,11 +37,9 @@ func (c *Commit) Tree() (*Tree, error) { // Parents return a CommitIter to the parent Commits func (c *Commit) Parents() *CommitIter { - return NewCommitIter(c.r, core.NewObjectLookupIter( - c.r.s.ObjectStorage(), - core.CommitObject, - c.parents, - )) + return NewCommitIter(c.r, + core.NewObjectLookupIter(c.r.s, core.CommitObject, c.parents), + ) } // NumParents returns the number of parents in a commit. diff --git a/commit_test.go b/commit_test.go index f55d01a..6d83aec 100644 --- a/commit_test.go +++ b/commit_test.go @@ -29,7 +29,7 @@ func (s *SuiteCommit) SetUpSuite(c *C) { func (s *SuiteCommit) TestDecodeNonCommit(c *C) { hash := core.NewHash("9a48f23120e880dfbe41f7c9b7b708e9ee62a492") - blob, err := s.Repository.s.ObjectStorage().Get(core.AnyObject, hash) + blob, err := s.Repository.s.Object(core.AnyObject, hash) c.Assert(err, IsNil) commit := &Commit{} @@ -8,11 +8,14 @@ import ( "gopkg.in/src-d/go-git.v4/core" ) -// Storage storage of objects and references -type Storage interface { - ConfigStorage() config.ConfigStorage - ObjectStorage() core.ObjectStorage - ReferenceStorage() core.ReferenceStorage +// Storer is a generic storage of objects, references and any information +// related to a particular repository. Some Storer implementations persist the +// information in an system directory (such as `.git`) and others +// implementations are in memmory being ephemeral +type Storer interface { + core.ObjectStorer + core.ReferenceStorer + config.ConfigStorer } // countLines returns the number of lines in a string à la git, this is @@ -52,4 +55,5 @@ func checkClose(c io.Closer, err *error) { } } +// DateFormat is the format being use in the orignal git implementation const DateFormat = "Mon Jan 02 15:04:05 2006 -0700" diff --git a/common_test.go b/common_test.go index 854db3a..672a157 100644 --- a/common_test.go +++ b/common_test.go @@ -57,7 +57,7 @@ func (s *BaseSuite) buildRepositories(c *C, f fixtures.Fixtures) { defer f.Close() n := packfile.NewScanner(f) - d, err := packfile.NewDecoder(n, r.s.ObjectStorage()) + d, err := packfile.NewDecoder(n, r.s) c.Assert(err, IsNil) _, err = d.Decode() c.Assert(err, IsNil) @@ -155,7 +155,7 @@ func unpackFixtures(c *C, fixtures ...[]packedFixture) map[string]*Repository { c.Assert(err, IsNil, comment) r := packfile.NewScanner(f) - d, err := packfile.NewDecoder(r, repos[fixture.url].s.ObjectStorage()) + d, err := packfile.NewDecoder(r, repos[fixture.url].s) c.Assert(err, IsNil, comment) _, err = d.Decode() c.Assert(err, IsNil, comment) diff --git a/config/config.go b/config/config.go index f94d4c9..b7482ea 100644 --- a/config/config.go +++ b/config/config.go @@ -7,22 +7,51 @@ import ( ) const ( + // DefaultRefSpec is the default refspec used, when none is given DefaultRefSpec = "+refs/heads/*:refs/remotes/%s/*" ) +// ConfigStorer interface to persist Config objects +type ConfigStorer interface { + Config() (*Config, error) + SetConfig(*Config) error +} + var ( + ErrInvalid = errors.New("config invalid remote") ErrRemoteConfigNotFound = errors.New("remote config not found") ErrRemoteConfigEmptyURL = errors.New("remote config: empty URL") ErrRemoteConfigEmptyName = errors.New("remote config: empty name") ) -type ConfigStorage interface { - Remote(name string) (*RemoteConfig, error) - Remotes() ([]*RemoteConfig, error) - SetRemote(*RemoteConfig) error - DeleteRemote(name string) error +// Config contains the repository configuration +type Config struct { + Remotes map[string]*RemoteConfig +} + +// NewConfig returns a new empty Config +func NewConfig() *Config { + return &Config{ + Remotes: make(map[string]*RemoteConfig, 0), + } +} + +// Validate validate the fields and set the default values +func (c *Config) Validate() error { + for name, r := range c.Remotes { + if r.Name != name { + return ErrInvalid + } + + if err := r.Validate(); err != nil { + return err + } + } + + return nil } +// RemoteConfig contains the configuration for a given repository type RemoteConfig struct { Name string URL string diff --git a/config/config_test.go b/config/config_test.go index d97053b..f2539d0 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -6,6 +6,26 @@ type ConfigSuite struct{} var _ = Suite(&ConfigSuite{}) +func (s *ConfigSuite) TestConfigValidateInvalidRemote(c *C) { + config := &Config{ + Remotes: map[string]*RemoteConfig{ + "foo": {Name: "foo"}, + }, + } + + c.Assert(config.Validate(), Equals, ErrRemoteConfigEmptyURL) +} + +func (s *ConfigSuite) TestConfigValidateInvalidKey(c *C) { + config := &Config{ + Remotes: map[string]*RemoteConfig{ + "bar": {Name: "foo"}, + }, + } + + c.Assert(config.Validate(), Equals, ErrInvalid) +} + func (s *ConfigSuite) TestRemoteConfigValidateMissingURL(c *C) { config := &RemoteConfig{Name: "foo"} c.Assert(config.Validate(), Equals, ErrRemoteConfigEmptyURL) diff --git a/core/memory.go b/core/memory.go index 97b1b9b..dabee3a 100644 --- a/core/memory.go +++ b/core/memory.go @@ -1,7 +1,8 @@ -package core +package core import ( "bytes" + "io" "io/ioutil" ) @@ -39,12 +40,12 @@ func (o *MemoryObject) Size() int64 { return o.sz } func (o *MemoryObject) SetSize(s int64) { o.sz = s } // Reader returns a ObjectReader used to read the object's content. -func (o *MemoryObject) Reader() (ObjectReader, error) { +func (o *MemoryObject) Reader() (io.ReadCloser, error) { return ioutil.NopCloser(bytes.NewBuffer(o.cont)), nil } // Writer returns a ObjectWriter used to write the object's content. -func (o *MemoryObject) Writer() (ObjectWriter, error) { +func (o *MemoryObject) Writer() (io.WriteCloser, error) { return o, nil } diff --git a/core/object.go b/core/object.go index 30beff8..8125465 100644 --- a/core/object.go +++ b/core/object.go @@ -12,21 +12,6 @@ var ( ErrInvalidType = errors.New("invalid object type") ) -// TODO: Consider adding a Hash function to the ObjectReader and ObjectWriter -// interfaces that returns the hash calculated for the reader or writer. - -// ObjectReader is a generic representation of an object reader. -// -// ObjectReader implements io.ReadCloser. Close should be called when finished -// with it. -type ObjectReader io.ReadCloser - -// ObjectWriter is a generic representation of an object writer. -// -// ObjectWriter implements io.WriterCloser. Close should be called when finished -// with it. -type ObjectWriter io.WriteCloser - // Object is a generic representation of any git object type Object interface { Hash() Hash @@ -34,8 +19,8 @@ type Object interface { SetType(ObjectType) Size() int64 SetSize(int64) - Reader() (ObjectReader, error) - Writer() (ObjectWriter, error) + Reader() (io.ReadCloser, error) + Writer() (io.WriteCloser, error) } // ObjectType internal object type @@ -116,7 +101,7 @@ func ParseObjectType(value string) (typ ObjectType, err error) { // The ObjectLookupIter must be closed with a call to Close() when it is no // longer needed. type ObjectLookupIter struct { - storage ObjectStorage + storage ObjectStorer series []Hash t ObjectType pos int @@ -124,7 +109,7 @@ type ObjectLookupIter struct { // NewObjectLookupIter returns an object iterator given an object storage and // a slice of object hashes. -func NewObjectLookupIter(storage ObjectStorage, t ObjectType, series []Hash) *ObjectLookupIter { +func NewObjectLookupIter(storage ObjectStorer, t ObjectType, series []Hash) *ObjectLookupIter { return &ObjectLookupIter{ storage: storage, series: series, @@ -142,7 +127,7 @@ func (iter *ObjectLookupIter) Next() (Object, error) { } hash := iter.series[iter.pos] - obj, err := iter.storage.Get(iter.t, hash) + obj, err := iter.storage.Object(iter.t, hash) if err == nil { iter.pos++ } diff --git a/core/object_test.go b/core/object_test.go index d087aae..5ebf26a 100644 --- a/core/object_test.go +++ b/core/object_test.go @@ -159,18 +159,18 @@ func (o *MockObjectStorage) NewObject() Object { return nil } -func (o *MockObjectStorage) Set(obj Object) (Hash, error) { +func (o *MockObjectStorage) SetObject(obj Object) (Hash, error) { return ZeroHash, nil } -func (o *MockObjectStorage) Get(t ObjectType, h Hash) (Object, error) { +func (o *MockObjectStorage) Object(t ObjectType, h Hash) (Object, error) { return &MemoryObject{h: h}, nil } -func (o *MockObjectStorage) Iter(t ObjectType) (ObjectIter, error) { +func (o *MockObjectStorage) IterObjects(t ObjectType) (ObjectIter, error) { return nil, nil } -func (o *MockObjectStorage) Begin() TxObjectStorage { +func (o *MockObjectStorage) Begin() Transaction { return nil } diff --git a/core/reference.go b/core/reference.go index 16b60ac..ee55a6a 100644 --- a/core/reference.go +++ b/core/reference.go @@ -203,15 +203,15 @@ func (iter *ReferenceSliceIter) Close() { iter.pos = len(iter.series) } -func ResolveReference(s ReferenceStorage, n ReferenceName) (*Reference, error) { - r, err := s.Get(n) +func ResolveReference(s ReferenceStorer, n ReferenceName) (*Reference, error) { + r, err := s.Reference(n) if err != nil || r == nil { return r, err } return resolveReference(s, r, 0) } -func resolveReference(s ReferenceStorage, r *Reference, recursion int) (*Reference, error) { +func resolveReference(s ReferenceStorer, r *Reference, recursion int) (*Reference, error) { if r.Type() != SymbolicReference { return r, nil } @@ -220,7 +220,7 @@ func resolveReference(s ReferenceStorage, r *Reference, recursion int) (*Referen return nil, ErrMaxResolveRecursion } - t, err := s.Get(r.Target()) + t, err := s.Reference(r.Target()) if err != nil { return nil, err } diff --git a/core/storage.go b/core/storage.go index 739dfb6..101115b 100644 --- a/core/storage.go +++ b/core/storage.go @@ -7,45 +7,49 @@ import ( var ( //ErrStop is used to stop a ForEach function in an Iter - ErrStop = errors.New("stop iter") - ErrNotImplemented = errors.New("method not-implemented") + ErrStop = errors.New("stop iter") ) -// ObjectStorage generic storage of objects -type ObjectStorage interface { +// ObjectStorer generic storage of objects +type ObjectStorer interface { // NewObject returns a new Object, the real type of the object can be a // custom implementation or the defaul one, MemoryObject NewObject() Object - // Set save an object into the storage, the object shuld be create with - // the NewObject, method, and file if the type is not supported. - Set(Object) (Hash, error) - // Get an object by hash with the given ObjectType. Implementors should - // return (nil, ErrObjectNotFound) if an object doesn't exist with both the - // given hash and object type. + // SetObject save an object into the storage, the object shuld be create + // with the NewObject, method, and file if the type is not supported. + SetObject(Object) (Hash, error) + // Object an object by hash with the given ObjectType. Implementors + // should return (nil, ErrObjectNotFound) if an object doesn't exist with + // both the given hash and object type. // // Valid ObjectType values are CommitObject, BlobObject, TagObject, - // TreeObject and AnyObject. - // - // If AnyObject is given, the object must be looked up regardless of its type. - Get(ObjectType, Hash) (Object, error) - // Iter returns a custom ObjectIter over all the object on the storage. + // TreeObject and AnyObject. If AnyObject is given, the object must be + // looked up regardless of its type. + Object(ObjectType, Hash) (Object, error) + // IterObjects returns a custom ObjectIter over all the object on the + // storage. // // Valid ObjectType values are CommitObject, BlobObject, TagObject, - Iter(ObjectType) (ObjectIter, error) + IterObjects(ObjectType) (ObjectIter, error) +} + +// Transactioner is a optional method for ObjectStorer, it enable transaction +// base write and read operations in the storage +type Transactioner interface { // Begin starts a transaction. - Begin() TxObjectStorage + Begin() Transaction } -// ObjectStorageWrite is a optional method for ObjectStorage, it enable direct -// write of packfile to the storage -type ObjectStorageWrite interface { - // Writer retuns a writer for writing a packfile to the Storage, this method - // is optional, if not implemented the ObjectStorage should return a - // ErrNotImplemented error. +// PackfileWriter is a optional method for ObjectStorer, it enable direct write +// of packfile to the storage +type PackfileWriter interface { + // PackfileWriter retuns a writer for writing a packfile to the Storage, + // this method is optional, if not implemented the ObjectStorer should + // return a ErrNotImplemented error. // // If the implementation not implements Writer the objects should be written // using the Set method. - Writer() (io.WriteCloser, error) + PackfileWriter() (io.WriteCloser, error) } // ObjectIter is a generic closable interface for iterating over objects. @@ -55,20 +59,20 @@ type ObjectIter interface { Close() } -// TxObjectStorage is an in-progress storage transaction. -// A transaction must end with a call to Commit or Rollback. -type TxObjectStorage interface { - Set(Object) (Hash, error) - Get(ObjectType, Hash) (Object, error) +// Transaction is an in-progress storage transaction. A transaction must end +// with a call to Commit or Rollback. +type Transaction interface { + SetObject(Object) (Hash, error) + Object(ObjectType, Hash) (Object, error) Commit() error Rollback() error } -// ReferenceStorage generic storage of references -type ReferenceStorage interface { - Set(*Reference) error - Get(ReferenceName) (*Reference, error) - Iter() (ReferenceIter, error) +// ReferenceStorer generic storage of references +type ReferenceStorer interface { + SetReference(*Reference) error + Reference(ReferenceName) (*Reference, error) + IterReferences() (ReferenceIter, error) } // ReferenceIter is a generic closable interface for iterating over references diff --git a/examples/storage/aerospike/storage.go b/examples/storage/aerospike/storage.go index a9312ce..776fc33 100644 --- a/examples/storage/aerospike/storage.go +++ b/examples/storage/aerospike/storage.go @@ -15,17 +15,13 @@ import ( const ( urlField = "url" referencesSet = "reference" - remotesSet = "remote" + configSet = "config" ) type Storage struct { client *driver.Client ns string url string - - os *ObjectStorage - rs *ReferenceStorage - cs *ConfigStorage } func NewStorage(client *driver.Client, ns, url string) (*Storage, error) { @@ -36,46 +32,11 @@ func NewStorage(client *driver.Client, ns, url string) (*Storage, error) { return &Storage{client: client, ns: ns, url: url}, nil } -func (s *Storage) ObjectStorage() core.ObjectStorage { - if s.os == nil { - s.os = &ObjectStorage{s.client, s.ns, s.url} - } - - return s.os -} - -func (s *Storage) ReferenceStorage() core.ReferenceStorage { - if s.rs == nil { - s.rs = &ReferenceStorage{s.client, s.ns, s.url} - } - - return s.rs -} - -func (s *Storage) ConfigStorage() config.ConfigStorage { - if s.cs == nil { - s.cs = &ConfigStorage{s.client, s.ns, s.url} - } - - return s.cs -} - -type ObjectStorage struct { - client *driver.Client - ns string - url string -} - -func (s *ObjectStorage) NewObject() core.Object { +func (s *Storage) NewObject() core.Object { return &core.MemoryObject{} } -// Writer method not supported, this method is optional to implemented. -func (s *ObjectStorage) Writer() (io.WriteCloser, error) { - return nil, core.ErrNotImplemented -} - -func (s *ObjectStorage) Set(obj core.Object) (core.Hash, error) { +func (s *Storage) SetObject(obj core.Object) (core.Hash, error) { key, err := s.buildKey(obj.Hash(), obj.Type()) if err != nil { return obj.Hash(), err @@ -102,7 +63,7 @@ func (s *ObjectStorage) Set(obj core.Object) (core.Hash, error) { return obj.Hash(), err } -func (s *ObjectStorage) Get(t core.ObjectType, h core.Hash) (core.Object, error) { +func (s *Storage) Object(t core.ObjectType, h core.Hash) (core.Object, error) { key, err := s.buildKey(h, t) if err != nil { return nil, err @@ -120,7 +81,7 @@ func (s *ObjectStorage) Get(t core.ObjectType, h core.Hash) (core.Object, error) return objectFromRecord(rec, t) } -func (s *ObjectStorage) Iter(t core.ObjectType) (core.ObjectIter, error) { +func (s *Storage) IterObjects(t core.ObjectType) (core.ObjectIter, error) { stmnt := driver.NewStatement(s.ns, t.String()) err := stmnt.Addfilter(driver.NewEqualFilter(urlField, s.url)) @@ -132,34 +93,10 @@ func (s *ObjectStorage) Iter(t core.ObjectType) (core.ObjectIter, error) { return &ObjectIter{t, rs.Records}, nil } -func (s *ObjectStorage) buildKey(h core.Hash, t core.ObjectType) (*driver.Key, error) { +func (s *Storage) buildKey(h core.Hash, t core.ObjectType) (*driver.Key, error) { return driver.NewKey(s.ns, t.String(), fmt.Sprintf("%s|%s", s.url, h.String())) } -func (s *ObjectStorage) Begin() core.TxObjectStorage { - return &TxObjectStorage{Storage: s} -} - -type TxObjectStorage struct { - Storage *ObjectStorage -} - -func (tx *TxObjectStorage) Get(t core.ObjectType, h core.Hash) (core.Object, error) { - return tx.Storage.Get(t, h) -} - -func (tx *TxObjectStorage) Set(obj core.Object) (core.Hash, error) { - return tx.Storage.Set(obj) -} - -func (tx *TxObjectStorage) Commit() error { - return nil -} - -func (tx *TxObjectStorage) Rollback() error { - return nil -} - type ObjectIter struct { t core.ObjectType ch chan *driver.Record @@ -212,15 +149,8 @@ func objectFromRecord(r *driver.Record, t core.ObjectType) (core.Object, error) return o, nil } -type ReferenceStorage struct { - client *driver.Client - ns string - url string -} - -// Set stores a reference. -func (s *ReferenceStorage) Set(ref *core.Reference) error { - key, err := s.buildKey(ref.Name()) +func (s *Storage) SetReference(ref *core.Reference) error { + key, err := s.buildReferenceKey(ref.Name()) if err != nil { return err } @@ -235,9 +165,8 @@ func (s *ReferenceStorage) Set(ref *core.Reference) error { return s.client.Put(nil, key, bins) } -// Get returns a stored reference with the given name -func (s *ReferenceStorage) Get(n core.ReferenceName) (*core.Reference, error) { - key, err := s.buildKey(n) +func (s *Storage) Reference(n core.ReferenceName) (*core.Reference, error) { + key, err := s.buildReferenceKey(n) if err != nil { return nil, err } @@ -253,12 +182,11 @@ func (s *ReferenceStorage) Get(n core.ReferenceName) (*core.Reference, error) { ), nil } -func (s *ReferenceStorage) buildKey(n core.ReferenceName) (*driver.Key, error) { +func (s *Storage) buildReferenceKey(n core.ReferenceName) (*driver.Key, error) { return driver.NewKey(s.ns, referencesSet, fmt.Sprintf("%s|%s", s.url, n)) } -// Iter returns a core.ReferenceIter -func (s *ReferenceStorage) Iter() (core.ReferenceIter, error) { +func (s *Storage) IterReferences() (core.ReferenceIter, error) { stmnt := driver.NewStatement(s.ns, referencesSet) err := stmnt.Addfilter(driver.NewEqualFilter(urlField, s.url)) if err != nil { @@ -281,14 +209,8 @@ func (s *ReferenceStorage) Iter() (core.ReferenceIter, error) { return core.NewReferenceSliceIter(refs), nil } -type ConfigStorage struct { - client *driver.Client - ns string - url string -} - -func (s *ConfigStorage) Remote(name string) (*config.RemoteConfig, error) { - key, err := s.buildRemoteKey(name) +func (s *Storage) Config() (*config.Config, error) { + key, err := s.buildConfigKey() if err != nil { return nil, err } @@ -298,44 +220,12 @@ func (s *ConfigStorage) Remote(name string) (*config.RemoteConfig, error) { return nil, err } - return remoteFromRecord(rec) -} - -func remoteFromRecord(r *driver.Record) (*config.RemoteConfig, error) { - content := r.Bins["blob"].([]byte) - - c := &config.RemoteConfig{} - return c, json.Unmarshal(content, c) -} - -func (s *ConfigStorage) Remotes() ([]*config.RemoteConfig, error) { - stmnt := driver.NewStatement(s.ns, remotesSet) - err := stmnt.Addfilter(driver.NewEqualFilter(urlField, s.url)) - if err != nil { - return nil, err - } - - rs, err := s.client.Query(nil, stmnt) - if err != nil { - return nil, err - return nil, err - } - - var remotes []*config.RemoteConfig - for r := range rs.Records { - remote, err := remoteFromRecord(r) - if err != nil { - return nil, err - } - - remotes = append(remotes, remote) - } - - return remotes, nil + c := &config.Config{} + return c, json.Unmarshal(rec.Bins["blob"].([]byte), c) } -func (s *ConfigStorage) SetRemote(r *config.RemoteConfig) error { - key, err := s.buildRemoteKey(r.Name) +func (s *Storage) SetConfig(r *config.Config) error { + key, err := s.buildConfigKey() if err != nil { return err } @@ -347,31 +237,20 @@ func (s *ConfigStorage) SetRemote(r *config.RemoteConfig) error { bins := driver.BinMap{ urlField: s.url, - "name": r.Name, "blob": json, } return s.client.Put(nil, key, bins) } -func (s *ConfigStorage) DeleteRemote(name string) error { - key, err := s.buildRemoteKey(name) - if err != nil { - return err - } - - _, err = s.client.Delete(nil, key) - return err -} - -func (s *ConfigStorage) buildRemoteKey(name string) (*driver.Key, error) { - return driver.NewKey(s.ns, remotesSet, fmt.Sprintf("%s|%s", s.url, name)) +func (s *Storage) buildConfigKey() (*driver.Key, error) { + return driver.NewKey(s.ns, configSet, fmt.Sprintf("%s|config", s.url)) } func createIndexes(c *driver.Client, ns string) error { for _, set := range [...]string{ referencesSet, - remotesSet, + configSet, core.BlobObject.String(), core.TagObject.String(), core.TreeObject.String(), diff --git a/formats/config/common.go b/formats/config/common.go index e7292e9..d2f1e5c 100644 --- a/formats/config/common.go +++ b/formats/config/common.go @@ -32,6 +32,7 @@ func (c *Config) Section(name string) *Section { return s } } + s := &Section{Name: name} c.Sections = append(c.Sections, s) return s diff --git a/formats/config/doc.go b/formats/config/doc.go index 1f7eb78..dd77fbc 100644 --- a/formats/config/doc.go +++ b/formats/config/doc.go @@ -1,5 +1,4 @@ -// Package config implements decoding, encoding and manipulation -// of git config files. +// Package config implements decoding/encoding of git config files. package config /* diff --git a/formats/config/section.go b/formats/config/section.go index 552ce74..1844913 100644 --- a/formats/config/section.go +++ b/formats/config/section.go @@ -21,28 +21,15 @@ func (s *Section) IsName(name string) bool { return strings.ToLower(s.Name) == strings.ToLower(name) } -func (s *Subsection) IsName(name string) bool { - return s.Name == name -} - func (s *Section) Option(key string) string { return s.Options.Get(key) } -func (s *Subsection) Option(key string) string { - return s.Options.Get(key) -} - func (s *Section) AddOption(key string, value string) *Section { s.Options = s.Options.withAddedOption(key, value) return s } -func (s *Subsection) AddOption(key string, value string) *Subsection { - s.Options = s.Options.withAddedOption(key, value) - return s -} - func (s *Section) SetOption(key string, value string) *Section { s.Options = s.Options.withSettedOption(key, value) return s @@ -53,16 +40,6 @@ func (s *Section) RemoveOption(key string) *Section { return s } -func (s *Subsection) SetOption(key string, value string) *Subsection { - s.Options = s.Options.withSettedOption(key, value) - return s -} - -func (s *Subsection) RemoveOption(key string) *Subsection { - s.Options = s.Options.withoutOption(key) - return s -} - func (s *Section) Subsection(name string) *Subsection { for i := len(s.Subsections) - 1; i >= 0; i-- { ss := s.Subsections[i] @@ -70,6 +47,7 @@ func (s *Section) Subsection(name string) *Subsection { return ss } } + ss := &Subsection{Name: name} s.Subsections = append(s.Subsections, ss) return ss @@ -84,3 +62,26 @@ func (s *Section) HasSubsection(name string) bool { return false } + +func (s *Subsection) IsName(name string) bool { + return s.Name == name +} + +func (s *Subsection) Option(key string) string { + return s.Options.Get(key) +} + +func (s *Subsection) AddOption(key string, value string) *Subsection { + s.Options = s.Options.withAddedOption(key, value) + return s +} + +func (s *Subsection) SetOption(key string, value string) *Subsection { + s.Options = s.Options.withSettedOption(key, value) + return s +} + +func (s *Subsection) RemoveOption(key string) *Subsection { + s.Options = s.Options.withoutOption(key) + return s +} diff --git a/formats/idxfile/decoder_test.go b/formats/idxfile/decoder_test.go index 02167a7..18546d2 100644 --- a/formats/idxfile/decoder_test.go +++ b/formats/idxfile/decoder_test.go @@ -42,7 +42,7 @@ func (s *IdxfileSuite) TestDecodeCRCs(c *C) { scanner := packfile.NewScanner(f.Packfile()) storage := memory.NewStorage() - pd, err := packfile.NewDecoder(scanner, storage.ObjectStorage()) + pd, err := packfile.NewDecoder(scanner, storage) c.Assert(err, IsNil) _, err = pd.Decode() c.Assert(err, IsNil) diff --git a/formats/packfile/decoder.go b/formats/packfile/decoder.go index 4606a3f..e96980a 100644 --- a/formats/packfile/decoder.go +++ b/formats/packfile/decoder.go @@ -37,13 +37,15 @@ var ( // reader and without a core.ObjectStorage or ReadObjectAt method is called // without a seekable scanner ErrNonSeekable = NewError("non-seekable scanner") + // ErrRollback error making Rollback over a transaction after an error + ErrRollback = NewError("rollback error, during set error") ) // Decoder reads and decodes packfiles from an input stream. type Decoder struct { s *Scanner - o core.ObjectStorage - tx core.TxObjectStorage + o core.ObjectStorer + tx core.Transaction offsetToHash map[int64]core.Hash hashToOffset map[core.Hash]int64 @@ -51,20 +53,14 @@ type Decoder struct { } // NewDecoder returns a new Decoder that reads from r. -func NewDecoder(s *Scanner, o core.ObjectStorage) (*Decoder, error) { +func NewDecoder(s *Scanner, o core.ObjectStorer) (*Decoder, error) { if !s.IsSeekable && o == nil { return nil, ErrNonSeekable } - var tx core.TxObjectStorage - if o != nil { - tx = o.Begin() - } - return &Decoder{ - s: s, - o: o, - tx: tx, + s: s, + o: o, offsetToHash: make(map[int64]core.Hash, 0), hashToOffset: make(map[core.Hash]int64, 0), @@ -87,39 +83,64 @@ func (d *Decoder) doDecode() error { return err } - if d.o == nil { - return d.readObjects(count) + _, isTxStorer := d.o.(core.Transactioner) + switch { + case d.o == nil: + return d.readObjects(int(count)) + case isTxStorer: + return d.readObjectsWithObjectStorerTx(int(count)) + default: + return d.readObjectsWithObjectStorer(int(count)) } +} - if err := d.readObjects(count); err != nil { - if err := d.tx.Rollback(); err != nil { - return nil +func (d *Decoder) readObjects(count int) error { + for i := 0; i < count; i++ { + if _, err := d.ReadObject(); err != nil { + return err } - - return err } - return d.tx.Commit() + return nil } -func (d *Decoder) readObjects(count uint32) error { - for i := 0; i < int(count); i++ { +func (d *Decoder) readObjectsWithObjectStorer(count int) error { + for i := 0; i < count; i++ { obj, err := d.ReadObject() if err != nil { return err } - if d.o == nil { - continue + if _, err := d.o.SetObject(obj); err != nil { + return err + } + } + + return nil +} + +func (d *Decoder) readObjectsWithObjectStorerTx(count int) error { + tx := d.o.(core.Transactioner).Begin() + + for i := 0; i < count; i++ { + obj, err := d.ReadObject() + if err != nil { + return err } - if _, err := d.tx.Set(obj); err != nil { + if _, err := tx.SetObject(obj); err != nil { + if rerr := d.tx.Rollback(); rerr != nil { + return ErrRollback.AddDetails( + "error: %s, during tx.Set error: %s", rerr, err, + ) + } + return err } } - return nil + return tx.Commit() } // ReadObject reads a object from the stream and return it @@ -241,7 +262,7 @@ func (d *Decoder) recallByOffset(o int64) (core.Object, error) { } if h, ok := d.offsetToHash[o]; ok { - return d.tx.Get(core.AnyObject, h) + return d.tx.Object(core.AnyObject, h) } return nil, core.ErrObjectNotFound @@ -254,7 +275,7 @@ func (d *Decoder) recallByHash(h core.Hash) (core.Object, error) { } } - obj, err := d.tx.Get(core.AnyObject, h) + obj, err := d.tx.Object(core.AnyObject, h) if err != core.ErrObjectNotFound { return obj, err } diff --git a/formats/packfile/decoder_test.go b/formats/packfile/decoder_test.go index 48790b4..aa178d7 100644 --- a/formats/packfile/decoder_test.go +++ b/formats/packfile/decoder_test.go @@ -33,7 +33,7 @@ func (s *ReaderSuite) TestDecode(c *C) { scanner := NewScanner(f.Packfile()) storage := memory.NewStorage() - d, err := NewDecoder(scanner, storage.ObjectStorage()) + d, err := NewDecoder(scanner, storage) c.Assert(err, IsNil) defer d.Close() @@ -97,7 +97,7 @@ func (s *ReaderSuite) TestDecodeCRCs(c *C) { scanner := NewScanner(f.Packfile()) storage := memory.NewStorage() - d, err := NewDecoder(scanner, storage.ObjectStorage()) + d, err := NewDecoder(scanner, storage) c.Assert(err, IsNil) _, err = d.Decode() c.Assert(err, IsNil) @@ -158,11 +158,9 @@ func (s *ReaderSuite) TestSetOffsets(c *C) { } func assertObjects(c *C, s *memory.Storage, expects []string) { - o := s.ObjectStorage().(*memory.ObjectStorage) - - c.Assert(len(expects), Equals, len(o.Objects)) + c.Assert(len(expects), Equals, len(s.Objects)) for _, exp := range expects { - obt, err := o.Get(core.AnyObject, core.NewHash(exp)) + obt, err := s.Object(core.AnyObject, core.NewHash(exp)) c.Assert(err, IsNil) c.Assert(obt.Hash().String(), Equals, exp) } @@ -18,14 +18,14 @@ var NoErrAlreadyUpToDate = errors.New("already up-to-date") // Remote represents a connection to a remote repository type Remote struct { c *config.RemoteConfig - s Storage + s Storer // cache fields, there during the connection is open upSrv common.GitUploadPackService upInfo *common.GitUploadPackInfo } -func newRemote(s Storage, c *config.RemoteConfig) *Remote { +func newRemote(s Storer, c *config.RemoteConfig) *Remote { return &Remote{s: s, c: c} } @@ -95,7 +95,7 @@ func (r *Remote) Fetch(o *FetchOptions) (err error) { return NoErrAlreadyUpToDate } - req, err := r.buildRequest(r.s.ReferenceStorage(), o, refs) + req, err := r.buildRequest(r.s, o, refs) if err != nil { return err } @@ -139,7 +139,7 @@ func (r *Remote) getWantedReferences(spec []config.RefSpec) ([]*core.Reference, } } - _, err := r.s.ObjectStorage().Get(core.CommitObject, ref.Hash()) + _, err := r.s.Object(core.CommitObject, ref.Hash()) if err == core.ErrObjectNotFound { refs = append(refs, ref) return nil @@ -150,7 +150,7 @@ func (r *Remote) getWantedReferences(spec []config.RefSpec) ([]*core.Reference, } func (r *Remote) buildRequest( - s core.ReferenceStorage, o *FetchOptions, refs []*core.Reference, + s core.ReferenceStorer, o *FetchOptions, refs []*core.Reference, ) (*common.GitUploadPackRequest, error) { req := &common.GitUploadPackRequest{} req.Depth = o.Depth @@ -159,7 +159,7 @@ func (r *Remote) buildRequest( req.Want(ref.Hash()) } - i, err := s.Iter() + i, err := s.IterReferences() if err != nil { return nil, err } @@ -177,9 +177,8 @@ func (r *Remote) buildRequest( } func (r *Remote) updateObjectStorage(reader io.Reader) error { - s := r.s.ObjectStorage() - if sw, ok := s.(core.ObjectStorageWrite); ok { - w, err := sw.Writer() + if sw, ok := r.s.(core.PackfileWriter); ok { + w, err := sw.PackfileWriter() if err != nil { return err } @@ -190,7 +189,7 @@ func (r *Remote) updateObjectStorage(reader io.Reader) error { } stream := packfile.NewScanner(reader) - d, err := packfile.NewDecoder(stream, s) + d, err := packfile.NewDecoder(stream, r.s) if err != nil { return err } @@ -212,7 +211,7 @@ func (r *Remote) updateLocalReferenceStorage(specs []config.RefSpec, refs []*cor name := spec.Dst(ref.Name()) n := core.NewHashReference(name, ref.Hash()) - if err := r.s.ReferenceStorage().Set(n); err != nil { + if err := r.s.SetReference(n); err != nil { return err } } @@ -227,13 +226,12 @@ func (r *Remote) buildFetchedTags() error { return err } - os := r.s.ObjectStorage() return iter.ForEach(func(ref *core.Reference) error { if !ref.IsTag() { return nil } - _, err := os.Get(core.AnyObject, ref.Hash()) + _, err := r.s.Object(core.AnyObject, ref.Hash()) if err == core.ErrObjectNotFound { return nil } @@ -242,7 +240,7 @@ func (r *Remote) buildFetchedTags() error { return err } - return r.s.ReferenceStorage().Set(ref) + return r.s.SetReference(ref) }) } @@ -257,12 +255,12 @@ func (r *Remote) Ref(name core.ReferenceName, resolved bool) (*core.Reference, e return core.ResolveReference(r.upInfo.Refs, name) } - return r.upInfo.Refs.Get(name) + return r.upInfo.Refs.Reference(name) } // Refs returns a map with all the References func (r *Remote) Refs() (core.ReferenceIter, error) { - return r.upInfo.Refs.Iter() + return r.upInfo.Refs.IterReferences() } // Disconnect from the remote and save the config diff --git a/remote_test.go b/remote_test.go index 37539af..04167cd 100644 --- a/remote_test.go +++ b/remote_test.go @@ -1,6 +1,7 @@ package git import ( + "io" "io/ioutil" "os" @@ -80,7 +81,7 @@ func (s *RemoteSuite) TestFetch(c *C) { }) c.Assert(err, IsNil) - c.Assert(sto.ObjectStorage().(*memory.ObjectStorage).Objects, HasLen, 31) + c.Assert(sto.Objects, HasLen, 31) expectedRefs := []*core.Reference{ core.NewReferenceFromStrings("refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), @@ -89,22 +90,33 @@ func (s *RemoteSuite) TestFetch(c *C) { } for _, exp := range expectedRefs { - r, _ := sto.ReferenceStorage().Get(exp.Name()) + r, _ := sto.Reference(exp.Name()) c.Assert(exp.String(), Equals, r.String()) } } -func (s *RemoteSuite) TestFetchObjectStorageWriter(c *C) { +type mockPackfileWriter struct { + Storer + PackfileWriterCalled bool +} + +func (m *mockPackfileWriter) PackfileWriter() (io.WriteCloser, error) { + m.PackfileWriterCalled = true + return m.Storer.(core.PackfileWriter).PackfileWriter() +} + +func (s *RemoteSuite) TestFetchWithPackfileWriter(c *C) { dir, err := ioutil.TempDir("", "fetch") c.Assert(err, IsNil) defer os.RemoveAll(dir) // clean up - var sto Storage - sto, err = filesystem.NewStorage(osfs.New(dir)) + fss, err := filesystem.NewStorage(osfs.New(dir)) c.Assert(err, IsNil) - r := newRemote(sto, &config.RemoteConfig{Name: "foo", URL: RepositoryFixture}) + mock := &mockPackfileWriter{Storer: fss} + + r := newRemote(mock, &config.RemoteConfig{Name: "foo", URL: RepositoryFixture}) r.upSrv = &MockGitUploadPackService{} c.Assert(r.Connect(), IsNil) @@ -116,14 +128,16 @@ func (s *RemoteSuite) TestFetchObjectStorageWriter(c *C) { c.Assert(err, IsNil) var count int - iter, err := sto.ObjectStorage().Iter(core.AnyObject) + iter, err := mock.IterObjects(core.AnyObject) c.Assert(err, IsNil) iter.ForEach(func(core.Object) error { count++ return nil }) + c.Assert(count, Equals, 31) + c.Assert(mock.PackfileWriterCalled, Equals, true) } func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDate(c *C) { diff --git a/repository.go b/repository.go index 553703a..899127b 100644 --- a/repository.go +++ b/repository.go @@ -15,12 +15,14 @@ var ( ErrObjectNotFound = errors.New("object not found") ErrInvalidReference = errors.New("invalid reference, should be a tag or a branch") ErrRepositoryNonEmpty = errors.New("repository non empty") + ErrRemoteNotFound = errors.New("remote not found") + ErrRemoteExists = errors.New("remote already exists") ) // Repository giturl string, auth common.AuthMethod repository struct type Repository struct { r map[string]*Remote - s Storage + s Storer } // NewMemoryRepository creates a new repository, backed by a memory.Storage @@ -42,7 +44,7 @@ func NewFilesystemRepository(path string) (*Repository, error) { } // NewRepository creates a new repository with the given Storage -func NewRepository(s Storage) (*Repository, error) { +func NewRepository(s Storer) (*Repository, error) { return &Repository{ s: s, r: make(map[string]*Remote, 0), @@ -51,24 +53,32 @@ func NewRepository(s Storage) (*Repository, error) { // Remote return a remote if exists func (r *Repository) Remote(name string) (*Remote, error) { - c, err := r.s.ConfigStorage().Remote(name) + cfg, err := r.s.Config() if err != nil { return nil, err } + c, ok := cfg.Remotes[name] + if !ok { + return nil, ErrRemoteNotFound + } + return newRemote(r.s, c), nil } // Remotes return all the remotes func (r *Repository) Remotes() ([]*Remote, error) { - config, err := r.s.ConfigStorage().Remotes() + cfg, err := r.s.Config() if err != nil { return nil, err } - remotes := make([]*Remote, len(config)) - for i, c := range config { + remotes := make([]*Remote, len(cfg.Remotes)) + + var i int + for _, c := range cfg.Remotes { remotes[i] = newRemote(r.s, c) + i++ } return remotes, nil @@ -81,16 +91,33 @@ func (r *Repository) CreateRemote(c *config.RemoteConfig) (*Remote, error) { } remote := newRemote(r.s, c) - if err := r.s.ConfigStorage().SetRemote(c); err != nil { + + cfg, err := r.s.Config() + if err != nil { return nil, err } - return remote, nil + if _, ok := cfg.Remotes[c.Name]; ok { + return nil, ErrRemoteExists + } + + cfg.Remotes[c.Name] = c + return remote, r.s.SetConfig(cfg) } // DeleteRemote delete a remote from the repository and delete the config func (r *Repository) DeleteRemote(name string) error { - return r.s.ConfigStorage().DeleteRemote(name) + cfg, err := r.s.Config() + if err != nil { + return err + } + + if _, ok := cfg.Remotes[name]; !ok { + return ErrRemoteNotFound + } + + delete(cfg.Remotes, name) + return r.s.SetConfig(cfg) } // Clone clones a remote repository @@ -145,35 +172,42 @@ const refspecSingleBranch = "+refs/heads/%s:refs/remotes/%s/%[1]s" func (r *Repository) updateRemoteConfig( remote *Remote, o *CloneOptions, c *config.RemoteConfig, ) error { - if o.SingleBranch { - head, err := core.ResolveReference(remote.Info().Refs, o.ReferenceName) - if err != nil { - return err - } + if !o.SingleBranch { + return nil + } - c.Fetch = []config.RefSpec{ - config.RefSpec(fmt.Sprintf(refspecSingleBranch, head.Name().Short(), c.Name)), - } + head, err := core.ResolveReference(remote.Info().Refs, o.ReferenceName) + if err != nil { + return err + } + + c.Fetch = []config.RefSpec{ + config.RefSpec(fmt.Sprintf(refspecSingleBranch, head.Name().Short(), c.Name)), + } - return r.s.ConfigStorage().SetRemote(c) + cfg, err := r.s.Config() + if err != nil { + return err } - return nil + cfg.Remotes[c.Name] = c + return r.s.SetConfig(cfg) + } func (r *Repository) createReferences(ref *core.Reference) error { if !ref.IsBranch() { // detached HEAD mode head := core.NewHashReference(core.HEAD, ref.Hash()) - return r.s.ReferenceStorage().Set(head) + return r.s.SetReference(head) } - if err := r.s.ReferenceStorage().Set(ref); err != nil { + if err := r.s.SetReference(ref); err != nil { return err } head := core.NewSymbolicReference(core.HEAD, ref.Name()) - return r.s.ReferenceStorage().Set(head) + return r.s.SetReference(head) } // IsEmpty returns true if the repository is empty @@ -241,7 +275,7 @@ func (r *Repository) Commit(h core.Hash) (*Commit, error) { // Commits decode the objects into commits func (r *Repository) Commits() (*CommitIter, error) { - iter, err := r.s.ObjectStorage().Iter(core.CommitObject) + iter, err := r.s.IterObjects(core.CommitObject) if err != nil { return nil, err } @@ -261,7 +295,7 @@ func (r *Repository) Tree(h core.Hash) (*Tree, error) { // Trees decodes the objects into trees func (r *Repository) Trees() (*TreeIter, error) { - iter, err := r.s.ObjectStorage().Iter(core.TreeObject) + iter, err := r.s.IterObjects(core.TreeObject) if err != nil { return nil, err } @@ -281,7 +315,7 @@ func (r *Repository) Blob(h core.Hash) (*Blob, error) { // Blobs decodes the objects into blobs func (r *Repository) Blobs() (*BlobIter, error) { - iter, err := r.s.ObjectStorage().Iter(core.BlobObject) + iter, err := r.s.IterObjects(core.BlobObject) if err != nil { return nil, err } @@ -302,7 +336,7 @@ func (r *Repository) Tag(h core.Hash) (*Tag, error) { // Tags returns a TagIter that can step through all of the annotated tags // in the repository. func (r *Repository) Tags() (*TagIter, error) { - iter, err := r.s.ObjectStorage().Iter(core.TagObject) + iter, err := r.s.IterObjects(core.TagObject) if err != nil { return nil, err } @@ -312,7 +346,7 @@ func (r *Repository) Tags() (*TagIter, error) { // Object returns an object with the given hash. func (r *Repository) Object(t core.ObjectType, h core.Hash) (Object, error) { - obj, err := r.s.ObjectStorage().Get(t, h) + obj, err := r.s.Object(t, h) if err != nil { if err == core.ErrObjectNotFound { return nil, ErrObjectNotFound @@ -341,7 +375,7 @@ func (r *Repository) Object(t core.ObjectType, h core.Hash) (Object, error) { // Objects returns an ObjectIter that can step through all of the annotated tags // in the repository. func (r *Repository) Objects() (*ObjectIter, error) { - iter, err := r.s.ObjectStorage().Iter(core.AnyObject) + iter, err := r.s.IterObjects(core.AnyObject) if err != nil { return nil, err } @@ -351,19 +385,19 @@ func (r *Repository) Objects() (*ObjectIter, error) { // Head returns the reference where HEAD is pointing func (r *Repository) Head() (*core.Reference, error) { - return core.ResolveReference(r.s.ReferenceStorage(), core.HEAD) + return core.ResolveReference(r.s, core.HEAD) } // Ref returns the Hash pointing the given refName func (r *Repository) Ref(name core.ReferenceName, resolved bool) (*core.Reference, error) { if resolved { - return core.ResolveReference(r.s.ReferenceStorage(), name) + return core.ResolveReference(r.s, name) } - return r.s.ReferenceStorage().Get(name) + return r.s.Reference(name) } // Refs returns a map with all the References func (r *Repository) Refs() (core.ReferenceIter, error) { - return r.s.ReferenceStorage().Iter() + return r.s.IterReferences() } diff --git a/repository_test.go b/repository_test.go index b67e31d..6c7fe4f 100644 --- a/repository_test.go +++ b/repository_test.go @@ -56,7 +56,7 @@ func (s *RepositorySuite) TestDeleteRemote(c *C) { c.Assert(err, IsNil) alt, err := r.Remote("foo") - c.Assert(err, Equals, config.ErrRemoteConfigNotFound) + c.Assert(err, Equals, ErrRemoteNotFound) c.Assert(alt, IsNil) } @@ -219,7 +219,7 @@ func (s *RepositorySuite) TestPull(c *C) { c.Assert(err, IsNil) c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - storage := r.s.ObjectStorage().(*memory.ObjectStorage) + storage := r.s.(*memory.Storage) c.Assert(storage.Objects, HasLen, 31) r.CreateRemote(&config.RemoteConfig{ diff --git a/storage/filesystem/config.go b/storage/filesystem/config.go index b32265f..4b47937 100644 --- a/storage/filesystem/config.go +++ b/storage/filesystem/config.go @@ -18,70 +18,24 @@ type ConfigStorage struct { dir *dotgit.DotGit } -func (c *ConfigStorage) Remote(name string) (*config.RemoteConfig, error) { - cfg, err := c.read() - if err != nil { - return nil, err - } - - s := cfg.Section(remoteSection) - if !s.HasSubsection(name) { - return nil, config.ErrRemoteConfigNotFound - } +func (c *ConfigStorage) Config() (*config.Config, error) { + cfg := config.NewConfig() - return parseRemote(s.Subsection(name)), nil -} - -func (c *ConfigStorage) Remotes() ([]*config.RemoteConfig, error) { - cfg, err := c.read() + ini, err := c.unmarshal() if err != nil { return nil, err } - remotes := []*config.RemoteConfig{} - sect := cfg.Section(remoteSection) + sect := ini.Section(remoteSection) for _, s := range sect.Subsections { - remotes = append(remotes, parseRemote(s)) - } - - return remotes, nil -} - -func (c *ConfigStorage) SetRemote(r *config.RemoteConfig) error { - if err := r.Validate(); err != nil { - return err + r := c.unmarshalRemote(s) + cfg.Remotes[r.Name] = r } - cfg, err := c.read() - if err != nil { - return err - } - - s := cfg.Section(remoteSection).Subsection(r.Name) - s.Name = r.Name - if r.URL != "" { - s.SetOption(urlKey, r.URL) - } - s.RemoveOption(fetchKey) - for _, rs := range r.Fetch { - s.AddOption(fetchKey, rs.String()) - } - - return c.write(cfg) -} - -func (c *ConfigStorage) DeleteRemote(name string) error { - cfg, err := c.read() - if err != nil { - return err - } - - cfg = cfg.RemoveSubsection(remoteSection, name) - - return c.write(cfg) + return cfg, nil } -func (c *ConfigStorage) read() (*gitconfig.Config, error) { +func (c *ConfigStorage) unmarshal() (*gitconfig.Config, error) { cfg := gitconfig.New() f, err := c.dir.Config() @@ -103,23 +57,7 @@ func (c *ConfigStorage) read() (*gitconfig.Config, error) { return cfg, nil } -func (c *ConfigStorage) write(cfg *gitconfig.Config) error { - f, err := c.dir.ConfigWriter() - if err != nil { - return err - } - - e := gitconfig.NewEncoder(f) - err = e.Encode(cfg) - if err != nil { - f.Close() - return err - } - - return f.Close() -} - -func parseRemote(s *gitconfig.Subsection) *config.RemoteConfig { +func (c *ConfigStorage) unmarshalRemote(s *gitconfig.Subsection) *config.RemoteConfig { fetch := []config.RefSpec{} for _, f := range s.Options.GetAll(fetchKey) { rs := config.RefSpec(f) @@ -134,3 +72,47 @@ func parseRemote(s *gitconfig.Subsection) *config.RemoteConfig { Fetch: fetch, } } + +func (c *ConfigStorage) SetConfig(cfg *config.Config) error { + if err := cfg.Validate(); err != nil { + return err + } + + ini, err := c.unmarshal() + if err != nil { + return err + } + + s := ini.Section(remoteSection) + s.Subsections = make(gitconfig.Subsections, len(cfg.Remotes)) + + var i int + for _, r := range cfg.Remotes { + s.Subsections[i] = c.marshalRemote(r) + i++ + } + + return c.marshal(ini) +} + +func (c *ConfigStorage) marshal(ini *gitconfig.Config) error { + f, err := c.dir.ConfigWriter() + if err != nil { + return err + } + + defer f.Close() + + e := gitconfig.NewEncoder(f) + return e.Encode(ini) +} + +func (c *ConfigStorage) marshalRemote(r *config.RemoteConfig) *gitconfig.Subsection { + s := &gitconfig.Subsection{Name: r.Name} + s.AddOption(urlKey, r.URL) + for _, rs := range r.Fetch { + s.AddOption(fetchKey, rs.String()) + } + + return s +} diff --git a/storage/filesystem/config_test.go b/storage/filesystem/config_test.go index 2eb0ab9..b86eaee 100644 --- a/storage/filesystem/config_test.go +++ b/storage/filesystem/config_test.go @@ -4,7 +4,6 @@ import ( "io/ioutil" stdos "os" - "gopkg.in/src-d/go-git.v4/config" "gopkg.in/src-d/go-git.v4/fixtures" "gopkg.in/src-d/go-git.v4/storage/filesystem/internal/dotgit" "gopkg.in/src-d/go-git.v4/utils/fs/os" @@ -29,27 +28,20 @@ func (s *ConfigSuite) SetUpTest(c *C) { s.path = tmp } -func (s *ConfigSuite) TestSetRemote(c *C) { - cfg := &ConfigStorage{s.dir} - err := cfg.SetRemote(&config.RemoteConfig{Name: "foo", URL: "foo"}) - c.Assert(err, IsNil) - - remote, err := cfg.Remote("foo") - c.Assert(err, IsNil) - c.Assert(remote.Name, Equals, "foo") -} - func (s *ConfigSuite) TestRemotes(c *C) { dir := dotgit.New(fixtures.Basic().ByTag(".git").One().DotGit()) - cfg := &ConfigStorage{dir} + storer := &ConfigStorage{dir} - remotes, err := cfg.Remotes() + cfg, err := storer.Config() c.Assert(err, IsNil) + + remotes := cfg.Remotes c.Assert(remotes, HasLen, 1) - c.Assert(remotes[0].Name, Equals, "origin") - c.Assert(remotes[0].URL, Equals, "https://github.com/git-fixtures/basic") - c.Assert(remotes[0].Fetch, HasLen, 1) - c.Assert(remotes[0].Fetch[0].String(), Equals, "+refs/heads/*:refs/remotes/origin/*") + remote := remotes["origin"] + c.Assert(remote.Name, Equals, "origin") + c.Assert(remote.URL, Equals, "https://github.com/git-fixtures/basic") + c.Assert(remote.Fetch, HasLen, 1) + c.Assert(remote.Fetch[0].String(), Equals, "+refs/heads/*:refs/remotes/origin/*") } func (s *ConfigSuite) TearDownTest(c *C) { diff --git a/storage/filesystem/object.go b/storage/filesystem/object.go index 6dbeae9..f780183 100644 --- a/storage/filesystem/object.go +++ b/storage/filesystem/object.go @@ -13,25 +13,17 @@ import ( "gopkg.in/src-d/go-git.v4/utils/fs" ) -// ObjectStorage is an implementation of core.ObjectStorage that stores -// data on disk in the standard git format (this is, the .git directory). -// -// Zero values of this type are not safe to use, see the New function below. -// -// Currently only reads are supported, no writting. -// -// Also values from this type are not yet able to track changes on disk, this is, -// Gitdir values will get outdated as soon as repositories change on disk. type ObjectStorage struct { dir *dotgit.DotGit index map[core.Hash]index } -func newObjectStorage(dir *dotgit.DotGit) (*ObjectStorage, error) { - s := &ObjectStorage{ +func newObjectStorage(dir *dotgit.DotGit) (ObjectStorage, error) { + s := ObjectStorage{ dir: dir, index: make(map[core.Hash]index, 0), } + return s, s.loadIdxFiles() } @@ -64,8 +56,7 @@ func (s *ObjectStorage) NewObject() core.Object { return &core.MemoryObject{} } -// Writer method not supported on Memory storage -func (s *ObjectStorage) Writer() (io.WriteCloser, error) { +func (s *ObjectStorage) PackfileWriter() (io.WriteCloser, error) { w, err := s.dir.NewObjectPack() if err != nil { return nil, err @@ -82,7 +73,7 @@ func (s *ObjectStorage) Writer() (io.WriteCloser, error) { } // Set adds a new object to the storage. -func (s *ObjectStorage) Set(o core.Object) (core.Hash, error) { +func (s *ObjectStorage) SetObject(o core.Object) (core.Hash, error) { if o.Type() == core.OFSDeltaObject || o.Type() == core.REFDeltaObject { return core.ZeroHash, core.ErrInvalidType } @@ -114,7 +105,7 @@ func (s *ObjectStorage) Set(o core.Object) (core.Hash, error) { // Get returns the object with the given hash, by searching for it in // the packfile and the git object directories. -func (s *ObjectStorage) Get(t core.ObjectType, h core.Hash) (core.Object, error) { +func (s *ObjectStorage) Object(t core.ObjectType, h core.Hash) (core.Object, error) { obj, err := s.getFromUnpacked(h) if err == core.ErrObjectNotFound { obj, err = s.getFromPackfile(h) @@ -183,7 +174,7 @@ func (s *ObjectStorage) getFromPackfile(h core.Hash) (core.Object, error) { defer f.Close() p := packfile.NewScanner(f) - d, err := packfile.NewDecoder(p, memory.NewStorage().ObjectStorage()) + d, err := packfile.NewDecoder(p, memory.NewStorage()) if err != nil { return nil, err } @@ -204,7 +195,7 @@ func (s *ObjectStorage) findObjectInPackfile(h core.Hash) (core.Hash, int64) { // Iter returns an iterator for all the objects in the packfile with the // given type. -func (s *ObjectStorage) Iter(t core.ObjectType) (core.ObjectIter, error) { +func (s *ObjectStorage) IterObjects(t core.ObjectType) (core.ObjectIter, error) { objects, err := s.dir.Objects() if err != nil { return nil, err @@ -251,20 +242,6 @@ func (s *ObjectStorage) buildPackfileIters( return iters, nil } -// Begin opens a new transaction. However, this implementation is not -// transactional, so Commit and Rollback have no effect. -func (o *ObjectStorage) Begin() core.TxObjectStorage { - return o -} - -func (tx *ObjectStorage) Commit() error { - return nil -} - -func (tx *ObjectStorage) Rollback() error { - return nil -} - type index map[core.Hash]int64 func (i index) Decode(r io.Reader) error { @@ -299,7 +276,7 @@ func newPackfileIter(f fs.File, t core.ObjectType, seen map[core.Hash]bool) (cor return nil, err } - d, err := packfile.NewDecoder(s, memory.NewStorage().ObjectStorage()) + d, err := packfile.NewDecoder(s, memory.NewStorage()) if err != nil { return nil, err } diff --git a/storage/filesystem/object_test.go b/storage/filesystem/object_test.go index 0136e54..38e4b6d 100644 --- a/storage/filesystem/object_test.go +++ b/storage/filesystem/object_test.go @@ -20,7 +20,7 @@ func (s *FsSuite) TestGetFromObjectFile(c *C) { c.Assert(err, IsNil) expected := core.NewHash("f3dfe29d268303fc6e1bbce268605fc99573406e") - obj, err := o.Get(core.AnyObject, expected) + obj, err := o.Object(core.AnyObject, expected) c.Assert(err, IsNil) c.Assert(obj.Hash(), Equals, expected) } @@ -32,7 +32,7 @@ func (s *FsSuite) TestGetFromPackfile(c *C) { c.Assert(err, IsNil) expected := core.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - obj, err := o.Get(core.AnyObject, expected) + obj, err := o.Object(core.AnyObject, expected) c.Assert(err, IsNil) c.Assert(obj.Hash(), Equals, expected) }) @@ -60,7 +60,7 @@ func (s *FsSuite) TestIter(c *C) { o, err := newObjectStorage(dotgit.New(fs)) c.Assert(err, IsNil) - iter, err := o.Iter(core.AnyObject) + iter, err := o.IterObjects(core.AnyObject) c.Assert(err, IsNil) var count int32 @@ -80,7 +80,7 @@ func (s *FsSuite) TestIterWithType(c *C) { o, err := newObjectStorage(dotgit.New(fs)) c.Assert(err, IsNil) - iter, err := o.Iter(core.CommitObject) + iter, err := o.IterObjects(core.CommitObject) c.Assert(err, IsNil) err = iter.ForEach(func(o core.Object) error { diff --git a/storage/filesystem/reference.go b/storage/filesystem/reference.go index b2aa6d9..0015859 100644 --- a/storage/filesystem/reference.go +++ b/storage/filesystem/reference.go @@ -9,15 +9,15 @@ type ReferenceStorage struct { dir *dotgit.DotGit } -func (r *ReferenceStorage) Set(ref *core.Reference) error { +func (r *ReferenceStorage) SetReference(ref *core.Reference) error { return r.dir.SetRef(ref) } -func (r *ReferenceStorage) Get(n core.ReferenceName) (*core.Reference, error) { +func (r *ReferenceStorage) Reference(n core.ReferenceName) (*core.Reference, error) { return r.dir.Ref(n) } -func (r *ReferenceStorage) Iter() (core.ReferenceIter, error) { +func (r *ReferenceStorage) IterReferences() (core.ReferenceIter, error) { refs, err := r.dir.Refs() if err != nil { return nil, err diff --git a/storage/filesystem/storage.go b/storage/filesystem/storage.go index d39d6e4..7e05cd3 100644 --- a/storage/filesystem/storage.go +++ b/storage/filesystem/storage.go @@ -2,21 +2,20 @@ package filesystem import ( - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/core" "gopkg.in/src-d/go-git.v4/storage/filesystem/internal/dotgit" "gopkg.in/src-d/go-git.v4/utils/fs" ) +// Storage is an implementation of git.Storer that stores data on disk in the +// standard git format (this is, the .git directory). Zero values of this type +// are not safe to use, see the NewStorage function below. type Storage struct { - dir *dotgit.DotGit - fs fs.Filesystem - - o *ObjectStorage - r *ReferenceStorage - c *ConfigStorage + ObjectStorage + ReferenceStorage + ConfigStorage } +// NewStorage returns a new Storage backed by a given `fs.Filesystem` func NewStorage(fs fs.Filesystem) (*Storage, error) { dir := dotgit.New(fs) o, err := newObjectStorage(dir) @@ -24,27 +23,9 @@ func NewStorage(fs fs.Filesystem) (*Storage, error) { return nil, err } - return &Storage{dir: dir, fs: fs, o: o}, nil -} - -func (s *Storage) ObjectStorage() core.ObjectStorage { - return s.o -} - -func (s *Storage) ReferenceStorage() core.ReferenceStorage { - if s.r != nil { - return s.r - } - - s.r = &ReferenceStorage{dir: s.dir} - return s.r -} - -func (s *Storage) ConfigStorage() config.ConfigStorage { - if s.c != nil { - return s.c - } - - s.c = &ConfigStorage{dir: s.dir} - return s.c + return &Storage{ + ObjectStorage: o, + ReferenceStorage: ReferenceStorage{dir: dir}, + ConfigStorage: ConfigStorage{dir: dir}, + }, nil } diff --git a/storage/filesystem/storage_test.go b/storage/filesystem/storage_test.go index f55452d..c24d5d5 100644 --- a/storage/filesystem/storage_test.go +++ b/storage/filesystem/storage_test.go @@ -18,20 +18,8 @@ type StorageSuite struct { var _ = Suite(&StorageSuite{}) func (s *StorageSuite) SetUpTest(c *C) { - path := c.MkDir() - storage, err := NewStorage(os.New(path)) + storage, err := NewStorage(os.New(c.MkDir())) c.Assert(err, IsNil) - s.BaseStorageSuite = test.NewBaseStorageSuite( - storage.ObjectStorage(), - storage.ReferenceStorage(), - storage.ConfigStorage(), - ) -} - -func (s *StorageSuite) TestTxObjectStorageSetAndCommit(c *C) { - c.Skip("tx not supported") -} -func (s *StorageSuite) TestTxObjectStorageSetAndRollback(c *C) { - c.Skip("tx not supported") + s.BaseStorageSuite = test.NewBaseStorageSuite(storage) } diff --git a/storage/memory/storage.go b/storage/memory/storage.go index 97e87c8..8141cfc 100644 --- a/storage/memory/storage.go +++ b/storage/memory/storage.go @@ -10,96 +10,52 @@ import ( var ErrUnsupportedObjectType = fmt.Errorf("unsupported object type") -// Storage in memory storage system +// Storage is an implementation of git.Storer that stores data on memory, being +// ephemeral. The use of this storage should be done in controlled envoriments, +// since the representation in memory of some repository can fill the machine +// memory. in the other hand this storage has the best performance. type Storage struct { - c *ConfigStorage - o *ObjectStorage - r *ReferenceStorage + ConfigStorage + ObjectStorage + ReferenceStorage } -// NewStorage returns a new Storage +// NewStorage returns a new Storage base on memory func NewStorage() *Storage { - return &Storage{} -} - -// ConfigStorage return the ConfigStorage, if not exists create a new one -func (s *Storage) ConfigStorage() config.ConfigStorage { - if s.c != nil { - return s.c - } - - s.c = &ConfigStorage{ - RemotesConfig: make(map[string]*config.RemoteConfig), - } - - return s.c -} - -// ObjectStorage returns the ObjectStorage, if not exists creates a new one -func (s *Storage) ObjectStorage() core.ObjectStorage { - if s.o != nil { - return s.o - } - - s.o = &ObjectStorage{ - Objects: make(map[core.Hash]core.Object, 0), - Commits: make(map[core.Hash]core.Object, 0), - Trees: make(map[core.Hash]core.Object, 0), - Blobs: make(map[core.Hash]core.Object, 0), - Tags: make(map[core.Hash]core.Object, 0), + return &Storage{ + ReferenceStorage: make(ReferenceStorage, 0), + ConfigStorage: ConfigStorage{}, + ObjectStorage: ObjectStorage{ + Objects: make(map[core.Hash]core.Object, 0), + Commits: make(map[core.Hash]core.Object, 0), + Trees: make(map[core.Hash]core.Object, 0), + Blobs: make(map[core.Hash]core.Object, 0), + Tags: make(map[core.Hash]core.Object, 0), + }, } - - return s.o -} - -// ReferenceStorage returns the ReferenceStorage if not exists creates a new one -func (s *Storage) ReferenceStorage() core.ReferenceStorage { - if s.r != nil { - return s.r - } - - r := make(ReferenceStorage, 0) - s.r = &r - - return s.r } type ConfigStorage struct { - RemotesConfig map[string]*config.RemoteConfig -} - -func (c *ConfigStorage) Remote(name string) (*config.RemoteConfig, error) { - r, ok := c.RemotesConfig[name] - if ok { - return r, nil - } - - return nil, config.ErrRemoteConfigNotFound + config *config.Config } -func (c *ConfigStorage) Remotes() ([]*config.RemoteConfig, error) { - var o []*config.RemoteConfig - for _, r := range c.RemotesConfig { - o = append(o, r) - } - - return o, nil -} -func (c *ConfigStorage) SetRemote(r *config.RemoteConfig) error { - if err := r.Validate(); err != nil { +func (c *ConfigStorage) SetConfig(cfg *config.Config) error { + if err := cfg.Validate(); err != nil { return err } - c.RemotesConfig[r.Name] = r + c.config = cfg return nil } -func (c *ConfigStorage) DeleteRemote(name string) error { - delete(c.RemotesConfig, name) - return nil +func (c *ConfigStorage) Config() (*config.Config, error) { + if c.config == nil { + c.config = config.NewConfig() + } + + return c.config, nil } -// ObjectStorage is the implementation of core.ObjectStorage for memory.Object type ObjectStorage struct { Objects map[core.Hash]core.Object Commits map[core.Hash]core.Object @@ -108,13 +64,11 @@ type ObjectStorage struct { Tags map[core.Hash]core.Object } -// NewObject creates a new MemoryObject func (o *ObjectStorage) NewObject() core.Object { return &core.MemoryObject{} } -// Set stores an object, the object should be properly filled before set it. -func (o *ObjectStorage) Set(obj core.Object) (core.Hash, error) { +func (o *ObjectStorage) SetObject(obj core.Object) (core.Hash, error) { h := obj.Hash() o.Objects[h] = obj @@ -134,8 +88,7 @@ func (o *ObjectStorage) Set(obj core.Object) (core.Hash, error) { return h, nil } -// Get returns a object with the given hash -func (o *ObjectStorage) Get(t core.ObjectType, h core.Hash) (core.Object, error) { +func (o *ObjectStorage) Object(t core.ObjectType, h core.Hash) (core.Object, error) { obj, ok := o.Objects[h] if !ok || (core.AnyObject != t && obj.Type() != t) { return nil, core.ErrObjectNotFound @@ -144,8 +97,7 @@ func (o *ObjectStorage) Get(t core.ObjectType, h core.Hash) (core.Object, error) return obj, nil } -// Iter returns a core.ObjectIter for the given core.ObjectTybe -func (o *ObjectStorage) Iter(t core.ObjectType) (core.ObjectIter, error) { +func (o *ObjectStorage) IterObjects(t core.ObjectType) (core.ObjectIter, error) { var series []core.Object switch t { case core.AnyObject: @@ -171,7 +123,7 @@ func flattenObjectMap(m map[core.Hash]core.Object) []core.Object { return objects } -func (o *ObjectStorage) Begin() core.TxObjectStorage { +func (o *ObjectStorage) Begin() core.Transaction { return &TxObjectStorage{ Storage: o, Objects: make(map[core.Hash]core.Object, 0), @@ -183,14 +135,14 @@ type TxObjectStorage struct { Objects map[core.Hash]core.Object } -func (tx *TxObjectStorage) Set(obj core.Object) (core.Hash, error) { +func (tx *TxObjectStorage) SetObject(obj core.Object) (core.Hash, error) { h := obj.Hash() tx.Objects[h] = obj return h, nil } -func (tx *TxObjectStorage) Get(t core.ObjectType, h core.Hash) (core.Object, error) { +func (tx *TxObjectStorage) Object(t core.ObjectType, h core.Hash) (core.Object, error) { obj, ok := tx.Objects[h] if !ok || (core.AnyObject != t && obj.Type() != t) { return nil, core.ErrObjectNotFound @@ -202,7 +154,7 @@ func (tx *TxObjectStorage) Get(t core.ObjectType, h core.Hash) (core.Object, err func (tx *TxObjectStorage) Commit() error { for h, obj := range tx.Objects { delete(tx.Objects, h) - if _, err := tx.Storage.Set(obj); err != nil { + if _, err := tx.Storage.SetObject(obj); err != nil { return err } } @@ -217,8 +169,7 @@ func (tx *TxObjectStorage) Rollback() error { type ReferenceStorage map[core.ReferenceName]*core.Reference -// Set stores a reference. -func (r ReferenceStorage) Set(ref *core.Reference) error { +func (r ReferenceStorage) SetReference(ref *core.Reference) error { if ref != nil { r[ref.Name()] = ref } @@ -226,8 +177,7 @@ func (r ReferenceStorage) Set(ref *core.Reference) error { return nil } -// Get returns a stored reference with the given name -func (r ReferenceStorage) Get(n core.ReferenceName) (*core.Reference, error) { +func (r ReferenceStorage) Reference(n core.ReferenceName) (*core.Reference, error) { ref, ok := r[n] if !ok { return nil, core.ErrReferenceNotFound @@ -236,8 +186,7 @@ func (r ReferenceStorage) Get(n core.ReferenceName) (*core.Reference, error) { return ref, nil } -// Iter returns a core.ReferenceIter -func (r ReferenceStorage) Iter() (core.ReferenceIter, error) { +func (r ReferenceStorage) IterReferences() (core.ReferenceIter, error) { var refs []*core.Reference for _, ref := range r { refs = append(refs, ref) diff --git a/storage/memory/storage_test.go b/storage/memory/storage_test.go index e1d5a33..ee8fa93 100644 --- a/storage/memory/storage_test.go +++ b/storage/memory/storage_test.go @@ -16,34 +16,5 @@ type StorageSuite struct { var _ = Suite(&StorageSuite{}) func (s *StorageSuite) SetUpTest(c *C) { - storage := NewStorage() - s.BaseStorageSuite = test.NewBaseStorageSuite( - storage.ObjectStorage(), - storage.ReferenceStorage(), - storage.ConfigStorage(), - ) -} - -func (s *StorageSuite) TestStorageObjectStorage(c *C) { - storage := NewStorage() - o := storage.ObjectStorage() - e := storage.ObjectStorage() - - c.Assert(o == e, Equals, true) -} - -func (s *StorageSuite) TestStorageReferenceStorage(c *C) { - storage := NewStorage() - o := storage.ReferenceStorage() - e := storage.ReferenceStorage() - - c.Assert(o == e, Equals, true) -} - -func (s *StorageSuite) TestStorageConfigStorage(c *C) { - storage := NewStorage() - o := storage.ConfigStorage() - e := storage.ConfigStorage() - - c.Assert(o == e, Equals, true) + s.BaseStorageSuite = test.NewBaseStorageSuite(NewStorage()) } diff --git a/storage/test/storage_suite.go b/storage/test/storage_suite.go index 8686853..451528f 100644 --- a/storage/test/storage_suite.go +++ b/storage/test/storage_suite.go @@ -6,7 +6,6 @@ import ( "fmt" "io" "io/ioutil" - "sort" "gopkg.in/src-d/go-git.v4/config" "gopkg.in/src-d/go-git.v4/core" @@ -14,6 +13,12 @@ import ( . "gopkg.in/check.v1" ) +type storer interface { + core.ObjectStorer + core.ReferenceStorer + config.ConfigStorer +} + type TestObject struct { Object core.Object Hash string @@ -21,19 +26,13 @@ type TestObject struct { } type BaseStorageSuite struct { - ObjectStorage core.ObjectStorage - ReferenceStorage core.ReferenceStorage - ConfigStore config.ConfigStorage + Storer storer validTypes []core.ObjectType testObjects map[core.ObjectType]TestObject } -func NewBaseStorageSuite( - os core.ObjectStorage, - rs core.ReferenceStorage, - cs config.ConfigStorage, -) BaseStorageSuite { +func NewBaseStorageSuite(s storer) BaseStorageSuite { commit := &core.MemoryObject{} commit.SetType(core.CommitObject) tree := &core.MemoryObject{} @@ -44,10 +43,7 @@ func NewBaseStorageSuite( tag.SetType(core.TagObject) return BaseStorageSuite{ - ObjectStorage: os, - ReferenceStorage: rs, - ConfigStore: cs, - + Storer: s, validTypes: []core.ObjectType{ core.CommitObject, core.BlobObject, @@ -62,19 +58,19 @@ func NewBaseStorageSuite( }} } -func (s *BaseStorageSuite) TestObjectStorageSetAndGet(c *C) { +func (s *BaseStorageSuite) TestSetObjectAndGetObject(c *C) { for _, to := range s.testObjects { comment := Commentf("failed for type %s", to.Type.String()) - h, err := s.ObjectStorage.Set(to.Object) + h, err := s.Storer.SetObject(to.Object) c.Assert(err, IsNil) c.Assert(h.String(), Equals, to.Hash, comment) - o, err := s.ObjectStorage.Get(to.Type, h) + o, err := s.Storer.Object(to.Type, h) c.Assert(err, IsNil) c.Assert(objectEquals(o, to.Object), IsNil) - o, err = s.ObjectStorage.Get(core.AnyObject, h) + o, err = s.Storer.Object(core.AnyObject, h) c.Assert(err, IsNil) c.Assert(objectEquals(o, to.Object), IsNil) @@ -83,31 +79,31 @@ func (s *BaseStorageSuite) TestObjectStorageSetAndGet(c *C) { continue } - o, err = s.ObjectStorage.Get(t, h) + o, err = s.Storer.Object(t, h) c.Assert(o, IsNil) c.Assert(err, Equals, core.ErrObjectNotFound) } } } -func (s *BaseStorageSuite) TestObjectStorageGetInvalid(c *C) { - o := s.ObjectStorage.NewObject() +func (s *BaseStorageSuite) TestSetObjectInvalid(c *C) { + o := s.Storer.NewObject() o.SetType(core.REFDeltaObject) - _, err := s.ObjectStorage.Set(o) + _, err := s.Storer.SetObject(o) c.Assert(err, NotNil) } -func (s *BaseStorageSuite) TestObjectStorageIter(c *C) { +func (s *BaseStorageSuite) TestStorerIter(c *C) { for _, o := range s.testObjects { - h, err := s.ObjectStorage.Set(o.Object) + h, err := s.Storer.SetObject(o.Object) c.Assert(err, IsNil) c.Assert(h, Equals, o.Object.Hash()) } for _, t := range s.validTypes { comment := Commentf("failed for type %s)", t.String()) - i, err := s.ObjectStorage.Iter(t) + i, err := s.Storer.IterObjects(t) c.Assert(err, IsNil, comment) o, err := i.Next() @@ -119,7 +115,7 @@ func (s *BaseStorageSuite) TestObjectStorageIter(c *C) { c.Assert(err, Equals, io.EOF, comment) } - i, err := s.ObjectStorage.Iter(core.AnyObject) + i, err := s.Storer.IterObjects(core.AnyObject) c.Assert(err, IsNil) foundObjects := []core.Object{} @@ -141,15 +137,20 @@ func (s *BaseStorageSuite) TestObjectStorageIter(c *C) { } } -func (s *BaseStorageSuite) TestTxObjectStorageSetAndCommit(c *C) { - tx := s.ObjectStorage.Begin() +func (s *BaseStorageSuite) TestObjectStorerTxSetObjectAndCommit(c *C) { + storer, ok := s.Storer.(core.Transactioner) + if !ok { + c.Skip("not a core.ObjectStorerTx") + } + + tx := storer.Begin() for _, o := range s.testObjects { - h, err := tx.Set(o.Object) + h, err := tx.SetObject(o.Object) c.Assert(err, IsNil) c.Assert(h.String(), Equals, o.Hash) } - iter, err := s.ObjectStorage.Iter(core.AnyObject) + iter, err := s.Storer.IterObjects(core.AnyObject) c.Assert(err, IsNil) _, err = iter.Next() c.Assert(err, Equals, io.EOF) @@ -157,7 +158,7 @@ func (s *BaseStorageSuite) TestTxObjectStorageSetAndCommit(c *C) { err = tx.Commit() c.Assert(err, IsNil) - iter, err = s.ObjectStorage.Iter(core.AnyObject) + iter, err = s.Storer.IterObjects(core.AnyObject) c.Assert(err, IsNil) var count int @@ -169,29 +170,44 @@ func (s *BaseStorageSuite) TestTxObjectStorageSetAndCommit(c *C) { c.Assert(count, Equals, 4) } -func (s *BaseStorageSuite) TestTxObjectStorageSetAndGet(c *C) { - tx := s.ObjectStorage.Begin() +func (s *BaseStorageSuite) TestObjectStorerTxSetObjectAndGetObject(c *C) { + storer, ok := s.Storer.(core.Transactioner) + if !ok { + c.Skip("not a core.ObjectStorerTx") + } + + tx := storer.Begin() for _, expected := range s.testObjects { - h, err := tx.Set(expected.Object) + h, err := tx.SetObject(expected.Object) c.Assert(err, IsNil) c.Assert(h.String(), Equals, expected.Hash) - o, err := tx.Get(expected.Type, core.NewHash(expected.Hash)) + o, err := tx.Object(expected.Type, core.NewHash(expected.Hash)) c.Assert(o.Hash().String(), DeepEquals, expected.Hash) } } -func (s *BaseStorageSuite) TestTxObjectStorageGetNotFound(c *C) { - tx := s.ObjectStorage.Begin() - o, err := tx.Get(core.AnyObject, core.ZeroHash) +func (s *BaseStorageSuite) TestObjectStorerTxGetObjectNotFound(c *C) { + storer, ok := s.Storer.(core.Transactioner) + if !ok { + c.Skip("not a core.ObjectStorerTx") + } + + tx := storer.Begin() + o, err := tx.Object(core.AnyObject, core.ZeroHash) c.Assert(o, IsNil) c.Assert(err, Equals, core.ErrObjectNotFound) } -func (s *BaseStorageSuite) TestTxObjectStorageSetAndRollback(c *C) { - tx := s.ObjectStorage.Begin() +func (s *BaseStorageSuite) TestObjectStorerTxSetObjectAndRollback(c *C) { + storer, ok := s.Storer.(core.Transactioner) + if !ok { + c.Skip("not a core.ObjectStorerTx") + } + + tx := storer.Begin() for _, o := range s.testObjects { - h, err := tx.Set(o.Object) + h, err := tx.SetObject(o.Object) c.Assert(err, IsNil) c.Assert(h.String(), Equals, o.Hash) } @@ -199,41 +215,41 @@ func (s *BaseStorageSuite) TestTxObjectStorageSetAndRollback(c *C) { err := tx.Rollback() c.Assert(err, IsNil) - iter, err := s.ObjectStorage.Iter(core.AnyObject) + iter, err := s.Storer.IterObjects(core.AnyObject) c.Assert(err, IsNil) _, err = iter.Next() c.Assert(err, Equals, io.EOF) } -func (s *BaseStorageSuite) TestReferenceStorageSetAndGet(c *C) { - err := s.ReferenceStorage.Set( +func (s *BaseStorageSuite) TestSetReferenceAndGetReference(c *C) { + err := s.Storer.SetReference( core.NewReferenceFromStrings("foo", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52"), ) c.Assert(err, IsNil) - err = s.ReferenceStorage.Set( + err = s.Storer.SetReference( core.NewReferenceFromStrings("bar", "482e0eada5de4039e6f216b45b3c9b683b83bfa"), ) c.Assert(err, IsNil) - e, err := s.ReferenceStorage.Get(core.ReferenceName("foo")) + e, err := s.Storer.Reference(core.ReferenceName("foo")) c.Assert(err, IsNil) c.Assert(e.Hash().String(), Equals, "bc9968d75e48de59f0870ffb71f5e160bbbdcf52") } -func (s *BaseStorageSuite) TestReferenceStorageGetNotFound(c *C) { - r, err := s.ReferenceStorage.Get(core.ReferenceName("bar")) +func (s *BaseStorageSuite) TestGetReferenceNotFound(c *C) { + r, err := s.Storer.Reference(core.ReferenceName("bar")) c.Assert(err, Equals, core.ErrReferenceNotFound) c.Assert(r, IsNil) } -func (s *BaseStorageSuite) TestReferenceStorageIter(c *C) { - err := s.ReferenceStorage.Set( +func (s *BaseStorageSuite) TestIterReferences(c *C) { + err := s.Storer.SetReference( core.NewReferenceFromStrings("refs/foo", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52"), ) c.Assert(err, IsNil) - i, err := s.ReferenceStorage.Iter() + i, err := s.Storer.IterReferences() c.Assert(err, IsNil) e, err := i.Next() @@ -245,50 +261,27 @@ func (s *BaseStorageSuite) TestReferenceStorageIter(c *C) { c.Assert(err, Equals, io.EOF) } -func (s *BaseStorageSuite) TestConfigStorageSetGetAndDelete(c *C) { - err := s.ConfigStore.SetRemote(&config.RemoteConfig{ +func (s *BaseStorageSuite) TestSetConfigAndConfig(c *C) { + expected := config.NewConfig() + expected.Remotes["foo"] = &config.RemoteConfig{ Name: "foo", URL: "http://foo/bar.git", - }) - - c.Assert(err, IsNil) + } - r, err := s.ConfigStore.Remote("foo") + err := s.Storer.SetConfig(expected) c.Assert(err, IsNil) - c.Assert(r.Name, Equals, "foo") - err = s.ConfigStore.DeleteRemote("foo") + cfg, err := s.Storer.Config() c.Assert(err, IsNil) - - r, err = s.ConfigStore.Remote("foo") - c.Assert(err, Equals, config.ErrRemoteConfigNotFound) - c.Assert(r, IsNil) -} - -func (s *BaseStorageSuite) TestConfigStorageSetInvalid(c *C) { - err := s.ConfigStore.SetRemote(&config.RemoteConfig{}) - c.Assert(err, NotNil) + c.Assert(cfg, DeepEquals, expected) } -func (s *BaseStorageSuite) TestConfigStorageRemotes(c *C) { - s.ConfigStore.SetRemote(&config.RemoteConfig{ - Name: "foo", URL: "http://foo/bar.git", - }) - - s.ConfigStore.SetRemote(&config.RemoteConfig{ - Name: "bar", URL: "http://foo/bar.git", - }) +func (s *BaseStorageSuite) TestSetConfigInvalid(c *C) { + cfg := config.NewConfig() + cfg.Remotes["foo"] = &config.RemoteConfig{} - r, err := s.ConfigStore.Remotes() - c.Assert(err, IsNil) - c.Assert(r, HasLen, 2) - - sorted := make([]string, 0, 2) - sorted = append(sorted, r[0].Name) - sorted = append(sorted, r[1].Name) - sort.Strings(sorted) - c.Assert(sorted[0], Equals, "bar") - c.Assert(sorted[1], Equals, "foo") + err := s.Storer.SetConfig(cfg) + c.Assert(err, NotNil) } func objectEquals(a core.Object, b core.Object) error { diff --git a/tag_test.go b/tag_test.go index 5957678..811fee7 100644 --- a/tag_test.go +++ b/tag_test.go @@ -115,7 +115,7 @@ func (s *TagSuite) TestObject(c *C) { func (s *TagSuite) TestTagItter(c *C) { r := s.Repositories["https://github.com/git-fixtures/tags.git"] - iter, err := r.s.ObjectStorage().Iter(core.TagObject) + iter, err := r.s.IterObjects(core.TagObject) c.Assert(err, IsNil) var count int @@ -131,7 +131,7 @@ func (s *TagSuite) TestTagItter(c *C) { func (s *TagSuite) TestTagIterError(c *C) { r := s.Repositories["https://github.com/git-fixtures/tags.git"] - iter, err := r.s.ObjectStorage().Iter(core.TagObject) + iter, err := r.s.IterObjects(core.TagObject) c.Assert(err, IsNil) i := NewTagIter(r, iter) @@ -51,7 +51,7 @@ func (t *Tree) File(path string) (*File, error) { return nil, ErrFileNotFound } - obj, err := t.r.s.ObjectStorage().Get(core.BlobObject, e.Hash) + obj, err := t.r.s.Object(core.BlobObject, e.Hash) if err != nil { return nil, err } @@ -84,7 +84,7 @@ func (t *Tree) dir(baseName string) (*Tree, error) { return nil, errDirNotFound } - obj, err := t.r.s.ObjectStorage().Get(core.TreeObject, entry.Hash) + obj, err := t.r.s.Object(core.TreeObject, entry.Hash) if err != nil { return nil, err } diff --git a/tree_test.go b/tree_test.go index 86b4851..3220490 100644 --- a/tree_test.go +++ b/tree_test.go @@ -37,7 +37,7 @@ func (s *TreeSuite) TestDecode(c *C) { func (s *TreeSuite) TestDecodeNonTree(c *C) { hash := core.NewHash("9a48f23120e880dfbe41f7c9b7b708e9ee62a492") - blob, err := s.Repository.s.ObjectStorage().Get(core.BlobObject, hash) + blob, err := s.Repository.s.Object(core.BlobObject, hash) c.Assert(err, IsNil) tree := &Tree{} @@ -89,12 +89,12 @@ func (o *SortReadObject) SetType(t core.ObjectType) { o.t = t } func (o *SortReadObject) Size() int64 { return o.sz } func (o *SortReadObject) SetSize(s int64) { o.sz = s } func (o *SortReadObject) Content() []byte { return o.cont } -func (o *SortReadObject) Reader() (core.ObjectReader, error) { +func (o *SortReadObject) Reader() (io.ReadCloser, error) { return &SortReadCloser{pos: 0, data: o.cont}, nil } -func (o *SortReadObject) Writer() (core.ObjectWriter, error) { return o, nil } -func (o *SortReadObject) Write(p []byte) (n int, err error) { return len(p), nil } -func (o *SortReadObject) Close() error { return nil } +func (o *SortReadObject) Writer() (io.WriteCloser, error) { return o, nil } +func (o *SortReadObject) Write(p []byte) (n int, err error) { return len(p), nil } +func (o *SortReadObject) Close() error { return nil } // a ReadCloser that only returns 6 bytes at a time, to simulate incomplete reads. type SortReadCloser struct { |