aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2017-07-26 14:41:59 +0200
committerGitHub <noreply@github.com>2017-07-26 14:41:59 +0200
commite19163e22eb19b352dd022f6edc9d81e1cd7a7ed (patch)
treeca08a52fdb31bd90637cec71351578436f254b4b
parentd7b898ea3be0342f064ad63f93aaffdb6518a5b3 (diff)
parent064051f972e90dd55e6c941f04b58b4a36dfedf1 (diff)
downloadgo-git-e19163e22eb19b352dd022f6edc9d81e1cd7a7ed.tar.gz
Merge pull request #509 from mcuadros/ctx-main
*: package context support in Repository, Remote and Submodule
-rw-r--r--remote.go55
-rw-r--r--remote_test.go41
-rw-r--r--repository.go83
-rw-r--r--repository_test.go117
-rw-r--r--submodule.go37
-rw-r--r--submodule_test.go12
-rw-r--r--worktree.go18
-rw-r--r--worktree_test.go3
8 files changed, 300 insertions, 66 deletions
diff --git a/remote.go b/remote.go
index 64b12ed..fe44009 100644
--- a/remote.go
+++ b/remote.go
@@ -52,6 +52,16 @@ func (r *Remote) String() string {
// Push performs a push to the remote. Returns NoErrAlreadyUpToDate if the
// remote was already up-to-date.
func (r *Remote) Push(o *PushOptions) error {
+ return r.PushContext(context.Background(), o)
+}
+
+// PushContext performs a push to the remote. Returns NoErrAlreadyUpToDate if
+// the remote was already up-to-date.
+//
+// The provided Context must be non-nil. If the context expires before the
+// operation is complete, an error is returned. The context only affects to the
+// transport operations.
+func (r *Remote) PushContext(ctx context.Context, o *PushOptions) error {
// TODO: Sideband support
if err := o.Validate(); err != nil {
return err
@@ -124,7 +134,7 @@ func (r *Remote) Push(o *PushOptions) error {
return err
}
- rs, err := pushHashes(s, r.s, req, hashesToPush)
+ rs, err := pushHashes(ctx, s, r.s, req, hashesToPush)
if err != nil {
return err
}
@@ -165,14 +175,30 @@ func (r *Remote) updateRemoteReferenceStorage(
return nil
}
-// Fetch fetches references from the remote to the local repository.
-// no changes to be fetched and no local references to update, or an error.
-func (r *Remote) Fetch(o *FetchOptions) error {
- _, err := r.fetch(o)
+// FetchContext fetches references along with the objects necessary to complete
+// their histories.
+//
+// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
+// no changes to be fetched, or an error.
+//
+// The provided Context must be non-nil. If the context expires before the
+// operation is complete, an error is returned. The context only affects to the
+// transport operations.
+func (r *Remote) FetchContext(ctx context.Context, o *FetchOptions) error {
+ _, err := r.fetch(ctx, o)
return err
}
-func (r *Remote) fetch(o *FetchOptions) (storer.ReferenceStorer, error) {
+// Fetch fetches references along with the objects necessary to complete their
+// histories.
+//
+// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
+// no changes to be fetched, or an error.
+func (r *Remote) Fetch(o *FetchOptions) error {
+ return r.FetchContext(context.Background(), o)
+}
+
+func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (storer.ReferenceStorer, error) {
if o.RemoteName == "" {
o.RemoteName = r.c.Name
}
@@ -219,7 +245,7 @@ func (r *Remote) fetch(o *FetchOptions) (storer.ReferenceStorer, error) {
return nil, err
}
- if err := r.fetchPack(o, s, req); err != nil {
+ if err := r.fetchPack(ctx, o, s, req); err != nil {
return nil, err
}
}
@@ -268,10 +294,10 @@ func newClient(url string) (transport.Transport, transport.Endpoint, error) {
return c, ep, err
}
-func (r *Remote) fetchPack(o *FetchOptions, s transport.UploadPackSession,
+func (r *Remote) fetchPack(ctx context.Context, o *FetchOptions, s transport.UploadPackSession,
req *packp.UploadPackRequest) (err error) {
- reader, err := s.UploadPack(context.TODO(), req)
+ reader, err := s.UploadPack(ctx, req)
if err != nil {
return err
}
@@ -698,8 +724,13 @@ func referencesToHashes(refs storer.ReferenceStorer) ([]plumbing.Hash, error) {
return hs, nil
}
-func pushHashes(sess transport.ReceivePackSession, sto storer.EncodedObjectStorer,
- req *packp.ReferenceUpdateRequest, hs []plumbing.Hash) (*packp.ReportStatus, error) {
+func pushHashes(
+ ctx context.Context,
+ sess transport.ReceivePackSession,
+ sto storer.EncodedObjectStorer,
+ req *packp.ReferenceUpdateRequest,
+ hs []plumbing.Hash,
+) (*packp.ReportStatus, error) {
rd, wr := io.Pipe()
req.Packfile = rd
@@ -714,7 +745,7 @@ func pushHashes(sess transport.ReceivePackSession, sto storer.EncodedObjectStore
done <- wr.Close()
}()
- rs, err := sess.ReceivePack(context.TODO(), req)
+ rs, err := sess.ReceivePack(ctx, req)
if err != nil {
return nil, err
}
diff --git a/remote_test.go b/remote_test.go
index 43276c2..ece052a 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -2,6 +2,7 @@ package git
import (
"bytes"
+ "context"
"io"
"io/ioutil"
"os"
@@ -98,6 +99,23 @@ func (s *RemoteSuite) TestFetch(c *C) {
})
}
+func (s *RemoteSuite) TestFetchContext(c *C) {
+ r := newRemote(memory.NewStorage(), &config.RemoteConfig{
+ URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()),
+ })
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ err := r.FetchContext(ctx, &FetchOptions{
+ RefSpecs: []config.RefSpec{
+ config.RefSpec("+refs/heads/master:refs/remotes/origin/master"),
+ },
+ })
+ c.Assert(err, NotNil)
+
+}
+
func (s *RemoteSuite) TestFetchWithAllTags(c *C) {
r := newRemote(memory.NewStorage(), &config.RemoteConfig{
URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()),
@@ -340,6 +358,29 @@ func (s *RemoteSuite) TestPushToEmptyRepository(c *C) {
}
+func (s *RemoteSuite) TestPushContext(c *C) {
+ url := c.MkDir()
+ _, err := PlainInit(url, true)
+ c.Assert(err, IsNil)
+
+ fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit()
+ sto, err := filesystem.NewStorage(fs)
+ c.Assert(err, IsNil)
+
+ r := newRemote(sto, &config.RemoteConfig{
+ Name: DefaultRemoteName,
+ URL: url,
+ })
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ err = r.PushContext(ctx, &PushOptions{
+ RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"},
+ })
+ c.Assert(err, NotNil)
+}
+
func (s *RemoteSuite) TestPushTags(c *C) {
url := c.MkDir()
server, err := PlainInit(url, true)
diff --git a/repository.go b/repository.go
index 014b92d..b80f8d9 100644
--- a/repository.go
+++ b/repository.go
@@ -1,6 +1,7 @@
package git
import (
+ "context"
"errors"
"fmt"
stdioutil "io/ioutil"
@@ -168,19 +169,36 @@ func Open(s storage.Storer, worktree billy.Filesystem) (*Repository, error) {
// Clone a repository into the given Storer and worktree Filesystem with the
// given options, if worktree is nil a bare repository is created. If the given
-// storer is not empty ErrRepositoryAlreadyExists is returned
+// storer is not empty ErrRepositoryAlreadyExists is returned.
+//
+// The provided Context must be non-nil. If the context expires before the
+// operation is complete, an error is returned. The context only affects to the
+// transport operations.
func Clone(s storage.Storer, worktree billy.Filesystem, o *CloneOptions) (*Repository, error) {
+ return CloneContext(context.Background(), s, worktree, o)
+}
+
+// CloneContext a repository into the given Storer and worktree Filesystem with
+// the given options, if worktree is nil a bare repository is created. If the
+// given storer is not empty ErrRepositoryAlreadyExists is returned.
+//
+// The provided Context must be non-nil. If the context expires before the
+// operation is complete, an error is returned. The context only affects to the
+// transport operations.
+func CloneContext(
+ ctx context.Context, s storage.Storer, worktree billy.Filesystem, o *CloneOptions,
+) (*Repository, error) {
r, err := Init(s, worktree)
if err != nil {
return nil, err
}
- return r, r.clone(o)
+ return r, r.clone(ctx, o)
}
// PlainInit create an empty git repository at the given path. isBare defines
// if the repository will have worktree (non-bare) or not (bare), if the path
-// is not empty ErrRepositoryAlreadyExists is returned
+// is not empty ErrRepositoryAlreadyExists is returned.
func PlainInit(path string, isBare bool) (*Repository, error) {
var wt, dot billy.Filesystem
@@ -279,14 +297,25 @@ func dotGitFileToOSFilesystem(path string, fs billy.Filesystem) (billy.Filesyste
// PlainClone a repository into the path with the given options, isBare defines
// if the new repository will be bare or normal. If the path is not empty
-// ErrRepositoryAlreadyExists is returned
+// ErrRepositoryAlreadyExists is returned.
func PlainClone(path string, isBare bool, o *CloneOptions) (*Repository, error) {
+ return PlainCloneContext(context.Background(), path, isBare, o)
+}
+
+// PlainCloneContext a repository into the path with the given options, isBare
+// defines if the new repository will be bare or normal. If the path is not empty
+// ErrRepositoryAlreadyExists is returned.
+//
+// The provided Context must be non-nil. If the context expires before the
+// operation is complete, an error is returned. The context only affects to the
+// transport operations.
+func PlainCloneContext(ctx context.Context, path string, isBare bool, o *CloneOptions) (*Repository, error) {
r, err := PlainInit(path, isBare)
if err != nil {
return nil, err
}
- return r, r.clone(o)
+ return r, r.clone(ctx, o)
}
func newRepository(s storage.Storer, worktree billy.Filesystem) *Repository {
@@ -372,7 +401,7 @@ func (r *Repository) DeleteRemote(name string) error {
}
// Clone clones a remote repository
-func (r *Repository) clone(o *CloneOptions) error {
+func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
if err := o.Validate(); err != nil {
return err
}
@@ -386,7 +415,7 @@ func (r *Repository) clone(o *CloneOptions) error {
return err
}
- head, err := r.fetchAndUpdateReferences(&FetchOptions{
+ head, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
RefSpecs: r.cloneRefSpec(o, c),
Depth: o.Depth,
Auth: o.Auth,
@@ -469,7 +498,7 @@ func (r *Repository) updateRemoteConfigIfNeeded(o *CloneOptions, c *config.Remot
}
func (r *Repository) fetchAndUpdateReferences(
- o *FetchOptions, ref plumbing.ReferenceName,
+ ctx context.Context, o *FetchOptions, ref plumbing.ReferenceName,
) (*plumbing.Reference, error) {
if err := o.Validate(); err != nil {
@@ -482,7 +511,7 @@ func (r *Repository) fetchAndUpdateReferences(
}
objsUpdated := true
- remoteRefs, err := remote.fetch(o)
+ remoteRefs, err := remote.fetch(ctx, o)
if err == NoErrAlreadyUpToDate {
objsUpdated = false
} else if err != nil {
@@ -581,10 +610,25 @@ func updateReferenceStorerIfNeeded(
return false, nil
}
-// Fetch fetches changes from a remote repository.
+// Fetch fetches references along with the objects necessary to complete
+// their histories, from the remote named as FetchOptions.RemoteName.
+//
// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
// no changes to be fetched, or an error.
func (r *Repository) Fetch(o *FetchOptions) error {
+ return r.FetchContext(context.Background(), o)
+}
+
+// FetchContext fetches references along with the objects necessary to complete
+// their histories, from the remote named as FetchOptions.RemoteName.
+//
+// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
+// no changes to be fetched, or an error.
+//
+// The provided Context must be non-nil. If the context expires before the
+// operation is complete, an error is returned. The context only affects to the
+// transport operations.
+func (r *Repository) FetchContext(ctx context.Context, o *FetchOptions) error {
if err := o.Validate(); err != nil {
return err
}
@@ -594,11 +638,24 @@ func (r *Repository) Fetch(o *FetchOptions) error {
return err
}
- return remote.Fetch(o)
+ return remote.FetchContext(ctx, o)
}
-// Push pushes changes to a remote.
+// Push performs a push to the remote. Returns NoErrAlreadyUpToDate if
+// the remote was already up-to-date, from the remote named as
+// FetchOptions.RemoteName.
func (r *Repository) Push(o *PushOptions) error {
+ return r.PushContext(context.Background(), o)
+}
+
+// PushContext performs a push to the remote. Returns NoErrAlreadyUpToDate if
+// the remote was already up-to-date, from the remote named as
+// FetchOptions.RemoteName.
+//
+// The provided Context must be non-nil. If the context expires before the
+// operation is complete, an error is returned. The context only affects to the
+// transport operations.
+func (r *Repository) PushContext(ctx context.Context, o *PushOptions) error {
if err := o.Validate(); err != nil {
return err
}
@@ -608,7 +665,7 @@ func (r *Repository) Push(o *PushOptions) error {
return err
}
- return remote.Push(o)
+ return remote.PushContext(ctx, o)
}
// Log returns the commit history from the given LogOptions.
diff --git a/repository_test.go b/repository_test.go
index 3cc8d48..7f984f6 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -2,6 +2,7 @@ package git
import (
"bytes"
+ "context"
"fmt"
"io"
"io/ioutil"
@@ -165,6 +166,17 @@ func (s *RepositorySuite) TestClone(c *C) {
c.Assert(remotes, HasLen, 1)
}
+func (s *RepositorySuite) TestCloneContext(c *C) {
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ _, err := CloneContext(ctx, memory.NewStorage(), nil, &CloneOptions{
+ URL: s.GetBasicLocalRepositoryURL(),
+ })
+
+ c.Assert(err, NotNil)
+}
+
func (s *RepositorySuite) TestCreateRemoteAndRemote(c *C) {
r, _ := Init(memory.NewStorage(), nil)
remote, err := r.CreateRemote(&config.RemoteConfig{
@@ -370,11 +382,7 @@ func (s *RepositorySuite) TestPlainOpenNotExists(c *C) {
}
func (s *RepositorySuite) TestPlainClone(c *C) {
- dir, err := ioutil.TempDir("", "plain-clone")
- c.Assert(err, IsNil)
- defer os.RemoveAll(dir)
-
- r, err := PlainClone(dir, false, &CloneOptions{
+ r, err := PlainClone(c.MkDir(), false, &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
@@ -385,6 +393,17 @@ func (s *RepositorySuite) TestPlainClone(c *C) {
c.Assert(remotes, HasLen, 1)
}
+func (s *RepositorySuite) TestPlainCloneContext(c *C) {
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ _, err := PlainCloneContext(ctx, c.MkDir(), false, &CloneOptions{
+ URL: s.GetBasicLocalRepositoryURL(),
+ })
+
+ c.Assert(err, NotNil)
+}
+
func (s *RepositorySuite) TestPlainCloneWithRecurseSubmodules(c *C) {
dir, err := ioutil.TempDir("", "plain-clone-submodule")
c.Assert(err, IsNil)
@@ -426,6 +445,20 @@ func (s *RepositorySuite) TestFetch(c *C) {
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
}
+func (s *RepositorySuite) TestFetchContext(c *C) {
+ r, _ := Init(memory.NewStorage(), nil)
+ _, err := r.CreateRemote(&config.RemoteConfig{
+ Name: DefaultRemoteName,
+ URL: s.GetBasicLocalRepositoryURL(),
+ })
+ c.Assert(err, IsNil)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ c.Assert(r.FetchContext(ctx, &FetchOptions{}), NotNil)
+}
+
func (s *RepositorySuite) TestCloneWithProgress(c *C) {
fs := memfs.New()
@@ -447,7 +480,7 @@ func (s *RepositorySuite) TestCloneDeep(c *C) {
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
c.Assert(head, IsNil)
- err = r.clone(&CloneOptions{
+ err = r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
@@ -486,7 +519,7 @@ func (s *RepositorySuite) TestCloneConfig(c *C) {
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
c.Assert(head, IsNil)
- err = r.clone(&CloneOptions{
+ err = r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
@@ -508,7 +541,7 @@ func (s *RepositorySuite) TestCloneSingleBranchAndNonHEAD(c *C) {
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
c.Assert(head, IsNil)
- err = r.clone(&CloneOptions{
+ err = r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
ReferenceName: plumbing.ReferenceName("refs/heads/branch"),
SingleBranch: true,
@@ -545,7 +578,7 @@ func (s *RepositorySuite) TestCloneSingleBranch(c *C) {
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
c.Assert(head, IsNil)
- err = r.clone(&CloneOptions{
+ err = r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
SingleBranch: true,
})
@@ -576,7 +609,7 @@ func (s *RepositorySuite) TestCloneSingleBranch(c *C) {
func (s *RepositorySuite) TestCloneDetachedHEAD(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{
+ err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"),
})
@@ -590,6 +623,7 @@ func (s *RepositorySuite) TestCloneDetachedHEAD(c *C) {
func (s *RepositorySuite) TestPush(c *C) {
url := c.MkDir()
+ fmt.Println(url)
server, err := PlainInit(url, true)
c.Assert(err, IsNil)
@@ -615,6 +649,27 @@ func (s *RepositorySuite) TestPush(c *C) {
})
}
+func (s *RepositorySuite) TestPushContext(c *C) {
+ url := c.MkDir()
+ fmt.Println(url)
+ _, err := PlainInit(url, true)
+ c.Assert(err, IsNil)
+
+ _, err = s.Repository.CreateRemote(&config.RemoteConfig{
+ Name: "foo",
+ URL: url,
+ })
+ c.Assert(err, IsNil)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ err = s.Repository.PushContext(ctx, &PushOptions{
+ RemoteName: "foo",
+ })
+ c.Assert(err, NotNil)
+}
+
func (s *RepositorySuite) TestPushDepth(c *C) {
url := c.MkDir()
server, err := PlainClone(url, true, &CloneOptions{
@@ -670,7 +725,7 @@ func (s *RepositorySuite) TestPushNonExistentRemote(c *C) {
func (s *RepositorySuite) TestLog(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{
+ err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
@@ -698,7 +753,7 @@ func (s *RepositorySuite) TestLog(c *C) {
func (s *RepositorySuite) TestLogHead(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{
+ err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
@@ -730,7 +785,7 @@ func (s *RepositorySuite) TestLogHead(c *C) {
func (s *RepositorySuite) TestLogError(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{
+ err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
@@ -744,7 +799,7 @@ func (s *RepositorySuite) TestLogError(c *C) {
func (s *RepositorySuite) TestCommit(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{
+ err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
@@ -768,7 +823,7 @@ func (s *RepositorySuite) TestCommit(c *C) {
func (s *RepositorySuite) TestCommits(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
+ err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
count := 0
@@ -791,7 +846,7 @@ func (s *RepositorySuite) TestCommits(c *C) {
func (s *RepositorySuite) TestBlob(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{
+ err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
@@ -813,7 +868,7 @@ func (s *RepositorySuite) TestBlob(c *C) {
func (s *RepositorySuite) TestBlobs(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
+ err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
count := 0
@@ -840,7 +895,7 @@ func (s *RepositorySuite) TestTagObject(c *C) {
)
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: url})
+ err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
hash := plumbing.NewHash("ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc")
@@ -858,7 +913,7 @@ func (s *RepositorySuite) TestTags(c *C) {
)
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: url})
+ err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
count := 0
@@ -903,7 +958,7 @@ func (s *RepositorySuite) TestNotes(c *C) {
)
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: url})
+ err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
count := 0
@@ -922,7 +977,7 @@ func (s *RepositorySuite) TestNotes(c *C) {
func (s *RepositorySuite) TestTree(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{
+ err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
@@ -945,7 +1000,7 @@ func (s *RepositorySuite) TestTree(c *C) {
func (s *RepositorySuite) TestTrees(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
+ err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
count := 0
@@ -973,7 +1028,7 @@ func (s *RepositorySuite) TestTagObjects(c *C) {
)
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: url})
+ err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
count := 0
@@ -998,7 +1053,7 @@ func (s *RepositorySuite) TestTagObjects(c *C) {
func (s *RepositorySuite) TestCommitIterClosePanic(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
+ err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
commits, err := r.CommitObjects()
@@ -1008,7 +1063,7 @@ func (s *RepositorySuite) TestCommitIterClosePanic(c *C) {
func (s *RepositorySuite) TestRef(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
+ err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
ref, err := r.Reference(plumbing.HEAD, false)
@@ -1022,7 +1077,7 @@ func (s *RepositorySuite) TestRef(c *C) {
func (s *RepositorySuite) TestRefs(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
+ err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
c.Assert(err, IsNil)
@@ -1034,7 +1089,7 @@ func (s *RepositorySuite) TestRefs(c *C) {
func (s *RepositorySuite) TestObject(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
+ err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
hash := plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
@@ -1047,7 +1102,7 @@ func (s *RepositorySuite) TestObject(c *C) {
func (s *RepositorySuite) TestObjects(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
+ err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
count := 0
@@ -1069,7 +1124,7 @@ func (s *RepositorySuite) TestObjects(c *C) {
func (s *RepositorySuite) TestObjectNotFound(c *C) {
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
+ err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
hash := plumbing.NewHash("0a3fb06ff80156fb153bcdcc58b5e16c2d27625c")
@@ -1099,7 +1154,7 @@ func (s *RepositorySuite) TestResolveRevision(c *C) {
)
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: url})
+ err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
datas := map[string]string{
@@ -1128,7 +1183,7 @@ func (s *RepositorySuite) TestResolveRevisionWithErrors(c *C) {
)
r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{URL: url})
+ err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
datas := map[string]string{
diff --git a/submodule.go b/submodule.go
index 572e6f7..ac027c2 100644
--- a/submodule.go
+++ b/submodule.go
@@ -2,10 +2,11 @@ package git
import (
"bytes"
+ "context"
"errors"
"fmt"
- billy "gopkg.in/src-d/go-billy.v3"
+ "gopkg.in/src-d/go-billy.v3"
"gopkg.in/src-d/go-git.v4/config"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/format/index"
@@ -139,10 +140,21 @@ func (s *Submodule) Repository() (*Repository, error) {
// submodule should be initialized first calling the Init method or setting in
// the options SubmoduleUpdateOptions.Init equals true
func (s *Submodule) Update(o *SubmoduleUpdateOptions) error {
- return s.update(o, plumbing.ZeroHash)
+ return s.UpdateContext(context.Background(), o)
}
-func (s *Submodule) update(o *SubmoduleUpdateOptions, forceHash plumbing.Hash) error {
+// UpdateContext the registered submodule to match what the superproject
+// expects, the submodule should be initialized first calling the Init method or
+// setting in the options SubmoduleUpdateOptions.Init equals true.
+//
+// The provided Context must be non-nil. If the context expires before the
+// operation is complete, an error is returned. The context only affects to the
+// transport operations.
+func (s *Submodule) UpdateContext(ctx context.Context, o *SubmoduleUpdateOptions) error {
+ return s.update(ctx, o, plumbing.ZeroHash)
+}
+
+func (s *Submodule) update(ctx context.Context, o *SubmoduleUpdateOptions, forceHash plumbing.Hash) error {
if !s.initialized && !o.Init {
return ErrSubmoduleNotInitialized
}
@@ -173,7 +185,7 @@ func (s *Submodule) update(o *SubmoduleUpdateOptions, forceHash plumbing.Hash) e
return err
}
- if err := s.fetchAndCheckout(r, o, hash); err != nil {
+ if err := s.fetchAndCheckout(ctx, r, o, hash); err != nil {
return err
}
@@ -202,9 +214,11 @@ func (s *Submodule) doRecursiveUpdate(r *Repository, o *SubmoduleUpdateOptions)
return l.Update(new)
}
-func (s *Submodule) fetchAndCheckout(r *Repository, o *SubmoduleUpdateOptions, hash plumbing.Hash) error {
+func (s *Submodule) fetchAndCheckout(
+ ctx context.Context, r *Repository, o *SubmoduleUpdateOptions, hash plumbing.Hash,
+) error {
if !o.NoFetch {
- err := r.Fetch(&FetchOptions{})
+ err := r.FetchContext(ctx, &FetchOptions{})
if err != nil && err != NoErrAlreadyUpToDate {
return err
}
@@ -239,8 +253,17 @@ func (s Submodules) Init() error {
// Update updates all the submodules in this list.
func (s Submodules) Update(o *SubmoduleUpdateOptions) error {
+ return s.UpdateContext(context.Background(), o)
+}
+
+// UpdateContext updates all the submodules in this list.
+//
+// The provided Context must be non-nil. If the context expires before the
+// operation is complete, an error is returned. The context only affects to the
+// transport operations.
+func (s Submodules) UpdateContext(ctx context.Context, o *SubmoduleUpdateOptions) error {
for _, sub := range s {
- if err := sub.Update(o); err != nil {
+ if err := sub.UpdateContext(ctx, o); err != nil {
return err
}
}
diff --git a/submodule_test.go b/submodule_test.go
index b398664..dd797c5 100644
--- a/submodule_test.go
+++ b/submodule_test.go
@@ -1,6 +1,7 @@
package git
import (
+ "context"
"io/ioutil"
"os"
"path/filepath"
@@ -190,3 +191,14 @@ func (s *SubmoduleSuite) TestSubmodulesStatus(c *C) {
c.Assert(err, IsNil)
c.Assert(status, HasLen, 2)
}
+
+func (s *SubmoduleSuite) TestSubmodulesUpdateContext(c *C) {
+ sm, err := s.Worktree.Submodules()
+ c.Assert(err, IsNil)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ err = sm.UpdateContext(ctx, &SubmoduleUpdateOptions{Init: true})
+ c.Assert(err, NotNil)
+}
diff --git a/worktree.go b/worktree.go
index 0c15d4c..5768888 100644
--- a/worktree.go
+++ b/worktree.go
@@ -1,6 +1,7 @@
package git
import (
+ "context"
"errors"
"fmt"
"io"
@@ -36,11 +37,22 @@ type Worktree struct {
// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
// no changes to be fetched, or an error.
func (w *Worktree) Pull(o *PullOptions) error {
+ return w.PullContext(context.Background(), o)
+}
+
+// PullContext incorporates changes from a remote repository into the current
+// branch. Returns nil if the operation is successful, NoErrAlreadyUpToDate if
+// there are no changes to be fetched, or an error.
+//
+// The provided Context must be non-nil. If the context expires before the
+// operation is complete, an error is returned. The context only affects to the
+// transport operations.
+func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
if err := o.Validate(); err != nil {
return err
}
- head, err := w.r.fetchAndUpdateReferences(&FetchOptions{
+ head, err := w.r.fetchAndUpdateReferences(ctx, &FetchOptions{
RemoteName: o.RemoteName,
Depth: o.Depth,
Auth: o.Auth,
@@ -334,7 +346,9 @@ func (w *Worktree) checkoutChangeSubmodule(name string,
return err
}
- return sub.update(&SubmoduleUpdateOptions{}, e.Hash)
+ // TODO: the submodule update should be reviewed as reported at:
+ // https://github.com/src-d/go-git/issues/415
+ return sub.update(context.TODO(), &SubmoduleUpdateOptions{}, e.Hash)
case merkletrie.Insert:
mode, err := e.Mode.ToOSFileMode()
if err != nil {
diff --git a/worktree_test.go b/worktree_test.go
index 97c4055..150176f 100644
--- a/worktree_test.go
+++ b/worktree_test.go
@@ -2,6 +2,7 @@ package git
import (
"bytes"
+ "context"
"io/ioutil"
"os"
"path/filepath"
@@ -83,7 +84,7 @@ func (s *WorktreeSuite) TestPullUpdateReferencesIfNeeded(c *C) {
func (s *WorktreeSuite) TestPullInSingleBranch(c *C) {
r, _ := Init(memory.NewStorage(), memfs.New())
- err := r.clone(&CloneOptions{
+ err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
SingleBranch: true,
})