diff --git a/Gopkg.lock b/Gopkg.lock index c6dff68ee..de17ef3c7 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -613,7 +613,7 @@ version = "v3.1.1" [[projects]] - digest = "1:2575e0987bd652097e3921a4713b886f786483fecac75ca0707cf7dad26424f3" + digest = "1:a72d911e18578e34367f4b849340501c7e6a2787a3a05651b3d53c6cb96990f4" name = "gopkg.in/src-d/go-git.v4" packages = [ ".", @@ -658,12 +658,12 @@ "utils/merkletrie/noder", ] pruneopts = "" - revision = "3dbfb89e0f5bce0008724e547b999fe3af9f60db" + revision = "a1f6ef44dfed1253ef7f3bc049f66b15f8fc2ab2" source = "github.com/src-d/go-git" - version = "v4.8.1" + version = "v4.9.1" [[projects]] - digest = "1:5ca66c5e97c9416cbc987566baa52f838fec2fc78cfccba2b5a690171921030b" + digest = "1:bfdfff30b5303aefc606eb7219da01d92c805bd123bd3dd4f4a0e303af80e03d" name = "gopkg.in/src-d/go-mysql-server.v0" packages = [ ".", @@ -682,7 +682,7 @@ "sql/plan", ] pruneopts = "NT" - revision = "5a9075414ef5cc7799a551289f81cd6d34242eaf" + revision = "31ad0f968a8823de219f1db70e2b4890f06ff48b" [[projects]] digest = "1:f995136b53497081f1b3f29b99e78a597da6afb2bc6f22908382559a863df4ea" diff --git a/Gopkg.toml b/Gopkg.toml index 722ba77c6..05b64ece0 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -1,6 +1,6 @@ [[constraint]] name = "gopkg.in/src-d/go-mysql-server.v0" - revision = "5a9075414ef5cc7799a551289f81cd6d34242eaf" + revision = "31ad0f968a8823de219f1db70e2b4890f06ff48b" [[constraint]] name = "github.com/jessevdk/go-flags" @@ -17,7 +17,7 @@ [[constraint]] name = "gopkg.in/src-d/go-git.v4" source = "github.com/src-d/go-git" - version = "4.8.1" + version = "4.9.1" [[constraint]] name = "gopkg.in/src-d/go-git-fixtures.v3" diff --git a/docs/using-gitbase/functions.md b/docs/using-gitbase/functions.md index 1f4456904..591da0917 100644 --- a/docs/using-gitbase/functions.md +++ b/docs/using-gitbase/functions.md @@ -95,4 +95,4 @@ Also, if you want to retrieve values from a non common property, you can pass it ## Standard functions -You can check standard functions in [`go-mysql-server` documentation](https://github.com/src-d/go-mysql-server/tree/5a9075414ef5cc7799a551289f81cd6d34242eaf#custom-functions). +You can check standard functions in [`go-mysql-server` documentation](https://github.com/src-d/go-mysql-server/tree/31ad0f968a8823de219f1db70e2b4890f06ff48b#custom-functions). diff --git a/docs/using-gitbase/indexes.md b/docs/using-gitbase/indexes.md index e07cb8404..293074da3 100644 --- a/docs/using-gitbase/indexes.md +++ b/docs/using-gitbase/indexes.md @@ -26,4 +26,4 @@ and for the second query also two indexes will be used and the result will be a You can find some more examples in the [examples](./examples.md#create-an-index-for-columns-on-a-table) section. -See [go-mysql-server](https://github.com/src-d/go-mysql-server/tree/5a9075414ef5cc7799a551289f81cd6d34242eaf#indexes) documentation for more details +See [go-mysql-server](https://github.com/src-d/go-mysql-server/tree/31ad0f968a8823de219f1db70e2b4890f06ff48b#indexes) documentation for more details diff --git a/docs/using-gitbase/supported-clients.md b/docs/using-gitbase/supported-clients.md index ae0c868b9..379de5d1d 100644 --- a/docs/using-gitbase/supported-clients.md +++ b/docs/using-gitbase/supported-clients.md @@ -1,3 +1,3 @@ ## Supported clients -To see the supported MySQL clients and examples about how to use them, take a look [here](https://github.com/src-d/go-mysql-server/blob/5a9075414ef5cc7799a551289f81cd6d34242eaf/SUPPORTED_CLIENTS.md). +To see the supported MySQL clients and examples about how to use them, take a look [here](https://github.com/src-d/go-mysql-server/blob/31ad0f968a8823de219f1db70e2b4890f06ff48b/SUPPORTED_CLIENTS.md). diff --git a/docs/using-gitbase/supported-syntax.md b/docs/using-gitbase/supported-syntax.md index 08a10b28f..cafea836a 100644 --- a/docs/using-gitbase/supported-syntax.md +++ b/docs/using-gitbase/supported-syntax.md @@ -1,3 +1,3 @@ ## Supported syntax -To see the SQL subset currently supported take a look at [this list](https://github.com/src-d/go-mysql-server/blob/5a9075414ef5cc7799a551289f81cd6d34242eaf/SUPPORTED.md) from [src-d/go-mysql-server](https://github.com/src-d/go-mysql-server). +To see the SQL subset currently supported take a look at [this list](https://github.com/src-d/go-mysql-server/blob/31ad0f968a8823de219f1db70e2b4890f06ff48b/SUPPORTED.md) from [src-d/go-mysql-server](https://github.com/src-d/go-mysql-server). diff --git a/vendor/gopkg.in/src-d/go-git.v4/options.go b/vendor/gopkg.in/src-d/go-git.v4/options.go index 5d10a88c3..ed7689ab3 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/options.go +++ b/vendor/gopkg.in/src-d/go-git.v4/options.go @@ -335,6 +335,11 @@ type LogOptions struct { // Show only those commits in which the specified file was inserted/updated. // It is equivalent to running `git log -- `. FileName *string + + // Pretend as if all the refs in refs/, along with HEAD, are listed on the command line as . + // It is equivalent to running `git log --all`. + // If set on true, the From option will be ignored. + All bool } var ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common.go index 2b4acebde..0d9ed5447 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common.go @@ -51,7 +51,13 @@ func WritePackfileToObjectStorage( } defer ioutil.CheckClose(w, &err) - _, err = io.Copy(w, packfile) + + var n int64 + n, err = io.Copy(w, packfile) + if err == nil && n == 0 { + return ErrEmptyPackfile + } + return err } diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common_test.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common_test.go index 387c0d1a1..eafc61726 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common_test.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common_test.go @@ -1,15 +1,29 @@ package packfile import ( + "bytes" "testing" "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/storage/memory" . "gopkg.in/check.v1" ) func Test(t *testing.T) { TestingT(t) } +type CommonSuite struct{} + +var _ = Suite(&CommonSuite{}) + +func (s *CommonSuite) TestEmptyUpdateObjectStorage(c *C) { + var buf bytes.Buffer + sto := memory.NewStorage() + + err := UpdateObjectStorage(sto, &buf) + c.Assert(err, Equals, ErrEmptyPackfile) +} + func newObject(t plumbing.ObjectType, cont []byte) plumbing.EncodedObject { o := plumbing.MemoryObject{} o.SetType(t) diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/fsobject.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/fsobject.go index 330cb73c9..a268bce7e 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/fsobject.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/fsobject.go @@ -48,7 +48,7 @@ func NewFSObject( // Reader implements the plumbing.EncodedObject interface. func (o *FSObject) Reader() (io.ReadCloser, error) { obj, ok := o.cache.Get(o.hash) - if ok { + if ok && obj != o { reader, err := obj.Reader() if err != nil { return nil, err diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/packfile.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/packfile.go index 2166e0aa2..1e7ef2694 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/packfile.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/packfile.go @@ -21,6 +21,16 @@ var ( ErrZLib = NewError("zlib reading error") ) +// When reading small objects from packfile it is beneficial to do so at +// once to exploit the buffered I/O. In many cases the objects are so small +// that they were already loaded to memory when the object header was +// loaded from the packfile. Wrapping in FSObject would cause this buffered +// data to be thrown away and then re-read later, with the additional +// seeking causing reloads from disk. Objects smaller than this threshold +// are now always read into memory and stored in cache instead of being +// wrapped in FSObject. +const smallObjectThreshold = 16 * 1024 + // Packfile allows retrieving information from inside a packfile. type Packfile struct { idxfile.Index @@ -79,15 +89,7 @@ func (p *Packfile) GetByOffset(o int64) (plumbing.EncodedObject, error) { } } - if _, err := p.s.SeekFromStart(o); err != nil { - if err == io.EOF || isInvalid(err) { - return nil, plumbing.ErrObjectNotFound - } - - return nil, err - } - - return p.nextObject() + return p.objectAtOffset(o) } // GetSizeByOffset retrieves the size of the encoded object from the @@ -108,6 +110,12 @@ func (p *Packfile) GetSizeByOffset(o int64) (size int64, err error) { return h.Length, nil } +func (p *Packfile) objectHeaderAtOffset(offset int64) (*ObjectHeader, error) { + h, err := p.s.SeekObjectHeader(offset) + p.s.pendingObject = nil + return h, err +} + func (p *Packfile) nextObjectHeader() (*ObjectHeader, error) { h, err := p.s.NextObjectHeader() p.s.pendingObject = nil @@ -154,11 +162,7 @@ func (p *Packfile) getObjectType(h *ObjectHeader) (typ plumbing.ObjectType, err if baseType, ok := p.offsetToType[offset]; ok { typ = baseType } else { - if _, err = p.s.SeekFromStart(offset); err != nil { - return - } - - h, err = p.nextObjectHeader() + h, err = p.objectHeaderAtOffset(offset) if err != nil { return } @@ -175,8 +179,8 @@ func (p *Packfile) getObjectType(h *ObjectHeader) (typ plumbing.ObjectType, err return } -func (p *Packfile) nextObject() (plumbing.EncodedObject, error) { - h, err := p.nextObjectHeader() +func (p *Packfile) objectAtOffset(offset int64) (plumbing.EncodedObject, error) { + h, err := p.objectHeaderAtOffset(offset) if err != nil { if err == io.EOF || isInvalid(err) { return nil, plumbing.ErrObjectNotFound @@ -190,6 +194,13 @@ func (p *Packfile) nextObject() (plumbing.EncodedObject, error) { return p.getNextObject(h) } + // If the object is not a delta and it's small enough then read it + // completely into memory now since it is already read from disk + // into buffer anyway. + if h.Length <= smallObjectThreshold && h.Type != plumbing.OFSDeltaObject && h.Type != plumbing.REFDeltaObject { + return p.getNextObject(h) + } + hash, err := p.FindHash(h.Offset) if err != nil { return nil, err @@ -233,11 +244,7 @@ func (p *Packfile) getObjectContent(offset int64) (io.ReadCloser, error) { } } - if _, err := p.s.SeekFromStart(offset); err != nil { - return nil, err - } - - h, err := p.nextObjectHeader() + h, err := p.objectHeaderAtOffset(offset) if err != nil { return nil, err } @@ -329,8 +336,6 @@ func (p *Packfile) fillOFSDeltaObjectContent(obj plumbing.EncodedObject, offset if err != nil { return err } - - p.cachePut(base) } obj.SetType(base.Type()) diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/parser.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/parser.go index 5a62d63bb..71cbba983 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/parser.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/parser.go @@ -398,11 +398,7 @@ func (p *Parser) readData(o *objectInfo) ([]byte, error) { return data, nil } - if _, err := p.scanner.SeekFromStart(o.Offset); err != nil { - return nil, err - } - - if _, err := p.scanner.NextObjectHeader(); err != nil { + if _, err := p.scanner.SeekObjectHeader(o.Offset); err != nil { return nil, err } diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go index 6fc183b94..614b0d1a8 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go @@ -138,14 +138,52 @@ func (s *Scanner) readCount() (uint32, error) { return binary.ReadUint32(s.r) } +// SeekObjectHeader seeks to specified offset and returns the ObjectHeader +// for the next object in the reader +func (s *Scanner) SeekObjectHeader(offset int64) (*ObjectHeader, error) { + // if seeking we assume that you are not interested in the header + if s.version == 0 { + s.version = VersionSupported + } + + if _, err := s.r.Seek(offset, io.SeekStart); err != nil { + return nil, err + } + + h, err := s.nextObjectHeader() + if err != nil { + return nil, err + } + + h.Offset = offset + return h, nil +} + // NextObjectHeader returns the ObjectHeader for the next object in the reader func (s *Scanner) NextObjectHeader() (*ObjectHeader, error) { - defer s.Flush() - if err := s.doPending(); err != nil { return nil, err } + offset, err := s.r.Seek(0, io.SeekCurrent) + if err != nil { + return nil, err + } + + h, err := s.nextObjectHeader() + if err != nil { + return nil, err + } + + h.Offset = offset + return h, nil +} + +// nextObjectHeader returns the ObjectHeader for the next object in the reader +// without the Offset field +func (s *Scanner) nextObjectHeader() (*ObjectHeader, error) { + defer s.Flush() + s.crc.Reset() h := &ObjectHeader{} @@ -308,7 +346,7 @@ var byteSlicePool = sync.Pool{ // SeekFromStart sets a new offset from start, returns the old position before // the change. func (s *Scanner) SeekFromStart(offset int64) (previous int64, err error) { - // if seeking we assume that you are not interested on the header + // if seeking we assume that you are not interested in the header if s.version == 0 { s.version = VersionSupported } @@ -385,7 +423,7 @@ type bufferedSeeker struct { } func (r *bufferedSeeker) Seek(offset int64, whence int) (int64, error) { - if whence == io.SeekCurrent { + if whence == io.SeekCurrent && offset == 0 { current, err := r.r.Seek(offset, whence) if err != nil { return current, err diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner_test.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner_test.go index 644d0eb1d..091b457c0 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner_test.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner_test.go @@ -118,6 +118,23 @@ func (s *ScannerSuite) TestNextObjectHeaderWithOutReadObjectNonSeekable(c *C) { c.Assert(n, Equals, f.PackfileHash) } +func (s *ScannerSuite) TestSeekObjectHeader(c *C) { + r := fixtures.Basic().One().Packfile() + p := NewScanner(r) + + h, err := p.SeekObjectHeader(expectedHeadersOFS[4].Offset) + c.Assert(err, IsNil) + c.Assert(h, DeepEquals, &expectedHeadersOFS[4]) +} + +func (s *ScannerSuite) TestSeekObjectHeaderNonSeekable(c *C) { + r := io.MultiReader(fixtures.Basic().One().Packfile()) + p := NewScanner(r) + + _, err := p.SeekObjectHeader(expectedHeadersOFS[4].Offset) + c.Assert(err, Equals, ErrSeekNotSupported) +} + var expectedHeadersOFS = []ObjectHeader{ {Type: plumbing.CommitObject, Offset: 12, Length: 254}, {Type: plumbing.OFSDeltaObject, Offset: 186, Length: 93, OffsetReference: 12}, diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker.go index 40ad2582b..8c76557c4 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker.go @@ -1,10 +1,12 @@ package object import ( + "container/list" "io" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/storer" + "gopkg.in/src-d/go-git.v4/storage" ) type commitPreIterator struct { @@ -181,3 +183,133 @@ func (w *commitPostIterator) ForEach(cb func(*Commit) error) error { } func (w *commitPostIterator) Close() {} + +// commitAllIterator stands for commit iterator for all refs. +type commitAllIterator struct { + // currCommit points to the current commit. + currCommit *list.Element +} + +// NewCommitAllIter returns a new commit iterator for all refs. +// repoStorer is a repo Storer used to get commits and references. +// commitIterFunc is a commit iterator function, used to iterate through ref commits in chosen order +func NewCommitAllIter(repoStorer storage.Storer, commitIterFunc func(*Commit) CommitIter) (CommitIter, error) { + commitsPath := list.New() + commitsLookup := make(map[plumbing.Hash]*list.Element) + head, err := storer.ResolveReference(repoStorer, plumbing.HEAD) + if err != nil { + return nil, err + } + + // add all references along with the HEAD + if err = addReference(repoStorer, commitIterFunc, head, commitsPath, commitsLookup); err != nil { + return nil, err + } + refIter, err := repoStorer.IterReferences() + if err != nil { + return nil, err + } + defer refIter.Close() + err = refIter.ForEach( + func(ref *plumbing.Reference) error { + return addReference(repoStorer, commitIterFunc, ref, commitsPath, commitsLookup) + }, + ) + if err != nil { + return nil, err + } + + return &commitAllIterator{commitsPath.Front()}, nil +} + +func addReference( + repoStorer storage.Storer, + commitIterFunc func(*Commit) CommitIter, + ref *plumbing.Reference, + commitsPath *list.List, + commitsLookup map[plumbing.Hash]*list.Element) error { + + _, exists := commitsLookup[ref.Hash()] + if exists { + // we already have it - skip the reference. + return nil + } + + refCommit, _ := GetCommit(repoStorer, ref.Hash()) + if refCommit == nil { + // if it's not a commit - skip it. + return nil + } + + var ( + refCommits []*Commit + parent *list.Element + ) + // collect all ref commits to add + commitIter := commitIterFunc(refCommit) + for c, e := commitIter.Next(); e == nil; { + parent, exists = commitsLookup[c.Hash] + if exists { + break + } + refCommits = append(refCommits, c) + c, e = commitIter.Next() + } + commitIter.Close() + + if parent == nil { + // common parent - not found + // add all commits to the path from this ref (maybe it's a HEAD and we don't have anything, yet) + for _, c := range refCommits { + parent = commitsPath.PushBack(c) + commitsLookup[c.Hash] = parent + } + } else { + // add ref's commits to the path in reverse order (from the latest) + for i := len(refCommits) - 1; i >= 0; i-- { + c := refCommits[i] + // insert before found common parent + parent = commitsPath.InsertBefore(c, parent) + commitsLookup[c.Hash] = parent + } + } + + return nil +} + +func (it *commitAllIterator) Next() (*Commit, error) { + if it.currCommit == nil { + return nil, io.EOF + } + + c := it.currCommit.Value.(*Commit) + it.currCommit = it.currCommit.Next() + + return c, nil +} + +func (it *commitAllIterator) ForEach(cb func(*Commit) error) error { + for { + c, err := it.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + + err = cb(c) + if err == storer.ErrStop { + break + } + if err != nil { + return err + } + } + + return nil +} + +func (it *commitAllIterator) Close() { + it.currCommit = nil +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_file.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_file.go index 84e738ac6..6f16e611f 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_file.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_file.go @@ -1,23 +1,30 @@ package object import ( - "gopkg.in/src-d/go-git.v4/plumbing/storer" "io" + + "gopkg.in/src-d/go-git.v4/plumbing" + + "gopkg.in/src-d/go-git.v4/plumbing/storer" ) type commitFileIter struct { fileName string sourceIter CommitIter currentCommit *Commit + checkParent bool } // NewCommitFileIterFromIter returns a commit iterator which performs diffTree between // successive trees returned from the commit iterator from the argument. The purpose of this is // to find the commits that explain how the files that match the path came to be. -func NewCommitFileIterFromIter(fileName string, commitIter CommitIter) CommitIter { +// If checkParent is true then the function double checks if potential parent (next commit in a path) +// is one of the parents in the tree (it's used by `git log --all`). +func NewCommitFileIterFromIter(fileName string, commitIter CommitIter, checkParent bool) CommitIter { iterator := new(commitFileIter) iterator.sourceIter = commitIter iterator.fileName = fileName + iterator.checkParent = checkParent return iterator } @@ -71,20 +78,14 @@ func (c *commitFileIter) getNextFileCommit() (*Commit, error) { return nil, diffErr } - foundChangeForFile := false - for _, change := range changes { - if change.name() == c.fileName { - foundChangeForFile = true - break - } - } + found := c.hasFileChange(changes, parentCommit) // Storing the current-commit in-case a change is found, and // Updating the current-commit for the next-iteration prevCommit := c.currentCommit c.currentCommit = parentCommit - if foundChangeForFile == true { + if found { return prevCommit, nil } @@ -95,6 +96,35 @@ func (c *commitFileIter) getNextFileCommit() (*Commit, error) { } } +func (c *commitFileIter) hasFileChange(changes Changes, parent *Commit) bool { + for _, change := range changes { + if change.name() != c.fileName { + continue + } + + // filename matches, now check if source iterator contains all commits (from all refs) + if c.checkParent { + if parent != nil && isParentHash(parent.Hash, c.currentCommit) { + return true + } + continue + } + + return true + } + + return false +} + +func isParentHash(hash plumbing.Hash, commit *Commit) bool { + for _, h := range commit.ParentHashes { + if h == hash { + return true + } + } + return false +} + func (c *commitFileIter) ForEach(cb func(*Commit) error) error { for { commit, nextErr := c.Next() diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/test/receive_pack.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/test/receive_pack.go index 5aea1c019..8dcde8bd1 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/test/receive_pack.go +++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/test/receive_pack.go @@ -262,11 +262,7 @@ func (s *ReceivePackSuite) receivePackNoCheck(c *C, ep *transport.Endpoint, req.Packfile = s.emptyPackfile() } - if s, err := r.ReceivePack(context.Background(), req); err != nil { - return s, err - } else { - return s, err - } + return r.ReceivePack(context.Background(), req) } func (s *ReceivePackSuite) receivePack(c *C, ep *transport.Endpoint, diff --git a/vendor/gopkg.in/src-d/go-git.v4/repository.go b/vendor/gopkg.in/src-d/go-git.v4/repository.go index 97134ec17..de92d6470 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/repository.go +++ b/vendor/gopkg.in/src-d/go-git.v4/repository.go @@ -41,6 +41,8 @@ var ( ErrTagExists = errors.New("tag already exists") // ErrTagNotFound an error stating the specified tag does not exist ErrTagNotFound = errors.New("tag not found") + // ErrFetching is returned when the packfile could not be downloaded + ErrFetching = errors.New("unable to fetch packfile") ErrInvalidReference = errors.New("invalid reference, should be a tag or a branch") ErrRepositoryNotExists = errors.New("repository does not exist") @@ -858,6 +860,8 @@ func (r *Repository) fetchAndUpdateReferences( remoteRefs, err := remote.fetch(ctx, o) if err == NoErrAlreadyUpToDate { objsUpdated = false + } else if err == packfile.ErrEmptyPackfile { + return nil, ErrFetching } else if err != nil { return nil, err } @@ -1023,8 +1027,36 @@ func (r *Repository) PushContext(ctx context.Context, o *PushOptions) error { // Log returns the commit history from the given LogOptions. func (r *Repository) Log(o *LogOptions) (object.CommitIter, error) { - h := o.From - if o.From == plumbing.ZeroHash { + fn := commitIterFunc(o.Order) + if fn == nil { + return nil, fmt.Errorf("invalid Order=%v", o.Order) + } + + var ( + it object.CommitIter + err error + ) + if o.All { + it, err = r.logAll(fn) + } else { + it, err = r.log(o.From, fn) + } + + if err != nil { + return nil, err + } + + if o.FileName != nil { + // for `git log --all` also check parent (if the next commit comes from the real parent) + it = r.logWithFile(*o.FileName, it, o.All) + } + + return it, nil +} + +func (r *Repository) log(from plumbing.Hash, commitIterFunc func(*object.Commit) object.CommitIter) (object.CommitIter, error) { + h := from + if from == plumbing.ZeroHash { head, err := r.Head() if err != nil { return nil, err @@ -1037,27 +1069,41 @@ func (r *Repository) Log(o *LogOptions) (object.CommitIter, error) { if err != nil { return nil, err } + return commitIterFunc(commit), nil +} - var commitIter object.CommitIter - switch o.Order { +func (r *Repository) logAll(commitIterFunc func(*object.Commit) object.CommitIter) (object.CommitIter, error) { + return object.NewCommitAllIter(r.Storer, commitIterFunc) +} + +func (*Repository) logWithFile(fileName string, commitIter object.CommitIter, checkParent bool) object.CommitIter { + return object.NewCommitFileIterFromIter(fileName, commitIter, checkParent) +} + +func commitIterFunc(order LogOrder) func(c *object.Commit) object.CommitIter { + switch order { case LogOrderDefault: - commitIter = object.NewCommitPreorderIter(commit, nil, nil) + return func(c *object.Commit) object.CommitIter { + return object.NewCommitPreorderIter(c, nil, nil) + } case LogOrderDFS: - commitIter = object.NewCommitPreorderIter(commit, nil, nil) + return func(c *object.Commit) object.CommitIter { + return object.NewCommitPreorderIter(c, nil, nil) + } case LogOrderDFSPost: - commitIter = object.NewCommitPostorderIter(commit, nil) + return func(c *object.Commit) object.CommitIter { + return object.NewCommitPostorderIter(c, nil) + } case LogOrderBSF: - commitIter = object.NewCommitIterBSF(commit, nil, nil) + return func(c *object.Commit) object.CommitIter { + return object.NewCommitIterBSF(c, nil, nil) + } case LogOrderCommitterTime: - commitIter = object.NewCommitIterCTime(commit, nil, nil) - default: - return nil, fmt.Errorf("invalid Order=%v", o.Order) - } - - if o.FileName == nil { - return commitIter, nil + return func(c *object.Commit) object.CommitIter { + return object.NewCommitIterCTime(c, nil, nil) + } } - return object.NewCommitFileIterFromIter(*o.FileName, commitIter), nil + return nil } // Tags returns all the tag References in a repository. diff --git a/vendor/gopkg.in/src-d/go-git.v4/repository_test.go b/vendor/gopkg.in/src-d/go-git.v4/repository_test.go index 70e344ea3..2a56dd21c 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/repository_test.go +++ b/vendor/gopkg.in/src-d/go-git.v4/repository_test.go @@ -1251,6 +1251,77 @@ func (s *RepositorySuite) TestLog(c *C) { c.Assert(err, Equals, io.EOF) } +func (s *RepositorySuite) TestLogAll(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + cIter, err := r.Log(&LogOptions{ + All: true, + }) + c.Assert(err, IsNil) + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), + plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), + plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), + plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), + plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), + plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), + plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), + } + + for _, o := range commitOrder { + commit, err := cIter.Next() + c.Assert(err, IsNil) + c.Assert(commit.Hash, Equals, o) + } + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) + cIter.Close() +} + +func (s *RepositorySuite) TestLogAllOrderByTime(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + cIter, err := r.Log(&LogOptions{ + Order: LogOrderCommitterTime, + All: true, + }) + c.Assert(err, IsNil) + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), + plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), + plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), + plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), + plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), + plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), + plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), + } + + for _, o := range commitOrder { + commit, err := cIter.Next() + c.Assert(err, IsNil) + c.Assert(commit.Hash, Equals, o) + } + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) + cIter.Close() +} + func (s *RepositorySuite) TestLogHead(c *C) { r, _ := Init(memory.NewStorage(), nil) err := r.clone(context.Background(), &CloneOptions{ @@ -1333,8 +1404,8 @@ func (s *RepositorySuite) TestLogFileForEach(c *C) { fileName := "php/crappy.php" cIter, err := r.Log(&LogOptions{FileName: &fileName}) - c.Assert(err, IsNil) + defer cIter.Close() commitOrder := []plumbing.Hash{ plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), @@ -1344,7 +1415,51 @@ func (s *RepositorySuite) TestLogFileForEach(c *C) { cIter.ForEach(func(commit *object.Commit) error { expectedCommitHash := commitOrder[expectedIndex] c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) - expectedIndex += 1 + expectedIndex++ + return nil + }) + c.Assert(expectedIndex, Equals, 1) +} + +func (s *RepositorySuite) TestLogNonHeadFile(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + fileName := "README" + cIter, err := r.Log(&LogOptions{FileName: &fileName}) + c.Assert(err, IsNil) + defer cIter.Close() + + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) +} + +func (s *RepositorySuite) TestLogAllFileForEach(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + fileName := "README" + cIter, err := r.Log(&LogOptions{FileName: &fileName, All: true}) + c.Assert(err, IsNil) + defer cIter.Close() + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), + } + + expectedIndex := 0 + cIter.ForEach(func(commit *object.Commit) error { + expectedCommitHash := commitOrder[expectedIndex] + c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) + expectedIndex++ return nil }) c.Assert(expectedIndex, Equals, 1) @@ -1362,6 +1477,7 @@ func (s *RepositorySuite) TestLogInvalidFile(c *C) { cIter, err := r.Log(&LogOptions{FileName: &fileName}) // Not raising an error since `git log -- vendor/foo12.go` responds silently c.Assert(err, IsNil) + defer cIter.Close() _, err = cIter.Next() c.Assert(err, Equals, io.EOF) @@ -1379,8 +1495,8 @@ func (s *RepositorySuite) TestLogFileInitialCommit(c *C) { Order: LogOrderCommitterTime, FileName: &fileName, }) - c.Assert(err, IsNil) + defer cIter.Close() commitOrder := []plumbing.Hash{ plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), @@ -1390,7 +1506,7 @@ func (s *RepositorySuite) TestLogFileInitialCommit(c *C) { cIter.ForEach(func(commit *object.Commit) error { expectedCommitHash := commitOrder[expectedIndex] c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) - expectedIndex += 1 + expectedIndex++ return nil }) c.Assert(expectedIndex, Equals, 1) @@ -1410,6 +1526,8 @@ func (s *RepositorySuite) TestLogFileWithOtherParamsFail(c *C) { From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), }) c.Assert(err, IsNil) + defer cIter.Close() + _, iterErr := cIter.Next() c.Assert(iterErr, Equals, io.EOF) } @@ -2343,8 +2461,6 @@ func executeOnPath(path, cmd string) error { c.Stderr = buf c.Stdout = buf - //defer func() { fmt.Println(buf.String()) }() - return c.Run() } diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref.go index d27c1a303..9da2f31e8 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref.go +++ b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref.go @@ -1,15 +1,24 @@ -// +build !norwfs - package dotgit import ( + "fmt" "os" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/utils/ioutil" + + "gopkg.in/src-d/go-billy.v4" ) func (d *DotGit) setRef(fileName, content string, old *plumbing.Reference) (err error) { + if billy.CapabilityCheck(d.fs, billy.ReadAndWriteCapability) { + return d.setRefRwfs(fileName, content, old) + } + + return d.setRefNorwfs(fileName, content, old) +} + +func (d *DotGit) setRefRwfs(fileName, content string, old *plumbing.Reference) (err error) { // If we are not checking an old ref, just truncate the file. mode := os.O_RDWR | os.O_CREATE if old == nil { @@ -41,3 +50,41 @@ func (d *DotGit) setRef(fileName, content string, old *plumbing.Reference) (err _, err = f.Write([]byte(content)) return err } + +// There are some filesystems that don't support opening files in RDWD mode. +// In these filesystems the standard SetRef function can not be used as it +// reads the reference file to check that it's not modified before updating it. +// +// This version of the function writes the reference without extra checks +// making it compatible with these simple filesystems. This is usually not +// a problem as they should be accessed by only one process at a time. +func (d *DotGit) setRefNorwfs(fileName, content string, old *plumbing.Reference) error { + _, err := d.fs.Stat(fileName) + if err == nil && old != nil { + fRead, err := d.fs.Open(fileName) + if err != nil { + return err + } + + ref, err := d.readReferenceFrom(fRead, old.Name().String()) + fRead.Close() + + if err != nil { + return err + } + + if ref.Hash() != old.Hash() { + return fmt.Errorf("reference has changed concurrently") + } + } + + f, err := d.fs.Create(fileName) + if err != nil { + return err + } + + defer f.Close() + + _, err = f.Write([]byte(content)) + return err +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref_norwfs.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref_norwfs.go deleted file mode 100644 index 5695bd3b6..000000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref_norwfs.go +++ /dev/null @@ -1,47 +0,0 @@ -// +build norwfs - -package dotgit - -import ( - "fmt" - - "gopkg.in/src-d/go-git.v4/plumbing" -) - -// There are some filesystems that don't support opening files in RDWD mode. -// In these filesystems the standard SetRef function can not be used as i -// reads the reference file to check that it's not modified before updating it. -// -// This version of the function writes the reference without extra checks -// making it compatible with these simple filesystems. This is usually not -// a problem as they should be accessed by only one process at a time. -func (d *DotGit) setRef(fileName, content string, old *plumbing.Reference) error { - _, err := d.fs.Stat(fileName) - if err == nil && old != nil { - fRead, err := d.fs.Open(fileName) - if err != nil { - return err - } - - ref, err := d.readReferenceFrom(fRead, old.Name().String()) - fRead.Close() - - if err != nil { - return err - } - - if ref.Hash() != old.Hash() { - return fmt.Errorf("reference has changed concurrently") - } - } - - f, err := d.fs.Create(fileName) - if err != nil { - return err - } - - defer f.Close() - - _, err = f.Write([]byte(content)) - return err -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_test.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_test.go index 308c6b70f..73b0291a7 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_test.go +++ b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_test.go @@ -57,11 +57,26 @@ func (s *SuiteDotGit) TestSetRefs(c *C) { fs := osfs.New(tmp) dir := New(fs) + testSetRefs(c, dir) +} + +func (s *SuiteDotGit) TestSetRefsNorwfs(c *C) { + tmp, err := ioutil.TempDir("", "dot-git") + c.Assert(err, IsNil) + defer os.RemoveAll(tmp) + + fs := osfs.New(tmp) + dir := New(&norwfs{fs}) + + testSetRefs(c, dir) +} + +func testSetRefs(c *C, dir *DotGit) { firstFoo := plumbing.NewReferenceFromStrings( "refs/heads/foo", "e8d3ffab552895c19b9fcf7aa264d277cde33881", ) - err = dir.SetRef(firstFoo, nil) + err := dir.SetRef(firstFoo, nil) c.Assert(err, IsNil) @@ -795,3 +810,11 @@ func (s *SuiteDotGit) TestAlternates(c *C) { } c.Assert(dotgits[1].fs.Root(), Equals, expectedPath) } + +type norwfs struct { + billy.Filesystem +} + +func (f *norwfs) Capabilities() billy.Capability { + return billy.Capabilities(f.Filesystem) &^ billy.ReadAndWriteCapability +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object.go index 57dcbb43f..3eb62a22f 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object.go +++ b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object.go @@ -20,24 +20,25 @@ import ( type ObjectStorage struct { options Options - // deltaBaseCache is an object cache uses to cache delta's bases when - deltaBaseCache cache.Object + // objectCache is an object cache uses to cache delta's bases and also recently + // loaded loose objects + objectCache cache.Object dir *dotgit.DotGit index map[plumbing.Hash]idxfile.Index } // NewObjectStorage creates a new ObjectStorage with the given .git directory and cache. -func NewObjectStorage(dir *dotgit.DotGit, cache cache.Object) *ObjectStorage { - return NewObjectStorageWithOptions(dir, cache, Options{}) +func NewObjectStorage(dir *dotgit.DotGit, objectCache cache.Object) *ObjectStorage { + return NewObjectStorageWithOptions(dir, objectCache, Options{}) } // NewObjectStorageWithOptions creates a new ObjectStorage with the given .git directory, cache and extra options -func NewObjectStorageWithOptions(dir *dotgit.DotGit, cache cache.Object, ops Options) *ObjectStorage { +func NewObjectStorageWithOptions(dir *dotgit.DotGit, objectCache cache.Object, ops Options) *ObjectStorage { return &ObjectStorage{ - options: ops, - deltaBaseCache: cache, - dir: dir, + options: ops, + objectCache: objectCache, + dir: dir, } } @@ -206,7 +207,7 @@ func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) ( idx := s.index[pack] hash, err := idx.FindHash(offset) if err == nil { - obj, ok := s.deltaBaseCache.Get(hash) + obj, ok := s.objectCache.Get(hash) if ok { return obj.Size(), nil } @@ -215,8 +216,8 @@ func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) ( } var p *packfile.Packfile - if s.deltaBaseCache != nil { - p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.deltaBaseCache) + if s.objectCache != nil { + p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.objectCache) } else { p = packfile.NewPackfile(idx, s.dir.Fs(), f) } @@ -241,9 +242,19 @@ func (s *ObjectStorage) EncodedObjectSize(h plumbing.Hash) ( // EncodedObject returns the object with the given hash, by searching for it in // the packfile and the git object directories. func (s *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (plumbing.EncodedObject, error) { - obj, err := s.getFromUnpacked(h) - if err == plumbing.ErrObjectNotFound { + var obj plumbing.EncodedObject + var err error + + if s.index != nil { obj, err = s.getFromPackfile(h, false) + if err == plumbing.ErrObjectNotFound { + obj, err = s.getFromUnpacked(h) + } + } else { + obj, err = s.getFromUnpacked(h) + if err == plumbing.ErrObjectNotFound { + obj, err = s.getFromPackfile(h, false) + } } // If the error is still object not found, check if it's a shared object @@ -254,7 +265,7 @@ func (s *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (p // Create a new object storage with the DotGit(s) and check for the // required hash object. Skip when not found. for _, dg := range dotgits { - o := NewObjectStorage(dg, s.deltaBaseCache) + o := NewObjectStorage(dg, s.objectCache) enobj, enerr := o.EncodedObject(t, h) if enerr != nil { continue @@ -304,9 +315,12 @@ func (s *ObjectStorage) getFromUnpacked(h plumbing.Hash) (obj plumbing.EncodedOb return nil, err } - defer ioutil.CheckClose(f, &err) + if cacheObj, found := s.objectCache.Get(h); found { + return cacheObj, nil + } + obj = s.NewEncodedObject() r, err := objfile.NewReader(f) if err != nil { @@ -327,6 +341,8 @@ func (s *ObjectStorage) getFromUnpacked(h plumbing.Hash) (obj plumbing.EncodedOb return nil, err } + s.objectCache.Put(obj) + _, err = io.Copy(w, r) return obj, err } @@ -369,7 +385,7 @@ func (s *ObjectStorage) decodeObjectAt( ) (plumbing.EncodedObject, error) { hash, err := idx.FindHash(offset) if err == nil { - obj, ok := s.deltaBaseCache.Get(hash) + obj, ok := s.objectCache.Get(hash) if ok { return obj, nil } @@ -380,8 +396,8 @@ func (s *ObjectStorage) decodeObjectAt( } var p *packfile.Packfile - if s.deltaBaseCache != nil { - p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.deltaBaseCache) + if s.objectCache != nil { + p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.objectCache) } else { p = packfile.NewPackfile(idx, s.dir.Fs(), f) } @@ -400,11 +416,7 @@ func (s *ObjectStorage) decodeDeltaObjectAt( } p := packfile.NewScanner(f) - if _, err := p.SeekFromStart(offset); err != nil { - return nil, err - } - - header, err := p.NextObjectHeader() + header, err := p.SeekObjectHeader(offset) if err != nil { return nil, err } @@ -495,7 +507,7 @@ func (s *ObjectStorage) buildPackfileIters( } return newPackfileIter( s.dir.Fs(), pack, t, seen, s.index[h], - s.deltaBaseCache, s.options.KeepDescriptors, + s.objectCache, s.options.KeepDescriptors, ) }, }, nil diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object_test.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object_test.go index 77eb31d81..5cfb22776 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object_test.go +++ b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object_test.go @@ -297,6 +297,23 @@ func (s *FsSuite) TestPackfileIterKeepDescriptors(c *C) { }) } +func (s *FsSuite) TestGetFromObjectFileSharedCache(c *C) { + f1 := fixtures.ByTag("worktree").One().DotGit() + f2 := fixtures.ByTag("worktree").ByTag("submodule").One().DotGit() + + ch := cache.NewObjectLRUDefault() + o1 := NewObjectStorage(dotgit.New(f1), ch) + o2 := NewObjectStorage(dotgit.New(f2), ch) + + expected := plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a") + obj, err := o1.EncodedObject(plumbing.CommitObject, expected) + c.Assert(err, IsNil) + c.Assert(obj.Hash(), Equals, expected) + + obj, err = o2.EncodedObject(plumbing.CommitObject, expected) + c.Assert(err, Equals, plumbing.ErrObjectNotFound) +} + func BenchmarkPackfileIter(b *testing.B) { if err := fixtures.Init(); err != nil { b.Fatal(err) diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/storage.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/storage.go index 14a772abe..370f7bd34 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/storage.go +++ b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/storage.go @@ -51,11 +51,7 @@ func NewStorageWithOptions(fs billy.Filesystem, cache cache.Object, ops Options) fs: fs, dir: dir, - ObjectStorage: ObjectStorage{ - options: ops, - deltaBaseCache: cache, - dir: dir, - }, + ObjectStorage: *NewObjectStorageWithOptions(dir, cache, ops), ReferenceStorage: ReferenceStorage{dir: dir}, IndexStorage: IndexStorage{dir: dir}, ShallowStorage: ShallowStorage{dir: dir}, diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/server/handler.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/server/handler.go index 95b0a1eb9..422a2ac3e 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/server/handler.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/server/handler.go @@ -83,7 +83,7 @@ func (h *Handler) ComQuery( } if handled { - return nil + return callback(&sqltypes.Result{}) } start := time.Now() diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/analyzer/resolve_columns.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/analyzer/resolve_columns.go index ce2ae02a0..39be0aa19 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/analyzer/resolve_columns.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/analyzer/resolve_columns.go @@ -12,6 +12,79 @@ import ( "gopkg.in/src-d/go-vitess.v1/vt/sqlparser" ) +func checkAliases(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, error) { + span, _ := ctx.Span("check_aliases") + defer span.Finish() + + a.Log("check aliases") + + var err error + plan.Inspect(n, func(node sql.Node) bool { + p, ok := node.(*plan.Project) + if !ok { + return true + } + + aliases := lookForAliasDeclarations(p) + for alias := range aliases { + if isAliasUsed(p, alias) { + err = ErrMisusedAlias.New(alias) + } + } + + return true + }) + + return n, err +} + +func lookForAliasDeclarations(node sql.Expressioner) map[string]struct{} { + var ( + aliases = map[string]struct{}{} + in = struct{}{} + ) + + for _, e := range node.Expressions() { + expression.Inspect(e, func(expr sql.Expression) bool { + if alias, ok := expr.(*expression.Alias); ok { + aliases[alias.Name()] = in + } + + return true + }) + } + + return aliases +} + +func isAliasUsed(node sql.Expressioner, alias string) bool { + var found bool + for _, e := range node.Expressions() { + expression.Inspect(e, func(expr sql.Expression) bool { + if a, ok := expr.(*expression.Alias); ok { + if a.Name() == alias { + return false + } + + return true + } + + if n, ok := expr.(sql.Nameable); ok && n.Name() == alias { + found = true + return false + } + + return true + }) + + if found { + break + } + } + + return found +} + // deferredColumn is a wrapper on UnresolvedColumn used only to defer the // resolution of the column because it may require some work done by // other analyzer phases. @@ -221,18 +294,6 @@ func resolveColumns(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, error) } } - var ( - aliasMap = make(map[string]struct{}) - exists = struct{}{} - ) - if project, ok := n.(*plan.Project); ok { - for _, e := range project.Projections { - if alias, ok := e.(*expression.Alias); ok { - aliasMap[strings.ToLower(alias.Name())] = exists - } - } - } - expressioner, ok := n.(sql.Expressioner) if !ok { return n, nil @@ -287,11 +348,6 @@ func resolveColumns(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, error) return nil, ErrColumnTableNotFound.New(uc.Table(), uc.Name()) } - if _, ok := aliasMap[name]; ok { - // no nested aliases - return nil, ErrMisusedAlias.New(uc.Name()) - } - return nil, ErrColumnNotFound.New(uc.Name()) } } diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/analyzer/rules.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/analyzer/rules.go index b480d0d59..0386fe57f 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/analyzer/rules.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/analyzer/rules.go @@ -27,6 +27,7 @@ var DefaultRules = []Rule{ var OnceBeforeDefault = []Rule{ {"resolve_subqueries", resolveSubqueries}, {"resolve_tables", resolveTables}, + {"check_aliases", checkAliases}, } // OnceAfterDefault contains the rules to be applied just once after the diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/comparison.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/comparison.go index bc037f7b7..2c52b78a8 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/comparison.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/comparison.go @@ -259,7 +259,9 @@ func (re *Regexp) compareRegexp(ctx *sql.Context, row sql.Row) (interface{}, err }, } } - matcher = re.pool.Get().(regex.Matcher) + if obj := re.pool.Get(); obj != nil { + matcher = obj.(regex.Matcher) + } } if matcher == nil { return nil, err diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/ceil_round_floor.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/ceil_round_floor.go index bcd3deb1b..9e7ddc5ee 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/ceil_round_floor.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/ceil_round_floor.go @@ -155,7 +155,7 @@ type Round struct { func NewRound(args ...sql.Expression) (sql.Expression, error) { argLen := len(args) if argLen == 0 || argLen > 2 { - return nil, sql.ErrInvalidArgumentNumber.New("1 or 2", argLen) + return nil, sql.ErrInvalidArgumentNumber.New("ROUND", "1 or 2", argLen) } var right sql.Expression diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/coalesce.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/coalesce.go index 1f0d75a68..e7a0b760b 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/coalesce.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/coalesce.go @@ -15,7 +15,7 @@ type Coalesce struct { // NewCoalesce creates a new Coalesce sql.Expression. func NewCoalesce(args ...sql.Expression) (sql.Expression, error) { if len(args) == 0 { - return nil, sql.ErrInvalidArgumentNumber.New("1 or more", 0) + return nil, sql.ErrInvalidArgumentNumber.New("COALESCE", "1 or more", 0) } return &Coalesce{args}, nil diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/concat.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/concat.go index 29660120f..5777a030a 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/concat.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/concat.go @@ -20,7 +20,7 @@ var ErrConcatArrayWithOthers = errors.NewKind("can't concat a string array with // NewConcat creates a new Concat UDF. func NewConcat(args ...sql.Expression) (sql.Expression, error) { if len(args) == 0 { - return nil, sql.ErrInvalidArgumentNumber.New("1 or more", 0) + return nil, sql.ErrInvalidArgumentNumber.New("CONCAT", "1 or more", 0) } for _, arg := range args { diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/concat_ws.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/concat_ws.go index d0c6a5e2d..4c856da1a 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/concat_ws.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/concat_ws.go @@ -18,7 +18,7 @@ type ConcatWithSeparator struct { // NewConcatWithSeparator creates a new NewConcatWithSeparator UDF. func NewConcatWithSeparator(args ...sql.Expression) (sql.Expression, error) { if len(args) == 0 { - return nil, sql.ErrInvalidArgumentNumber.New("1 or more", 0) + return nil, sql.ErrInvalidArgumentNumber.New("CONCAT_WS", "1 or more", 0) } for _, arg := range args { diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/json_extract.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/json_extract.go index 0de3f97ab..b49796c5c 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/json_extract.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/json_extract.go @@ -18,7 +18,7 @@ type JSONExtract struct { // NewJSONExtract creates a new JSONExtract UDF. func NewJSONExtract(args ...sql.Expression) (sql.Expression, error) { if len(args) < 2 { - return nil, sql.ErrInvalidArgumentNumber.New(2, len(args)) + return nil, sql.ErrInvalidArgumentNumber.New("JSON_EXTRACT", 2, len(args)) } return &JSONExtract{args[0], args[1:]}, nil diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/logarithm.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/logarithm.go index 771c97c43..18f74b1be 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/logarithm.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/logarithm.go @@ -1,13 +1,13 @@ package function import ( + "fmt" "math" "reflect" - "fmt" - "gopkg.in/src-d/go-mysql-server.v0/sql/expression" - "gopkg.in/src-d/go-mysql-server.v0/sql" "gopkg.in/src-d/go-errors.v1" + "gopkg.in/src-d/go-mysql-server.v0/sql" + "gopkg.in/src-d/go-mysql-server.v0/sql/expression" ) // ErrInvalidArgumentForLogarithm is returned when an invalid argument value is passed to a @@ -94,7 +94,7 @@ type Log struct { func NewLog(args ...sql.Expression) (sql.Expression, error) { argLen := len(args) if argLen == 0 || argLen > 2 { - return nil, sql.ErrInvalidArgumentNumber.New("1 or 2", argLen) + return nil, sql.ErrInvalidArgumentNumber.New("LOG", "1 or 2", argLen) } if argLen == 1 { diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/rpad_lpad.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/rpad_lpad.go index 963089820..cc37eee34 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/rpad_lpad.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/rpad_lpad.go @@ -5,13 +5,14 @@ import ( "reflect" "strings" - "gopkg.in/src-d/go-mysql-server.v0/sql" "gopkg.in/src-d/go-errors.v1" + "gopkg.in/src-d/go-mysql-server.v0/sql" ) var ErrDivisionByZero = errors.NewKind("division by zero") type padType rune + const ( lPadType padType = 'l' rPadType padType = 'r' @@ -28,7 +29,7 @@ func NewPadFunc(pType padType) func(e ...sql.Expression) (sql.Expression, error) func NewPad(pType padType, args ...sql.Expression) (sql.Expression, error) { argLen := len(args) if argLen != 3 { - return nil, sql.ErrInvalidArgumentNumber.New("3", argLen) + return nil, sql.ErrInvalidArgumentNumber.New(string(pType)+"pad", "3", argLen) } return &Pad{args[0], args[1], args[2], pType}, nil diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/substring.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/substring.go index b40321ce7..68f9c51fa 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/substring.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/expression/function/substring.go @@ -32,7 +32,7 @@ func NewSubstring(args ...sql.Expression) (sql.Expression, error) { start = args[1] ln = args[2] default: - return nil, sql.ErrInvalidArgumentNumber.New("2 or 3", len(args)) + return nil, sql.ErrInvalidArgumentNumber.New("SUBSTRING", "2 or 3", len(args)) } return &Substring{str, start, ln}, nil } diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/functionregistry.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/functionregistry.go index e5f92e74c..6a6c0ef3a 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/functionregistry.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/functionregistry.go @@ -9,7 +9,7 @@ var ErrFunctionNotFound = errors.NewKind("function not found: %s") // ErrInvalidArgumentNumber is returned when the number of arguments to call a // function is different from the function arity. -var ErrInvalidArgumentNumber = errors.NewKind("expecting %v arguments for calling this function, %d received") +var ErrInvalidArgumentNumber = errors.NewKind("%s: expecting %v arguments for calling this function, %d received") // Function is a function defined by the user that can be applied in a SQL // query. diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/plan/innerjoin.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/plan/innerjoin.go index ff61a577c..5645ade09 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/plan/innerjoin.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/plan/innerjoin.go @@ -2,12 +2,18 @@ package plan import ( "io" + "os" "reflect" opentracing "github.com/opentracing/opentracing-go" "gopkg.in/src-d/go-mysql-server.v0/sql" ) +const experimentalInMemoryJoinKey = "EXPERIMENTAL_IN_MEMORY_JOIN" +const inMemoryJoinSessionVar = "inmemory_joins" + +var useInMemoryJoins = os.Getenv(experimentalInMemoryJoinKey) != "" + // InnerJoin is an inner join between two tables. type InnerJoin struct { BinaryNode @@ -61,12 +67,36 @@ func (j *InnerJoin) RowIter(ctx *sql.Context) (sql.RowIter, error) { return nil, err } - return sql.NewSpanIter(span, &innerJoinIter{ - l: l, - rp: j.Right, - ctx: ctx, - cond: j.Cond, - }), nil + var inMemorySession bool + _, val := ctx.Get(inMemoryJoinSessionVar) + if val != nil { + inMemorySession = true + } + + var iter sql.RowIter + if useInMemoryJoins || inMemorySession { + r, err := j.Right.RowIter(ctx) + if err != nil { + span.Finish() + return nil, err + } + + iter = &innerJoinMemoryIter{ + l: l, + r: r, + ctx: ctx, + cond: j.Cond, + } + } else { + iter = &innerJoinIter{ + l: l, + rp: j.Right, + ctx: ctx, + cond: j.Cond, + } + } + + return sql.NewSpanIter(span, iter), nil } // TransformUp implements the Transformable interface. @@ -196,3 +226,78 @@ func (i *innerJoinIter) Close() error { return nil } + +type innerJoinMemoryIter struct { + l sql.RowIter + r sql.RowIter + ctx *sql.Context + cond sql.Expression + pos int + leftRow sql.Row + right []sql.Row +} + +func (i *innerJoinMemoryIter) Next() (sql.Row, error) { + for { + if i.leftRow == nil { + r, err := i.l.Next() + if err != nil { + return nil, err + } + + i.leftRow = r + } + + if i.r != nil { + for { + row, err := i.r.Next() + if err != nil { + if err == io.EOF { + break + } + return nil, err + } + + i.right = append(i.right, row) + } + i.r = nil + } + + if i.pos >= len(i.right) { + i.pos = 0 + i.leftRow = nil + continue + } + + rightRow := i.right[i.pos] + var row = make(sql.Row, len(i.leftRow)+len(rightRow)) + copy(row, i.leftRow) + copy(row[len(i.leftRow):], rightRow) + + i.pos++ + + v, err := i.cond.Eval(i.ctx, row) + if err != nil { + return nil, err + } + + if v == true { + return row, nil + } + } +} + +func (i *innerJoinMemoryIter) Close() error { + if err := i.l.Close(); err != nil { + if i.r != nil { + _ = i.r.Close() + } + return err + } + + if i.r != nil { + return i.r.Close() + } + + return nil +} diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/plan/show_create_table.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/plan/show_create_table.go index 9019496bd..853613e62 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/plan/show_create_table.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/plan/show_create_table.go @@ -89,7 +89,7 @@ func produceCreateStatement(table sql.Table) string { // Statement creation parts for each column for indx, col := range schema { - createStmtPart := fmt.Sprintf("`%s` %s", col.Name, col.Type.Type()) + createStmtPart := fmt.Sprintf(" `%s` %s", col.Name, col.Type.Type()) if !col.Nullable { createStmtPart = fmt.Sprintf("%s NOT NULL", createStmtPart) @@ -111,7 +111,7 @@ func produceCreateStatement(table sql.Table) string { prettyColCreateStmts := strings.Join(colCreateStatements, ",\n") composedCreateTableStatement := - fmt.Sprintf("CREATE TABLE `%s` (%s) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", table.Name(), prettyColCreateStmts) + fmt.Sprintf("CREATE TABLE `%s` (\n%s\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", table.Name(), prettyColCreateStmts) return composedCreateTableStatement } diff --git a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/session.go b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/session.go index 553fcee7a..2449a492d 100644 --- a/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/session.go +++ b/vendor/gopkg.in/src-d/go-mysql-server.v0/sql/session.go @@ -59,12 +59,13 @@ type BaseSession struct { mu sync.RWMutex config map[string]TypedValue warnings []*Warning + warncnt uint16 } // Address returns the server address. func (s *BaseSession) Address() string { return s.addr } -// User returns session's client information. +// Client returns session's client information. func (s *BaseSession) Client() Client { return s.client } // Set implements the Session interface. @@ -127,8 +128,15 @@ func (s *BaseSession) Warnings() []*Warning { func (s *BaseSession) ClearWarnings() { s.mu.Lock() defer s.mu.Unlock() - if s.warnings != nil { - s.warnings = s.warnings[:0] + + cnt := uint16(len(s.warnings)) + if s.warncnt == cnt { + if s.warnings != nil { + s.warnings = s.warnings[:0] + } + s.warncnt = 0 + } else { + s.warncnt = cnt } }