diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 4a3da62fc..395088b7b 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -12,7 +12,7 @@ is supported by go-git. | init | ✔ | Plain init and `--bare` are supported. Flags `--template`, `--separate-git-dir` and `--shared` are not. | | clone | ✔ | Plain clone and equivalents to `--progress`, `--single-branch`, `--depth`, `--origin`, `--recurse-submodules` are supported. Others are not. | | **basic snapshotting** | -| add | ✔ | Plain add is supported. Any other flag aren't supported | +| add | ✔ | Plain add is supported. Any other flags aren't supported | | status | ✔ | | commit | ✔ | | reset | ✔ | diff --git a/Makefile b/Makefile index d576778f4..3866fb70f 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,6 @@ GIT_REPOSITORY = http://github.com/git/git.git # Coverage COVERAGE_REPORT = coverage.txt -COVERAGE_PROFILE = profile.out COVERAGE_MODE = atomic ifneq ($(origin CI), undefined) @@ -37,16 +36,7 @@ test: test-coverage: @cd $(WORKDIR); \ echo "" > $(COVERAGE_REPORT); \ - for dir in `find . -name "*.go" | grep -o '.*/' | sort | uniq`; do \ - $(GOTEST) $$dir -coverprofile=$(COVERAGE_PROFILE) -covermode=$(COVERAGE_MODE); \ - if [ $$? != 0 ]; then \ - exit 2; \ - fi; \ - if [ -f $(COVERAGE_PROFILE) ]; then \ - cat $(COVERAGE_PROFILE) >> $(COVERAGE_REPORT); \ - rm $(COVERAGE_PROFILE); \ - fi; \ - done; \ + $(GOTEST) -coverprofile=$(COVERAGE_REPORT) -coverpkg=./... -covermode=$(COVERAGE_MODE) ./... clean: rm -rf $(GIT_DIST_PATH) \ No newline at end of file diff --git a/README.md b/README.md index ed9306c83..07a9f786c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +## WE CONTINUE THE DEVELOPMENT AT [go-git/go-git](https://github.com/go-git/go-git). This repository is abandoned, and no further updates will be done on the code base, nor issue/prs will be answered or attended. + ![go-git logo](https://cdn.rawgit.com/src-d/artwork/02036484/go-git/files/go-git-github-readme-header.png) [![GoDoc](https://godoc.org/gopkg.in/src-d/go-git.v4?status.svg)](https://godoc.org/github.com/src-d/go-git) [![Build Status](https://travis-ci.org/src-d/go-git.svg)](https://travis-ci.org/src-d/go-git) [![Build status](https://ci.appveyor.com/api/projects/status/nyidskwifo4py6ub?svg=true)](https://ci.appveyor.com/project/mcuadros/go-git) [![codecov.io](https://codecov.io/github/src-d/go-git/coverage.svg)](https://codecov.io/github/src-d/go-git) [![Go Report Card](https://goreportcard.com/badge/github.com/src-d/go-git)](https://goreportcard.com/report/github.com/src-d/go-git) diff --git a/_examples/log/main.go b/_examples/log/main.go index ba0597ac6..58075159c 100644 --- a/_examples/log/main.go +++ b/_examples/log/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "time" "gopkg.in/src-d/go-git.v4" . "gopkg.in/src-d/go-git.v4/_examples" @@ -31,7 +32,9 @@ func main() { CheckIfError(err) // ... retrieves the commit history - cIter, err := r.Log(&git.LogOptions{From: ref.Hash()}) + since := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC) + until := time.Date(2019, 7, 30, 0, 0, 0, 0, time.UTC) + cIter, err := r.Log(&git.LogOptions{From: ref.Hash(), Since: &since, Until: &until}) CheckIfError(err) // ... just iterates over the commits, printing it diff --git a/_examples/ls-remote/main.go b/_examples/ls-remote/main.go index 68c0454a6..42d9b4eb2 100644 --- a/_examples/ls-remote/main.go +++ b/_examples/ls-remote/main.go @@ -19,7 +19,7 @@ func main() { log.Print("Fetching tags...") - // We can then use every Remote functions to retrieve wanted informations + // We can then use every Remote functions to retrieve wanted information refs, err := rem.List(&git.ListOptions{}) if err != nil { log.Fatal(err) diff --git a/_examples/merge_base/helpers.go b/_examples/merge_base/helpers.go index b7b1ed696..179a81765 100644 --- a/_examples/merge_base/helpers.go +++ b/_examples/merge_base/helpers.go @@ -13,7 +13,7 @@ func checkIfError(err error, code exitCode, mainReason string, v ...interface{}) return } - printErr(wrappErr(err, mainReason, v...)) + printErr(wrapErr(err, mainReason, v...)) os.Exit(int(code)) } @@ -52,7 +52,7 @@ func printCommits(commits []*object.Commit) { } } -func wrappErr(err error, s string, v ...interface{}) error { +func wrapErr(err error, s string, v ...interface{}) error { if err != nil { return fmt.Errorf("%s\n %s", fmt.Sprintf(s, v...), err) } diff --git a/_examples/open/main.go b/_examples/open/main.go index dec183ed2..71c6b8465 100644 --- a/_examples/open/main.go +++ b/_examples/open/main.go @@ -14,7 +14,7 @@ func main() { CheckArgs("") path := os.Args[1] - // We instanciate a new repository targeting the given path (the .git folder) + // We instantiate a new repository targeting the given path (the .git folder) r, err := git.PlainOpen(path) CheckIfError(err) diff --git a/_examples/progress/main.go b/_examples/progress/main.go index 357703c9f..074430f86 100644 --- a/_examples/progress/main.go +++ b/_examples/progress/main.go @@ -22,7 +22,7 @@ func main() { // as git does, when you make a clone, pull or some other operations the // server sends information via the sideband, this information can being - // collected provinding a io.Writer to the CloneOptions options + // collected providing a io.Writer to the CloneOptions options Progress: os.Stdout, }) diff --git a/_examples/pull/main.go b/_examples/pull/main.go index 06369fa87..6f258c855 100644 --- a/_examples/pull/main.go +++ b/_examples/pull/main.go @@ -13,7 +13,7 @@ func main() { CheckArgs("") path := os.Args[1] - // We instance\iate a new repository targeting the given path (the .git folder) + // We instantiate a new repository targeting the given path (the .git folder) r, err := git.PlainOpen(path) CheckIfError(err) diff --git a/_examples/tag/main.go b/_examples/tag/main.go index 1e6212bff..93192b0bb 100644 --- a/_examples/tag/main.go +++ b/_examples/tag/main.go @@ -15,7 +15,7 @@ func main() { CheckArgs("") path := os.Args[1] - // We instanciate a new repository targeting the given path (the .git folder) + // We instantiate a new repository targeting the given path (the .git folder) r, err := git.PlainOpen(path) CheckIfError(err) diff --git a/config/branch_test.go b/config/branch_test.go index 2dbe888c7..6d9ca8631 100644 --- a/config/branch_test.go +++ b/config/branch_test.go @@ -38,7 +38,7 @@ func (b *BranchSuite) TestValidateMerge(c *C) { c.Assert(badBranch.Validate(), NotNil) } -func (b *BranchSuite) TestMarshall(c *C) { +func (b *BranchSuite) TestMarshal(c *C) { expected := []byte(`[core] bare = false [branch "branch-tracking-on-clone"] @@ -60,7 +60,7 @@ func (b *BranchSuite) TestMarshall(c *C) { c.Assert(string(actual), Equals, string(expected)) } -func (b *BranchSuite) TestUnmarshall(c *C) { +func (b *BranchSuite) TestUnmarshal(c *C) { input := []byte(`[core] bare = false [branch "branch-tracking-on-clone"] diff --git a/config/config.go b/config/config.go index ea614e96d..321ca0418 100644 --- a/config/config.go +++ b/config/config.go @@ -33,7 +33,7 @@ var ( ) // Config contains the repository configuration -// ftp://www.kernel.org/pub/software/scm/git/docs/git-config.html#FILES +// https://www.kernel.org/pub/software/scm/git/docs/git-config.html#FILES type Config struct { Core struct { // IsBare if true this repository is assumed to be bare and has no diff --git a/config/config_test.go b/config/config_test.go index db0932caa..54eb5e1a8 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -9,7 +9,7 @@ type ConfigSuite struct{} var _ = Suite(&ConfigSuite{}) -func (s *ConfigSuite) TestUnmarshall(c *C) { +func (s *ConfigSuite) TestUnmarshal(c *C) { input := []byte(`[core] bare = true worktree = foo @@ -60,7 +60,7 @@ func (s *ConfigSuite) TestUnmarshall(c *C) { c.Assert(cfg.Branches["master"].Merge, Equals, plumbing.ReferenceName("refs/heads/master")) } -func (s *ConfigSuite) TestMarshall(c *C) { +func (s *ConfigSuite) TestMarshal(c *C) { output := []byte(`[core] bare = true worktree = bar @@ -119,7 +119,7 @@ func (s *ConfigSuite) TestMarshall(c *C) { c.Assert(string(b), Equals, string(output)) } -func (s *ConfigSuite) TestUnmarshallMarshall(c *C) { +func (s *ConfigSuite) TestUnmarshalMarshal(c *C) { input := []byte(`[core] bare = true worktree = foo diff --git a/config/modules_test.go b/config/modules_test.go index 8e10d70f1..8ea68e777 100644 --- a/config/modules_test.go +++ b/config/modules_test.go @@ -39,7 +39,7 @@ func (s *ModulesSuite) TestValidateMissingName(c *C) { c.Assert(m.Validate(), Equals, ErrModuleEmptyPath) } -func (s *ModulesSuite) TestMarshall(c *C) { +func (s *ModulesSuite) TestMarshal(c *C) { input := []byte(`[submodule "qux"] path = qux url = baz @@ -54,7 +54,7 @@ func (s *ModulesSuite) TestMarshall(c *C) { c.Assert(output, DeepEquals, input) } -func (s *ModulesSuite) TestUnmarshall(c *C) { +func (s *ModulesSuite) TestUnmarshal(c *C) { input := []byte(`[submodule "qux"] path = qux url = https://github.com/foo/qux.git @@ -79,7 +79,7 @@ func (s *ModulesSuite) TestUnmarshall(c *C) { c.Assert(cfg.Submodules["foo/bar"].Branch, Equals, "dev") } -func (s *ModulesSuite) TestUnmarshallMarshall(c *C) { +func (s *ModulesSuite) TestUnmarshalMarshal(c *C) { input := []byte(`[submodule "foo/bar"] path = foo/bar url = https://github.com/foo/bar.git diff --git a/internal/revision/parser.go b/internal/revision/parser.go index d2c509e50..61de386b2 100644 --- a/internal/revision/parser.go +++ b/internal/revision/parser.go @@ -1,5 +1,5 @@ // Package revision extracts git revision from string -// More informations about revision : https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html +// More information about revision : https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html package revision import ( diff --git a/internal/revision/parser_test.go b/internal/revision/parser_test.go index a58f0ad78..fe4522803 100644 --- a/internal/revision/parser_test.go +++ b/internal/revision/parser_test.go @@ -366,7 +366,7 @@ func (s *ParserSuite) TestParseRefWithValidName(c *C) { } } -func (s *ParserSuite) TestParseRefWithUnvalidName(c *C) { +func (s *ParserSuite) TestParseRefWithInvalidName(c *C) { datas := map[string]error{ ".master": &ErrInvalidRevision{`must not start with "."`}, "/master": &ErrInvalidRevision{`must not start with "/"`}, diff --git a/internal/revision/scanner.go b/internal/revision/scanner.go index fb5f333f7..c46c21b79 100644 --- a/internal/revision/scanner.go +++ b/internal/revision/scanner.go @@ -10,7 +10,7 @@ import ( // validates it belongs to a rune category type runeCategoryValidator func(r rune) bool -// tokenizeExpression aggegates a series of runes matching check predicate into a single +// tokenizeExpression aggregates a series of runes matching check predicate into a single // string and provides given tokenType as token type func tokenizeExpression(ch rune, tokenType token, check runeCategoryValidator, r *bufio.Reader) (token, string, error) { var data []rune diff --git a/internal/url/url.go b/internal/url/url.go index 0f0d709d9..14cf133de 100644 --- a/internal/url/url.go +++ b/internal/url/url.go @@ -6,7 +6,7 @@ import ( var ( isSchemeRegExp = regexp.MustCompile(`^[^:]+://`) - scpLikeUrlRegExp = regexp.MustCompile(`^(?:(?P[^@]+)@)?(?P[^:\s]+):(?:(?P[0-9]{1,5})/)?(?P[^\\].*)$`) + scpLikeUrlRegExp = regexp.MustCompile(`^(?:(?P[^@]+)@)?(?P[^:\s]+):(?:(?P[0-9]{1,5})(?:\/|:))?(?P[^\\].*\/[^\\].*)$`) ) // MatchesScheme returns true if the given string matches a URL-like diff --git a/internal/url/url_test.go b/internal/url/url_test.go new file mode 100755 index 000000000..d168db6df --- /dev/null +++ b/internal/url/url_test.go @@ -0,0 +1,60 @@ +package url + +import ( + "testing" + + . "gopkg.in/check.v1" +) + +func Test(t *testing.T) { TestingT(t) } + +type URLSuite struct{} + +var _ = Suite(&URLSuite{}) + +func (s *URLSuite) TestMatchesScpLike(c *C) { + examples := []string{ + "git@github.com:james/bond", + "git@github.com:007/bond", + "git@github.com:22:james/bond", + "git@github.com:22:007/bond", + } + + for _, url := range examples { + c.Check(MatchesScpLike(url), Equals, true) + } +} + +func (s *URLSuite) TestFindScpLikeComponents(c *C) { + url := "git@github.com:james/bond" + user, host, port, path := FindScpLikeComponents(url) + + c.Check(user, Equals, "git") + c.Check(host, Equals, "github.com") + c.Check(port, Equals, "") + c.Check(path, Equals, "james/bond") + + url = "git@github.com:007/bond" + user, host, port, path = FindScpLikeComponents(url) + + c.Check(user, Equals, "git") + c.Check(host, Equals, "github.com") + c.Check(port, Equals, "") + c.Check(path, Equals, "007/bond") + + url = "git@github.com:22:james/bond" + user, host, port, path = FindScpLikeComponents(url) + + c.Check(user, Equals, "git") + c.Check(host, Equals, "github.com") + c.Check(port, Equals, "22") + c.Check(path, Equals, "james/bond") + + url = "git@github.com:22:007/bond" + user, host, port, path = FindScpLikeComponents(url) + + c.Check(user, Equals, "git") + c.Check(host, Equals, "github.com") + c.Check(port, Equals, "22") + c.Check(path, Equals, "007/bond") +} diff --git a/object_walker.go b/object_walker.go index f8b19cdb0..1fdcb36a4 100644 --- a/object_walker.go +++ b/object_walker.go @@ -21,7 +21,7 @@ func newObjectWalker(s storage.Storer) *objectWalker { return &objectWalker{s, map[plumbing.Hash]struct{}{}} } -// walkAllRefs walks all (hash) refererences from the repo. +// walkAllRefs walks all (hash) references from the repo. func (p *objectWalker) walkAllRefs() error { // Walk over all the references in the repo. it, err := p.Storer.IterReferences() diff --git a/options.go b/options.go index 0f728e7c2..cc8f9c59f 100644 --- a/options.go +++ b/options.go @@ -4,6 +4,7 @@ import ( "errors" "regexp" "strings" + "time" "golang.org/x/crypto/openpgp" "gopkg.in/src-d/go-git.v4/config" @@ -348,6 +349,14 @@ type LogOptions struct { // It is equivalent to running `git log --all`. // If set on true, the From option will be ignored. All bool + + // Show commits more recent than a specific date. + // It is equivalent to running `git log --since ` or `git log --after `. + Since *time.Time + + // Show commits older than a specific date. + // It is equivalent to running `git log --until ` or `git log --before `. + Until *time.Time } var ( diff --git a/plumbing/filemode/filemode.go b/plumbing/filemode/filemode.go index 0994bc4d7..594984f9e 100644 --- a/plumbing/filemode/filemode.go +++ b/plumbing/filemode/filemode.go @@ -32,10 +32,10 @@ const ( Regular FileMode = 0100644 // Deprecated represent non-executable files with the group writable // bit set. This mode was supported by the first versions of git, - // but it has been deprecatred nowadays. This library uses them + // but it has been deprecated nowadays. This library uses them // internally, so you can read old packfiles, but will treat them as // Regulars when interfacing with the outside world. This is the - // standard git behaviuor. + // standard git behaviour. Deprecated FileMode = 0100664 // Executable represents executable files. Executable FileMode = 0100755 @@ -152,7 +152,7 @@ func (m FileMode) IsRegular() bool { } // IsFile returns if the FileMode represents that of a file, this is, -// Regular, Deprecated, Excutable or Link. +// Regular, Deprecated, Executable or Link. func (m FileMode) IsFile() bool { return m == Regular || m == Deprecated || diff --git a/plumbing/filemode/filemode_test.go b/plumbing/filemode/filemode_test.go index 299c96a7c..8d713f6f0 100644 --- a/plumbing/filemode/filemode_test.go +++ b/plumbing/filemode/filemode_test.go @@ -126,7 +126,7 @@ func (s *ModeSuite) TestNewFromOsFileModeExclusive(c *C) { } func (s *ModeSuite) TestNewFromOsFileModeTemporary(c *C) { - // temporaty files are ignored + // temporary files are ignored fixture{ input: os.FileMode(0644) | os.ModeTemporary, // Trw-r--r-- expected: Empty, err: "no equivalent.*", diff --git a/plumbing/format/diff/unified_encoder.go b/plumbing/format/diff/unified_encoder.go index 169242dc5..ce3bc7c1f 100644 --- a/plumbing/format/diff/unified_encoder.go +++ b/plumbing/format/diff/unified_encoder.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "io" + "regexp" "strings" "gopkg.in/src-d/go-git.v4/plumbing" @@ -25,9 +26,10 @@ const ( tPath = "+++ %s\n" binary = "Binary files %s and %s differ\n" - addLine = "+%s\n" - deleteLine = "-%s\n" - equalLine = " %s\n" + addLine = "+%s%s" + deleteLine = "-%s%s" + equalLine = " %s%s" + noNewLine = "\n\\ No newline at end of file\n" oldMode = "old mode %o\n" newMode = "new mode %o\n" @@ -216,7 +218,7 @@ func (c *hunksGenerator) processHunk(i int, op Operation) { linesBefore = c.ctxLines } - c.current = &hunk{ctxPrefix: ctxPrefix} + c.current = &hunk{ctxPrefix: strings.TrimSuffix(ctxPrefix, "\n")} c.current.AddOp(Equal, c.beforeContext...) switch op { @@ -279,12 +281,13 @@ func (c *hunksGenerator) processEqualsLines(ls []string, i int) { } } +var splitLinesRE = regexp.MustCompile(`[^\n]*(\n|$)`) + func splitLines(s string) []string { - out := strings.Split(s, "\n") + out := splitLinesRE.FindAllString(s, -1) if out[len(out)-1] == "" { out = out[:len(out)-1] } - return out } @@ -346,7 +349,7 @@ type op struct { } func (o *op) String() string { - var prefix string + var prefix, suffix string switch o.t { case Add: prefix = addLine @@ -355,6 +358,10 @@ func (o *op) String() string { case Equal: prefix = equalLine } + n := len(o.text) + if n > 0 && o.text[n-1] != '\n' { + suffix = noNewLine + } - return fmt.Sprintf(prefix, o.text) + return fmt.Sprintf(prefix, o.text, suffix) } diff --git a/plumbing/format/diff/unified_encoder_test.go b/plumbing/format/diff/unified_encoder_test.go index 7736af19f..091a96a57 100644 --- a/plumbing/format/diff/unified_encoder_test.go +++ b/plumbing/format/diff/unified_encoder_test.go @@ -83,7 +83,7 @@ var oneChunkPatch Patch = testPatch{ content: "A\n", op: Delete, }, { - content: "B\nC\nD\nE\nF\nG", + content: "B\nC\nD\nE\nF\nG\n", op: Equal, }, { content: "H\n", @@ -125,7 +125,7 @@ var oneChunkPatchInverted Patch = testPatch{ content: "A\n", op: Add, }, { - content: "B\nC\nD\nE\nF\nG", + content: "B\nC\nD\nE\nF\nG\n", op: Equal, }, { content: "H\n", @@ -164,13 +164,13 @@ var fixtures []*fixture = []*fixture{{ seed: "hello\nbug\n", }, chunks: []testChunk{{ - content: "hello", + content: "hello\n", op: Equal, }, { - content: "world", + content: "world\n", op: Delete, }, { - content: "bug", + content: "bug\n", op: Add, }}, }}, @@ -239,18 +239,18 @@ rename to test1.txt from: &testFile{ mode: filemode.Regular, path: "test.txt", - seed: "test", + seed: "test\n", }, to: &testFile{ mode: filemode.Regular, path: "test1.txt", - seed: "test1", + seed: "test1\n", }, chunks: []testChunk{{ - content: "test", + content: "test\n", op: Delete, }, { - content: "test1", + content: "test1\n", op: Add, }}, }}, @@ -260,7 +260,7 @@ rename to test1.txt diff: `diff --git a/test.txt b/test1.txt rename from test.txt rename to test1.txt -index 30d74d258442c7c65512eafab474568dd706c430..f079749c42ffdcc5f52ed2d3a6f15b09307e975e 100644 +index 9daeafb9864cf43055ae93beb0afd6c7d144bfa4..a5bce3fd2565d8f458555a0c6f42d0504a848bd5 100644 --- a/test.txt +++ b/test1.txt @@ -1 +1 @@ @@ -299,19 +299,19 @@ rename to test1.txt from: &testFile{ mode: filemode.Regular, path: "test.txt", - seed: "test", + seed: "test\n", }, to: &testFile{ mode: filemode.Regular, path: "test.txt", - seed: "test2", + seed: "test2\n", }, chunks: []testChunk{{ - content: "test", + content: "test\n", op: Delete, }, { - content: "test2", + content: "test2\n", op: Add, }}, }}, @@ -320,7 +320,7 @@ rename to test1.txt desc: "one line change", context: 1, diff: `diff --git a/test.txt b/test.txt -index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d55b2ae9d 100644 +index 9daeafb9864cf43055ae93beb0afd6c7d144bfa4..180cf8328022becee9aaa2577a8f84ea2b9f3827 100644 --- a/test.txt +++ b/test.txt @@ -1 +1 @@ @@ -334,19 +334,19 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d from: &testFile{ mode: filemode.Regular, path: "test.txt", - seed: "test", + seed: "test\n", }, to: &testFile{ mode: filemode.Regular, path: "test.txt", - seed: "test2", + seed: "test2\n", }, chunks: []testChunk{{ - content: "test", + content: "test\n", op: Delete, }, { - content: "test2", + content: "test2\n", op: Add, }}, }}, @@ -356,7 +356,7 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d context: 1, diff: `this is the message diff --git a/test.txt b/test.txt -index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d55b2ae9d 100644 +index 9daeafb9864cf43055ae93beb0afd6c7d144bfa4..180cf8328022becee9aaa2577a8f84ea2b9f3827 100644 --- a/test.txt +++ b/test.txt @@ -1 +1 @@ @@ -397,7 +397,9 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d +++ b/test.txt @@ -1 +1 @@ -test +\ No newline at end of file +test2 +\ No newline at end of file `, }, { patch: testPatch{ @@ -407,7 +409,7 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d to: &testFile{ mode: filemode.Regular, path: "new.txt", - seed: "test\ntest2\test3", + seed: "test\ntest2\ntest3", }, chunks: []testChunk{{ @@ -421,13 +423,14 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d context: 1, diff: `diff --git a/new.txt b/new.txt new file mode 100644 -index 0000000000000000000000000000000000000000..65c8dd02a42273038658a22b1cb29c8d9457ca12 +index 0000000000000000000000000000000000000000..3ceaab5442b64a0c2b33dd25fae67ccdb4fd1ea8 --- /dev/null +++ b/new.txt @@ -0,0 +1,3 @@ +test +test2 +test3 +\ No newline at end of file `, }, { patch: testPatch{ @@ -456,6 +459,7 @@ index 30d74d258442c7c65512eafab474568dd706c430..00000000000000000000000000000000 +++ /dev/null @@ -1 +0,0 @@ -test +\ No newline at end of file `, }, { patch: oneChunkPatch, @@ -548,6 +552,7 @@ index ab5eed5d4a2c33aeef67e0188ee79bed666bde6f..0adddcde4fd38042c354518351820eb0 X Y Z +\ No newline at end of file `, }, { patch: oneChunkPatch, @@ -813,6 +818,47 @@ index 0adddcde4fd38042c354518351820eb06c417c82..553ae669c7a9303cf848fcc749a25692 +++ b/onechunk.txt @@ -23 +22,0 @@ Y -Z +\ No newline at end of file +`, +}, { + patch: testPatch{ + message: "", + filePatches: []testFilePatch{{ + from: &testFile{ + mode: filemode.Regular, + path: "onechunk.txt", + seed: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\nZ", + }, + to: &testFile{ + mode: filemode.Regular, + path: "onechunk.txt", + seed: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY", + }, + + chunks: []testChunk{{ + content: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\n", + op: Equal, + }, { + content: "Y\nZ", + op: Delete, + }, { + content: "Y", + op: Add, + }}, + }}, + }, + desc: "remove last letter and no newline at end of file", + context: 0, + diff: `diff --git a/onechunk.txt b/onechunk.txt +index 0adddcde4fd38042c354518351820eb06c417c82..d39ae38aad7ba9447b5e7998b2e4714f26c9218d 100644 +--- a/onechunk.txt ++++ b/onechunk.txt +@@ -22,2 +21 @@ X +-Y +-Z +\ No newline at end of file ++Y +\ No newline at end of file `, }} diff --git a/plumbing/format/idxfile/decoder.go b/plumbing/format/idxfile/decoder.go index 9e9c1769a..d1a8a2c2b 100644 --- a/plumbing/format/idxfile/decoder.go +++ b/plumbing/format/idxfile/decoder.go @@ -12,7 +12,7 @@ import ( var ( // ErrUnsupportedVersion is returned by Decode when the idx file version // is not supported. - ErrUnsupportedVersion = errors.New("Unsuported version") + ErrUnsupportedVersion = errors.New("Unsupported version") // ErrMalformedIdxFile is returned by Decode when the idx file is corrupted. ErrMalformedIdxFile = errors.New("Malformed IDX file") ) diff --git a/plumbing/format/index/decoder_test.go b/plumbing/format/index/decoder_test.go index 7468ad07c..92d312d50 100644 --- a/plumbing/format/index/decoder_test.go +++ b/plumbing/format/index/decoder_test.go @@ -115,7 +115,7 @@ func (s *IndexSuite) TestDecodeMergeConflict(c *C) { {TheirMode, "14f8e368114f561c38e134f6e68ea6fea12d77ed"}, } - // stagged files + // staged files for i, e := range idx.Entries[4:7] { c.Assert(e.Stage, Equals, expected[i].Stage) c.Assert(e.CreatedAt.IsZero(), Equals, true) diff --git a/plumbing/format/index/encoder_test.go b/plumbing/format/index/encoder_test.go index 78cbbbaef..ea121fc53 100644 --- a/plumbing/format/index/encoder_test.go +++ b/plumbing/format/index/encoder_test.go @@ -55,7 +55,7 @@ func (s *IndexSuite) TestEncode(c *C) { } -func (s *IndexSuite) TestEncodeUnsuportedVersion(c *C) { +func (s *IndexSuite) TestEncodeUnsupportedVersion(c *C) { idx := &Index{Version: 3} buf := bytes.NewBuffer(nil) @@ -64,7 +64,7 @@ func (s *IndexSuite) TestEncodeUnsuportedVersion(c *C) { c.Assert(err, Equals, ErrUnsupportedVersion) } -func (s *IndexSuite) TestEncodeWithIntentToAddUnsuportedVersion(c *C) { +func (s *IndexSuite) TestEncodeWithIntentToAddUnsupportedVersion(c *C) { idx := &Index{ Version: 2, Entries: []*Entry{{IntentToAdd: true}}, @@ -76,7 +76,7 @@ func (s *IndexSuite) TestEncodeWithIntentToAddUnsuportedVersion(c *C) { c.Assert(err, Equals, ErrUnsupportedVersion) } -func (s *IndexSuite) TestEncodeWithSkipWorktreeUnsuportedVersion(c *C) { +func (s *IndexSuite) TestEncodeWithSkipWorktreeUnsupportedVersion(c *C) { idx := &Index{ Version: 2, Entries: []*Entry{{SkipWorktree: true}}, diff --git a/plumbing/format/packfile/parser.go b/plumbing/format/packfile/parser.go index 71cbba983..d8c0f753d 100644 --- a/plumbing/format/packfile/parser.go +++ b/plumbing/format/packfile/parser.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "io" + "io/ioutil" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/cache" @@ -263,11 +264,14 @@ func (p *Parser) indexObjects() error { } func (p *Parser) resolveDeltas() error { + buf := &bytes.Buffer{} for _, obj := range p.oi { - content, err := p.get(obj) + buf.Reset() + err := p.get(obj, buf) if err != nil { return err } + content := buf.Bytes() if err := p.onInflatedObjectHeader(obj.Type, obj.Length, obj.Offset); err != nil { return err @@ -279,7 +283,7 @@ func (p *Parser) resolveDeltas() error { if !obj.IsDelta() && len(obj.Children) > 0 { for _, child := range obj.Children { - if _, err := p.resolveObject(child, content); err != nil { + if err := p.resolveObject(ioutil.Discard, child, content); err != nil { return err } } @@ -294,82 +298,87 @@ func (p *Parser) resolveDeltas() error { return nil } -func (p *Parser) get(o *objectInfo) (b []byte, err error) { - var ok bool +func (p *Parser) get(o *objectInfo, buf *bytes.Buffer) error { if !o.ExternalRef { // skip cache check for placeholder parents - b, ok = p.cache.Get(o.Offset) + b, ok := p.cache.Get(o.Offset) + if ok { + _, err := buf.Write(b) + return err + } } // If it's not on the cache and is not a delta we can try to find it in the // storage, if there's one. External refs must enter here. - if !ok && p.storage != nil && !o.Type.IsDelta() { + if p.storage != nil && !o.Type.IsDelta() { e, err := p.storage.EncodedObject(plumbing.AnyObject, o.SHA1) if err != nil { - return nil, err + return err } o.Type = e.Type() r, err := e.Reader() if err != nil { - return nil, err - } - - b = make([]byte, e.Size()) - if _, err = r.Read(b); err != nil { - return nil, err + return err } - } - if b != nil { - return b, nil + _, err = buf.ReadFrom(io.LimitReader(r, e.Size())) + return err } if o.ExternalRef { // we were not able to resolve a ref in a thin pack - return nil, ErrReferenceDeltaNotFound + return ErrReferenceDeltaNotFound } - var data []byte if o.DiskType.IsDelta() { - base, err := p.get(o.Parent) + b := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(b) + b.Reset() + err := p.get(o.Parent, b) if err != nil { - return nil, err + return err } + base := b.Bytes() - data, err = p.resolveObject(o, base) + err = p.resolveObject(buf, o, base) if err != nil { - return nil, err + return err } } else { - data, err = p.readData(o) + err := p.readData(buf, o) if err != nil { - return nil, err + return err } } if len(o.Children) > 0 { + data := make([]byte, buf.Len()) + copy(data, buf.Bytes()) p.cache.Put(o.Offset, data) } - - return data, nil + return nil } func (p *Parser) resolveObject( + w io.Writer, o *objectInfo, base []byte, -) ([]byte, error) { +) error { if !o.DiskType.IsDelta() { - return nil, nil + return nil } - - data, err := p.readData(o) + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + err := p.readData(buf, o) if err != nil { - return nil, err + return err } + data := buf.Bytes() data, err = applyPatchBase(o, data, base) if err != nil { - return nil, err + return err } if p.storage != nil { @@ -377,37 +386,35 @@ func (p *Parser) resolveObject( obj.SetSize(o.Size()) obj.SetType(o.Type) if _, err := obj.Write(data); err != nil { - return nil, err + return err } if _, err := p.storage.SetEncodedObject(obj); err != nil { - return nil, err + return err } } - - return data, nil + _, err = w.Write(data) + return err } -func (p *Parser) readData(o *objectInfo) ([]byte, error) { +func (p *Parser) readData(w io.Writer, o *objectInfo) error { if !p.scanner.IsSeekable && o.DiskType.IsDelta() { data, ok := p.deltas[o.Offset] if !ok { - return nil, ErrDeltaNotCached + return ErrDeltaNotCached } - - return data, nil + _, err := w.Write(data) + return err } if _, err := p.scanner.SeekObjectHeader(o.Offset); err != nil { - return nil, err + return err } - buf := new(bytes.Buffer) - if _, _, err := p.scanner.NextObject(buf); err != nil { - return nil, err + if _, _, err := p.scanner.NextObject(w); err != nil { + return err } - - return buf.Bytes(), nil + return nil } func applyPatchBase(ota *objectInfo, data, base []byte) ([]byte, error) { diff --git a/plumbing/format/packfile/patch_delta.go b/plumbing/format/packfile/patch_delta.go index a972f1c42..e1a5141b4 100644 --- a/plumbing/format/packfile/patch_delta.go +++ b/plumbing/format/packfile/patch_delta.go @@ -1,8 +1,9 @@ package packfile import ( + "bytes" "errors" - "io/ioutil" + "io" "gopkg.in/src-d/go-git.v4/plumbing" ) @@ -26,19 +27,29 @@ func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) error { return err } - src, err := ioutil.ReadAll(r) + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + _, err = buf.ReadFrom(r) if err != nil { return err } + src := buf.Bytes() - dst, err := PatchDelta(src, delta) + dst := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(dst) + dst.Reset() + err = patchDelta(dst, src, delta) if err != nil { return err } - target.SetSize(int64(len(dst))) - _, err = w.Write(dst) + target.SetSize(int64(dst.Len())) + + b := byteSlicePool.Get().([]byte) + _, err = io.CopyBuffer(w, dst, b) + byteSlicePool.Put(b) return err } @@ -51,23 +62,31 @@ var ( // An error will be returned if delta is corrupted (ErrDeltaLen) or an action command // is not copy from source or copy from delta (ErrDeltaCmd). func PatchDelta(src, delta []byte) ([]byte, error) { + b := &bytes.Buffer{} + if err := patchDelta(b, src, delta); err != nil { + return nil, err + } + return b.Bytes(), nil +} + +func patchDelta(dst *bytes.Buffer, src, delta []byte) error { if len(delta) < deltaSizeMin { - return nil, ErrInvalidDelta + return ErrInvalidDelta } srcSz, delta := decodeLEB128(delta) if srcSz != uint(len(src)) { - return nil, ErrInvalidDelta + return ErrInvalidDelta } targetSz, delta := decodeLEB128(delta) remainingTargetSz := targetSz var cmd byte - dest := make([]byte, 0, targetSz) + dst.Grow(int(targetSz)) for { if len(delta) == 0 { - return nil, ErrInvalidDelta + return ErrInvalidDelta } cmd = delta[0] @@ -77,35 +96,35 @@ func PatchDelta(src, delta []byte) ([]byte, error) { var err error offset, delta, err = decodeOffset(cmd, delta) if err != nil { - return nil, err + return err } sz, delta, err = decodeSize(cmd, delta) if err != nil { - return nil, err + return err } if invalidSize(sz, targetSz) || invalidOffsetSize(offset, sz, srcSz) { break } - dest = append(dest, src[offset:offset+sz]...) + dst.Write(src[offset:offset+sz]) remainingTargetSz -= sz } else if isCopyFromDelta(cmd) { sz := uint(cmd) // cmd is the size itself if invalidSize(sz, targetSz) { - return nil, ErrInvalidDelta + return ErrInvalidDelta } if uint(len(delta)) < sz { - return nil, ErrInvalidDelta + return ErrInvalidDelta } - dest = append(dest, delta[0:sz]...) + dst.Write(delta[0:sz]) remainingTargetSz -= sz delta = delta[sz:] } else { - return nil, ErrDeltaCmd + return ErrDeltaCmd } if remainingTargetSz <= 0 { @@ -113,7 +132,7 @@ func PatchDelta(src, delta []byte) ([]byte, error) { } } - return dest, nil + return nil } // Decodes a number encoded as an unsigned LEB128 at the start of some diff --git a/plumbing/hash.go b/plumbing/hash.go index 8e6087789..637a4252a 100644 --- a/plumbing/hash.go +++ b/plumbing/hash.go @@ -9,7 +9,7 @@ import ( "strconv" ) -// Hash SHA1 hased content +// Hash SHA1 hashed content type Hash [20]byte // ZeroHash is Hash with value zero diff --git a/plumbing/object/commit_stats_test.go b/plumbing/object/commit_stats_test.go index 2fb3f086f..dc9e4ad38 100644 --- a/plumbing/object/commit_stats_test.go +++ b/plumbing/object/commit_stats_test.go @@ -22,7 +22,7 @@ type CommitStatsSuite struct { var _ = Suite(&CommitStatsSuite{}) func (s *CommitStatsSuite) TestStats(c *C) { - r, hash := s.writeHisotry(c, []byte("foo\n"), []byte("foo\nbar\n")) + r, hash := s.writeHistory(c, []byte("foo\n"), []byte("foo\nbar\n")) aCommit, err := r.CommitObject(hash) c.Assert(err, IsNil) @@ -37,7 +37,7 @@ func (s *CommitStatsSuite) TestStats(c *C) { } func (s *CommitStatsSuite) TestStats_RootCommit(c *C) { - r, hash := s.writeHisotry(c, []byte("foo\n")) + r, hash := s.writeHistory(c, []byte("foo\n")) aCommit, err := r.CommitObject(hash) c.Assert(err, IsNil) @@ -53,7 +53,7 @@ func (s *CommitStatsSuite) TestStats_RootCommit(c *C) { } func (s *CommitStatsSuite) TestStats_WithoutNewLine(c *C) { - r, hash := s.writeHisotry(c, []byte("foo\nbar"), []byte("foo\nbar\n")) + r, hash := s.writeHistory(c, []byte("foo\nbar"), []byte("foo\nbar\n")) aCommit, err := r.CommitObject(hash) c.Assert(err, IsNil) @@ -67,7 +67,7 @@ func (s *CommitStatsSuite) TestStats_WithoutNewLine(c *C) { c.Assert(fileStats[0].String(), Equals, " foo | 2 +-\n") } -func (s *CommitStatsSuite) writeHisotry(c *C, files ...[]byte) (*git.Repository, plumbing.Hash) { +func (s *CommitStatsSuite) writeHistory(c *C, files ...[]byte) (*git.Repository, plumbing.Hash) { cm := &git.CommitOptions{ Author: &object.Signature{Name: "Foo", Email: "foo@example.local", When: time.Now()}, } diff --git a/plumbing/object/commit_walker_bfs_filtered.go b/plumbing/object/commit_walker_bfs_filtered.go index b12523d48..7b17f156d 100644 --- a/plumbing/object/commit_walker_bfs_filtered.go +++ b/plumbing/object/commit_walker_bfs_filtered.go @@ -15,7 +15,7 @@ import ( // If the commit history can not be traversed, or the Close() method is called, // the CommitIter won't return more commits. // If no isValid is passed, all ancestors of from commit will be valid. -// If no isLimit is limmit, all ancestors of all commits will be visited. +// If no isLimit is limit, all ancestors of all commits will be visited. func NewFilterCommitIter( from *Commit, isValid *CommitFilter, @@ -50,7 +50,7 @@ func NewFilterCommitIter( // CommitFilter returns a boolean for the passed Commit type CommitFilter func(*Commit) bool -// filterCommitIter implments CommitIter +// filterCommitIter implements CommitIter type filterCommitIter struct { isValid CommitFilter isLimit CommitFilter diff --git a/plumbing/object/commit_walker_file.go b/plumbing/object/commit_walker_file.go index 6f16e611f..b73e4ce9d 100644 --- a/plumbing/object/commit_walker_file.go +++ b/plumbing/object/commit_walker_file.go @@ -128,6 +128,9 @@ func isParentHash(hash plumbing.Hash, commit *Commit) bool { func (c *commitFileIter) ForEach(cb func(*Commit) error) error { for { commit, nextErr := c.Next() + if nextErr == io.EOF { + break + } if nextErr != nil { return nextErr } @@ -138,6 +141,7 @@ func (c *commitFileIter) ForEach(cb func(*Commit) error) error { return err } } + return nil } func (c *commitFileIter) Close() { diff --git a/plumbing/object/commit_walker_limit.go b/plumbing/object/commit_walker_limit.go new file mode 100644 index 000000000..ee56e509e --- /dev/null +++ b/plumbing/object/commit_walker_limit.go @@ -0,0 +1,65 @@ +package object + +import ( + "io" + "time" + + "gopkg.in/src-d/go-git.v4/plumbing/storer" +) + +type commitLimitIter struct { + sourceIter CommitIter + limitOptions LogLimitOptions +} + +type LogLimitOptions struct { + Since *time.Time + Until *time.Time +} + +func NewCommitLimitIterFromIter(commitIter CommitIter, limitOptions LogLimitOptions) CommitIter { + iterator := new(commitLimitIter) + iterator.sourceIter = commitIter + iterator.limitOptions = limitOptions + return iterator +} + +func (c *commitLimitIter) Next() (*Commit, error) { + for { + commit, err := c.sourceIter.Next() + if err != nil { + return nil, err + } + + if c.limitOptions.Since != nil && commit.Committer.When.Before(*c.limitOptions.Since) { + continue + } + if c.limitOptions.Until != nil && commit.Committer.When.After(*c.limitOptions.Until) { + continue + } + return commit, nil + } +} + +func (c *commitLimitIter) ForEach(cb func(*Commit) error) error { + for { + commit, nextErr := c.Next() + if nextErr == io.EOF { + break + } + if nextErr != nil { + return nextErr + } + err := cb(commit) + if err == storer.ErrStop { + return nil + } else if err != nil { + return err + } + } + return nil +} + +func (c *commitLimitIter) Close() { + c.sourceIter.Close() +} diff --git a/plumbing/object/merge_base_test.go b/plumbing/object/merge_base_test.go index 598539d8a..72c9cd940 100644 --- a/plumbing/object/merge_base_test.go +++ b/plumbing/object/merge_base_test.go @@ -48,8 +48,8 @@ candidates result CD1, CD2, M, N CD1, CD2 M and N are reachable from CD2, so they're not C, G, dev, M, N C, G, dev M and N are reachable from G, so they're not C, D, M, N C, D M and N are reachable from C, so they're not - A, A^, A, N, N^ A, N A^ and N^ are rechable from A and N - A^^^, A^, A^^, A, N A, N A^^^, A^^ and A^ are rechable from A, so they're not + A, A^, A, N, N^ A, N A^ and N^ are reachable from A and N + A^^^, A^, A^^, A, N A, N A^^^, A^^ and A^ are reachable from A, so they're not IsAncestor ---------------------------- diff --git a/plumbing/protocol/packp/advrefs_decode.go b/plumbing/protocol/packp/advrefs_decode.go index 1b4c62c89..80f5b4e66 100644 --- a/plumbing/protocol/packp/advrefs_decode.go +++ b/plumbing/protocol/packp/advrefs_decode.go @@ -53,7 +53,7 @@ func (d *advRefsDecoder) Decode(v *AdvRefs) error { type decoderStateFn func(*advRefsDecoder) decoderStateFn -// fills out the parser stiky error +// fills out the parser sticky error func (d *advRefsDecoder) error(format string, a ...interface{}) { msg := fmt.Sprintf( "pkt-line %d: %s", d.nLine, @@ -281,7 +281,7 @@ func decodeShallow(p *advRefsDecoder) decoderStateFn { } if len(p.line) == 0 { - return nil // succesfull parse of the advertised-refs message + return nil // successful parse of the advertised-refs message } return decodeShallow diff --git a/plumbing/protocol/packp/capability/list.go b/plumbing/protocol/packp/capability/list.go index 26a79b6e7..96092112d 100644 --- a/plumbing/protocol/packp/capability/list.go +++ b/plumbing/protocol/packp/capability/list.go @@ -14,8 +14,8 @@ var ( // ErrArguments is returned if arguments are given with a capabilities that // not supports arguments ErrArguments = errors.New("arguments not allowed") - // ErrEmtpyArgument is returned when an empty value is given - ErrEmtpyArgument = errors.New("empty argument") + // ErrEmptyArgument is returned when an empty value is given + ErrEmptyArgument = errors.New("empty argument") // ErrMultipleArguments multiple argument given to a capabilities that not // support it ErrMultipleArguments = errors.New("multiple arguments not allowed") @@ -119,7 +119,7 @@ func (l *List) Add(c Capability, values ...string) error { func (l *List) validateNoEmptyArgs(values []string) error { for _, v := range values { if v == "" { - return ErrEmtpyArgument + return ErrEmptyArgument } } return nil diff --git a/plumbing/protocol/packp/capability/list_test.go b/plumbing/protocol/packp/capability/list_test.go index 82dd63ff3..61b0b13be 100644 --- a/plumbing/protocol/packp/capability/list_test.go +++ b/plumbing/protocol/packp/capability/list_test.go @@ -176,7 +176,7 @@ func (s *SuiteCapabilities) TestAddErrArgumentsNotAllowed(c *check.C) { func (s *SuiteCapabilities) TestAddErrArguments(c *check.C) { cap := NewList() err := cap.Add(SymRef, "") - c.Assert(err, check.Equals, ErrEmtpyArgument) + c.Assert(err, check.Equals, ErrEmptyArgument) } func (s *SuiteCapabilities) TestAddErrMultipleArguments(c *check.C) { diff --git a/plumbing/protocol/packp/ulreq.go b/plumbing/protocol/packp/ulreq.go index 74109d885..72895e308 100644 --- a/plumbing/protocol/packp/ulreq.go +++ b/plumbing/protocol/packp/ulreq.go @@ -68,8 +68,8 @@ func NewUploadRequest() *UploadRequest { } // NewUploadRequestFromCapabilities returns a pointer to a new UploadRequest -// value, the request capabilities are filled with the most optiomal ones, based -// on the adv value (advertaised capabilities), the UploadRequest generated it +// value, the request capabilities are filled with the most optimal ones, based +// on the adv value (advertised capabilities), the UploadRequest generated it // has no wants or shallows and an infinite depth. func NewUploadRequestFromCapabilities(adv *capability.List) *UploadRequest { r := NewUploadRequest() diff --git a/plumbing/protocol/packp/ulreq_encode.go b/plumbing/protocol/packp/ulreq_encode.go index 89a59868d..dcfeb8329 100644 --- a/plumbing/protocol/packp/ulreq_encode.go +++ b/plumbing/protocol/packp/ulreq_encode.go @@ -64,10 +64,10 @@ func (e *ulReqEncoder) encodeFirstWant() stateFn { return nil } - return e.encodeAditionalWants + return e.encodeAdditionalWants } -func (e *ulReqEncoder) encodeAditionalWants() stateFn { +func (e *ulReqEncoder) encodeAdditionalWants() stateFn { last := e.data.Wants[0] for _, w := range e.data.Wants[1:] { if bytes.Equal(last[:], w[:]) { diff --git a/plumbing/protocol/packp/updreq_decode.go b/plumbing/protocol/packp/updreq_decode.go index 51e8183d1..59f095f66 100644 --- a/plumbing/protocol/packp/updreq_decode.go +++ b/plumbing/protocol/packp/updreq_decode.go @@ -13,9 +13,9 @@ import ( ) var ( - shallowLineLength = len(shallow) + hashSize - minCommandLength = hashSize*2 + 2 + 1 - minCommandAndCapsLenth = minCommandLength + 1 + shallowLineLength = len(shallow) + hashSize + minCommandLength = hashSize*2 + 2 + 1 + minCommandAndCapsLength = minCommandLength + 1 ) var ( @@ -46,7 +46,7 @@ func errInvalidShallowLineLength(got int) error { func errInvalidCommandCapabilitiesLineLength(got int) error { return errMalformedRequest(fmt.Sprintf( "invalid command and capabilities line length: expected at least %d, got %d", - minCommandAndCapsLenth, got)) + minCommandAndCapsLength, got)) } func errInvalidCommandLineLength(got int) error { @@ -174,7 +174,7 @@ func (d *updReqDecoder) decodeCommandAndCapabilities() error { return errMissingCapabilitiesDelimiter } - if len(b) < minCommandAndCapsLenth { + if len(b) < minCommandAndCapsLength { return errInvalidCommandCapabilitiesLineLength(len(b)) } diff --git a/plumbing/protocol/packp/uppackreq.go b/plumbing/protocol/packp/uppackreq.go index 114413952..831ef8fc5 100644 --- a/plumbing/protocol/packp/uppackreq.go +++ b/plumbing/protocol/packp/uppackreq.go @@ -27,8 +27,8 @@ func NewUploadPackRequest() *UploadPackRequest { } // NewUploadPackRequestFromCapabilities creates a new UploadPackRequest and -// returns a pointer. The request capabilities are filled with the most optiomal -// ones, based on the adv value (advertaised capabilities), the UploadPackRequest +// returns a pointer. The request capabilities are filled with the most optimal +// ones, based on the adv value (advertised capabilities), the UploadPackRequest // it has no wants, haves or shallows and an infinite depth func NewUploadPackRequestFromCapabilities(adv *capability.List) *UploadPackRequest { ur := NewUploadRequestFromCapabilities(adv) diff --git a/plumbing/storer/object.go b/plumbing/storer/object.go index 98d1ec3fe..c84960a65 100644 --- a/plumbing/storer/object.go +++ b/plumbing/storer/object.go @@ -141,7 +141,7 @@ func NewEncodedObjectLookupIter( // Next returns the next object from the iterator. If the iterator has reached // the end it will return io.EOF as an error. If the object can't be found in // the object storage, it will return plumbing.ErrObjectNotFound as an error. -// If the object is retreieved successfully error will be nil. +// If the object is retrieved successfully error will be nil. func (iter *EncodedObjectLookupIter) Next() (plumbing.EncodedObject, error) { if iter.pos >= len(iter.series) { return nil, io.EOF @@ -187,7 +187,7 @@ func NewEncodedObjectSliceIter(series []plumbing.EncodedObject) *EncodedObjectSl } // Next returns the next object from the iterator. If the iterator has reached -// the end it will return io.EOF as an error. If the object is retreieved +// the end it will return io.EOF as an error. If the object is retrieved // successfully error will be nil. func (iter *EncodedObjectSliceIter) Next() (plumbing.EncodedObject, error) { if len(iter.series) == 0 { diff --git a/plumbing/transport/http/common.go b/plumbing/transport/http/common.go index 38e903d45..16ff9304b 100644 --- a/plumbing/transport/http/common.go +++ b/plumbing/transport/http/common.go @@ -84,7 +84,7 @@ var DefaultClient = NewClient(nil) // Unless a properly initialized client is given, it will fall back into // `http.DefaultClient`. // -// Note that for HTTP client cannot distinguist between private repositories and +// Note that for HTTP client cannot distinguish between private repositories and // unexistent repositories on GitHub. So it returns `ErrAuthorizationRequired` // for both. func NewClient(c *http.Client) transport.Transport { diff --git a/plumbing/transport/internal/common/common.go b/plumbing/transport/internal/common/common.go index 00497f3c1..cb1b6daab 100644 --- a/plumbing/transport/internal/common/common.go +++ b/plumbing/transport/internal/common/common.go @@ -66,7 +66,7 @@ type Command interface { Close() error } -// CommandKiller expands the Command interface, enableing it for being killed. +// CommandKiller expands the Command interface, enabling it for being killed. type CommandKiller interface { // Kill and close the session whatever the state it is. It will block until // the command is terminated. diff --git a/plumbing/transport/internal/common/common_test.go b/plumbing/transport/internal/common/common_test.go index b2f035d71..c60ef3b05 100644 --- a/plumbing/transport/internal/common/common_test.go +++ b/plumbing/transport/internal/common/common_test.go @@ -13,7 +13,7 @@ type CommonSuite struct{} var _ = Suite(&CommonSuite{}) -func (s *CommonSuite) TestIsRepoNotFoundErrorForUnknowSource(c *C) { +func (s *CommonSuite) TestIsRepoNotFoundErrorForUnknownSource(c *C) { msg := "unknown system is complaining of something very sad :(" isRepoNotFound := isRepoNotFoundError(msg) diff --git a/repository.go b/repository.go index 2251d6cfe..11269efa9 100644 --- a/repository.go +++ b/repository.go @@ -1068,6 +1068,11 @@ func (r *Repository) Log(o *LogOptions) (object.CommitIter, error) { it = r.logWithFile(*o.FileName, it, o.All) } + if o.Since != nil || o.Until != nil { + limitOptions := object.LogLimitOptions{Since: o.Since, Until: o.Until} + it = r.logWithLimit(it, limitOptions) + } + return it, nil } @@ -1097,6 +1102,10 @@ func (*Repository) logWithFile(fileName string, commitIter object.CommitIter, ch return object.NewCommitFileIterFromIter(fileName, commitIter, checkParent) } +func (*Repository) logWithLimit(commitIter object.CommitIter, limitOptions object.LogLimitOptions) object.CommitIter { + return object.NewCommitLimitIterFromIter(commitIter, limitOptions) +} + func commitIterFunc(order LogOrder) func(c *object.Commit) object.CommitIter { switch order { case LogOrderDefault: diff --git a/repository_test.go b/repository_test.go index b87eabbf6..e85311f2e 100644 --- a/repository_test.go +++ b/repository_test.go @@ -3,6 +3,7 @@ package git import ( "bytes" "context" + "errors" "fmt" "io" "io/ioutil" @@ -13,6 +14,8 @@ import ( "testing" "time" + fixtures "gopkg.in/src-d/go-git-fixtures.v3" + "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/armor" openpgperr "golang.org/x/crypto/openpgp/errors" @@ -31,7 +34,6 @@ import ( "gopkg.in/src-d/go-billy.v4/memfs" "gopkg.in/src-d/go-billy.v4/osfs" "gopkg.in/src-d/go-billy.v4/util" - "gopkg.in/src-d/go-git-fixtures.v3" ) type RepositorySuite struct { @@ -1507,12 +1509,13 @@ func (s *RepositorySuite) TestLogFileForEach(c *C) { } expectedIndex := 0 - cIter.ForEach(func(commit *object.Commit) error { + err = cIter.ForEach(func(commit *object.Commit) error { expectedCommitHash := commitOrder[expectedIndex] c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) expectedIndex++ return nil }) + c.Assert(err, IsNil) c.Assert(expectedIndex, Equals, 1) } @@ -1551,12 +1554,13 @@ func (s *RepositorySuite) TestLogAllFileForEach(c *C) { } expectedIndex := 0 - cIter.ForEach(func(commit *object.Commit) error { + err = cIter.ForEach(func(commit *object.Commit) error { expectedCommitHash := commitOrder[expectedIndex] c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) expectedIndex++ return nil }) + c.Assert(err, IsNil) c.Assert(expectedIndex, Equals, 1) } @@ -1598,12 +1602,13 @@ func (s *RepositorySuite) TestLogFileInitialCommit(c *C) { } expectedIndex := 0 - cIter.ForEach(func(commit *object.Commit) error { + err = cIter.ForEach(func(commit *object.Commit) error { expectedCommitHash := commitOrder[expectedIndex] c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) expectedIndex++ return nil }) + c.Assert(err, IsNil) c.Assert(expectedIndex, Equals, 1) } @@ -1649,6 +1654,157 @@ func (s *RepositorySuite) TestLogFileWithOtherParamsPass(c *C) { c.Assert(iterErr, Equals, io.EOF) } +type mockErrCommitIter struct{} + +func (m *mockErrCommitIter) Next() (*object.Commit, error) { + return nil, errors.New("mock next error") +} +func (m *mockErrCommitIter) ForEach(func(*object.Commit) error) error { + return errors.New("mock foreach error") +} + +func (m *mockErrCommitIter) Close() {} + +func (s *RepositorySuite) TestLogFileWithError(c *C) { + fileName := "README" + cIter := object.NewCommitFileIterFromIter(fileName, &mockErrCommitIter{}, false) + defer cIter.Close() + + err := cIter.ForEach(func(commit *object.Commit) error { + return nil + }) + c.Assert(err, NotNil) +} + +func (s *RepositorySuite) TestLogLimitNext(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + since := time.Date(2015, 4, 1, 0, 0, 0, 0, time.UTC) + cIter, err := r.Log(&LogOptions{Since: &since}) + + c.Assert(err, IsNil) + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + } + + 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) +} + +func (s *RepositorySuite) TestLogLimitForEach(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + since := time.Date(2015, 3, 31, 11, 54, 0, 0, time.UTC) + until := time.Date(2015, 4, 1, 0, 0, 0, 0, time.UTC) + cIter, err := r.Log(&LogOptions{Since: &since, Until: &until}) + c.Assert(err, IsNil) + defer cIter.Close() + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), + } + + expectedIndex := 0 + err = cIter.ForEach(func(commit *object.Commit) error { + expectedCommitHash := commitOrder[expectedIndex] + c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) + expectedIndex++ + return nil + }) + c.Assert(err, IsNil) + c.Assert(expectedIndex, Equals, 1) +} + +func (s *RepositorySuite) TestLogAllLimitForEach(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + since := time.Date(2015, 3, 31, 11, 54, 0, 0, time.UTC) + until := time.Date(2015, 4, 1, 0, 0, 0, 0, time.UTC) + cIter, err := r.Log(&LogOptions{Since: &since, Until: &until, All: true}) + c.Assert(err, IsNil) + defer cIter.Close() + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), + plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), + } + + expectedIndex := 0 + err = cIter.ForEach(func(commit *object.Commit) error { + expectedCommitHash := commitOrder[expectedIndex] + c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) + expectedIndex++ + return nil + }) + c.Assert(err, IsNil) + c.Assert(expectedIndex, Equals, 2) +} + +func (s *RepositorySuite) TestLogLimitWithOtherParamsFail(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + + since := time.Date(2015, 3, 31, 11, 54, 0, 0, time.UTC) + cIter, err := r.Log(&LogOptions{ + Order: LogOrderCommitterTime, + Since: &since, + From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + }) + c.Assert(err, IsNil) + defer cIter.Close() + + _, iterErr := cIter.Next() + c.Assert(iterErr, Equals, io.EOF) +} + +func (s *RepositorySuite) TestLogLimitWithOtherParamsPass(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + + until := time.Date(2015, 3, 31, 11, 43, 0, 0, time.UTC) + cIter, err := r.Log(&LogOptions{ + Order: LogOrderCommitterTime, + Until: &until, + From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + }) + c.Assert(err, IsNil) + defer cIter.Close() + + commitVal, iterErr := cIter.Next() + c.Assert(iterErr, Equals, nil) + c.Assert(commitVal.Hash.String(), Equals, "b029517f6300c2da0f4b651b8642506cd6aaf45d") + + _, iterErr = cIter.Next() + c.Assert(iterErr, Equals, io.EOF) +} + func (s *RepositorySuite) TestCommit(c *C) { r, _ := Init(memory.NewStorage(), nil) err := r.clone(context.Background(), &CloneOptions{ diff --git a/storage/memory/storage.go b/storage/memory/storage.go index f240f2a1f..fee826659 100644 --- a/storage/memory/storage.go +++ b/storage/memory/storage.go @@ -15,7 +15,7 @@ import ( var ErrUnsupportedObjectType = fmt.Errorf("unsupported object type") // 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, +// ephemeral. The use of this storage should be done in controlled environments, // 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 { diff --git a/utils/diff/diff_ext_test.go b/utils/diff/diff_ext_test.go index adda27691..c6c7e9006 100644 --- a/utils/diff/diff_ext_test.go +++ b/utils/diff/diff_ext_test.go @@ -99,6 +99,37 @@ var doTests = [...]struct { {Type: 1, Text: "111\nBCD\n"}, }, }, + { + src: "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\nN\nÑ\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ", + dst: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\nZ", + exp: []diffmatchpatch.Diff{ + {Type: -1, Text: "A\n"}, + {Type: 0, Text: "B\nC\nD\nE\nF\nG\n"}, + {Type: -1, Text: "H\n"}, + {Type: 0, Text: "I\nJ\nK\nL\nM\nN\n"}, + {Type: -1, Text: "Ñ\n"}, + {Type: 0, Text: "O\nP\nQ\nR\nS\nT\n"}, + {Type: -1, Text: "U\n"}, + {Type: 0, Text: "V\nW\nX\nY\nZ"}, + }, + }, + { + src: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\nZ", + dst: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\n", + exp: []diffmatchpatch.Diff{ + {Type: 0, Text: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\n"}, + {Type: -1, Text: "Z"}, + }, + }, + { + src: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\nZ", + dst: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY", + exp: []diffmatchpatch.Diff{ + {Type: 0, Text: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\n"}, + {Type: -1, Text: "Y\nZ"}, + {Type: 1, Text: "Y"}, + }, + }, } func (s *suiteCommon) TestDo(c *C) { diff --git a/utils/merkletrie/difftree.go b/utils/merkletrie/difftree.go index d57ed1333..77ba5a8e4 100644 --- a/utils/merkletrie/difftree.go +++ b/utils/merkletrie/difftree.go @@ -8,7 +8,7 @@ package merkletrie // type defined in this same package; we will iterate over both // trees at the same time, while comparing the current noders in // each iterator. Depending on how they differ we will output the -// corresponding chages and move the iterators further over both +// corresponding changes and move the iterators further over both // trees. // // The table bellow show all the possible comparison results, along @@ -69,7 +69,7 @@ package merkletrie // // ### C. To was created: 01, 02, 03, 04, 05, 06 // - check: `DifferentName() && ToBeforeFrom()` -// - action: inserRecursively(to) +// - action: insertRecursively(to) // - advance: `ToNext()` // // ### D. From was deleted: 10, 20, 30, 40, 50, 60 @@ -131,13 +131,13 @@ package merkletrie // - action: `DeleteDir(from); InsertFile(to)` // - advance: `FromNext(); ToNext()` // -// ### J. file with contents to dir with contetns: 25, 26, 35, 36 +// ### J. file with contents to dir with contents: 25, 26, 35, 36 // - check: `SameName() && DifferentHash() && FromIsFile() && // FromIsNotEmpty() && ToIsDir() && ToIsNotEmpty()` // - action: `DeleteFile(from); InsertDirRecursively(to)` // - advance: `FromNext(); ToNext()` // -// ### J'. dir with contetns to file with contents: 52, 62, 53, 63 +// ### J'. dir with contents to file with contents: 52, 62, 53, 63 // - check: `SameName() && DifferentHash() && FromIsDir() && // FromIsNotEmpty() && ToIsFile() && ToIsNotEmpty()` // - action: `DeleteDirRecursively(from); InsertFile(to)` @@ -216,7 +216,7 @@ package merkletrie // 1 0 1 0 1 0 | a() | a<1> | I' | f | delete(from); insert(to); NN // 1 0 1 0 1 1 | a() | a<> | F' | f | delete(from); insert(to); NN // 1 0 1 1 0 0 | a(...) | a(;;;) | L | g | nothing; SS -// 1 0 1 1 0 1 | a(...) | a() | K' | h | deleteChidren(from); NN +// 1 0 1 1 0 1 | a(...) | a() | K' | h | deleteChildren(from); NN // 1 0 1 1 1 0 | a() | a(...) | K | i | insertChildren(to); NN // 1 0 1 1 1 1 | ---- | ---- | | | // 1 1 0 0 0 0 | a<1> | a<1> | B | b | nothing; NN diff --git a/utils/merkletrie/internal/frame/frame.go b/utils/merkletrie/internal/frame/frame.go index a0b042ee6..77a3de4f9 100644 --- a/utils/merkletrie/internal/frame/frame.go +++ b/utils/merkletrie/internal/frame/frame.go @@ -38,7 +38,7 @@ func New(n noder.Noder) (*Frame, error) { } // String returns the quoted names of the noders in the frame sorted in -// alphabeticall order by name, surrounded by square brackets and +// alphabetical order by name, surrounded by square brackets and // separated by comas. // // Examples: @@ -61,7 +61,7 @@ func (f *Frame) String() string { } // First returns, but dont extract, the noder with the alphabetically -// smaller name in the frame and true if the frame was not empy. +// smaller name in the frame and true if the frame was not empty. // Otherwise it returns nil and false. func (f *Frame) First() (noder.Noder, bool) { if f.Len() == 0 { diff --git a/utils/merkletrie/internal/fsnoder/doc.go b/utils/merkletrie/internal/fsnoder/doc.go index 3f55b5f7d..c79ac5922 100644 --- a/utils/merkletrie/internal/fsnoder/doc.go +++ b/utils/merkletrie/internal/fsnoder/doc.go @@ -30,7 +30,7 @@ Directories are expressed as: - its elements between parents, separated with spaces, in any order. -- (optionally) the root directory can be unnamed, by skiping its name. +- (optionally) the root directory can be unnamed, by skipping its name. Examples: diff --git a/utils/merkletrie/internal/fsnoder/file.go b/utils/merkletrie/internal/fsnoder/file.go index c975a6048..686a675aa 100644 --- a/utils/merkletrie/internal/fsnoder/file.go +++ b/utils/merkletrie/internal/fsnoder/file.go @@ -60,7 +60,7 @@ const ( fileEndMark = '>' ) -// String returns a string formated as: name. +// String returns a string formatted as: name. func (f *file) String() string { var buf bytes.Buffer buf.WriteString(f.name) diff --git a/utils/merkletrie/internal/fsnoder/new_test.go b/utils/merkletrie/internal/fsnoder/new_test.go index 805772f97..a2c474afd 100644 --- a/utils/merkletrie/internal/fsnoder/new_test.go +++ b/utils/merkletrie/internal/fsnoder/new_test.go @@ -176,7 +176,7 @@ func (s *FSNoderSuite) TestEmptyDir(c *C) { check(c, input, expected) } -func (s *FSNoderSuite) TestDirWithEmtpyFile(c *C) { +func (s *FSNoderSuite) TestDirWithEmptyFile(c *C) { input := "(A(a<>))" a, err := newFile("a", "") @@ -189,7 +189,7 @@ func (s *FSNoderSuite) TestDirWithEmtpyFile(c *C) { check(c, input, expected) } -func (s *FSNoderSuite) TestDirWithEmtpyFileSameName(c *C) { +func (s *FSNoderSuite) TestDirWithEmptyFileSameName(c *C) { input := "(A(A<>))" f, err := newFile("A", "") diff --git a/utils/merkletrie/iter_test.go b/utils/merkletrie/iter_test.go index b334cf108..3b240434e 100644 --- a/utils/merkletrie/iter_test.go +++ b/utils/merkletrie/iter_test.go @@ -95,7 +95,7 @@ func (t test) run(c *C, iter *merkletrie.Iter, } // A testsCollection value represents a tree and a collection of tests -// we want to perfrom on iterators of that tree. +// we want to perform on iterators of that tree. // // Example: // diff --git a/worktree_linux.go b/worktree_linux.go index efb01b5a5..891cb1cf3 100644 --- a/worktree_linux.go +++ b/worktree_linux.go @@ -12,7 +12,7 @@ import ( func init() { fillSystemInfo = func(e *index.Entry, sys interface{}) { if os, ok := sys.(*syscall.Stat_t); ok { - e.CreatedAt = time.Unix(os.Ctim.Sec, os.Ctim.Nsec) + e.CreatedAt = time.Unix(int64(os.Ctim.Sec), int64(os.Ctim.Nsec)) e.Dev = uint32(os.Dev) e.Inode = uint32(os.Ino) e.GID = os.Gid