diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2016-08-15 21:43:33 +0200 |
---|---|---|
committer | Máximo Cuadros <mcuadros@gmail.com> | 2016-08-15 21:43:33 +0200 |
commit | ed2e3b299e03e4bfd4c37bf5232e9fde05c0600d (patch) | |
tree | a4ecca997e4528b643758ddaa1dedfa4546369cd | |
parent | 4c6e65190f48f0a7558718d239ffb23ee59580ac (diff) | |
download | go-git-ed2e3b299e03e4bfd4c37bf5232e9fde05c0600d.tar.gz |
Repository.Pull, PoC
-rw-r--r-- | options.go | 52 | ||||
-rw-r--r-- | remote.go | 4 | ||||
-rw-r--r-- | repository.go | 68 |
3 files changed, 119 insertions, 5 deletions
@@ -1,6 +1,8 @@ package git import ( + "errors" + "gopkg.in/src-d/go-git.v3/clients/common" "gopkg.in/src-d/go-git.v4/core" ) @@ -10,6 +12,11 @@ const ( DefaultRemoteName = "origin" ) +var ( + ErrMissingURL = errors.New("URL field is required") + ErrMissingReferences = errors.New("references cannot be empty") +) + // RepositoryCloneOptions describe how a clone should be perform type RepositoryCloneOptions struct { // The (possibly remote) repository URL to clone from @@ -26,7 +33,12 @@ type RepositoryCloneOptions struct { Depth int } -func (o *RepositoryCloneOptions) Default() { +// Validate validate the fields and set the default values +func (o *RepositoryCloneOptions) Validate() error { + if o.URL == "" { + return ErrMissingURL + } + if o.RemoteName == "" { o.RemoteName = DefaultRemoteName } @@ -34,12 +46,50 @@ func (o *RepositoryCloneOptions) Default() { if o.ReferenceName == "" { o.ReferenceName = core.HEAD } + + return nil +} + +// RepositoryPullOptions describe how a pull should be perform +type RepositoryPullOptions struct { + // Name of the remote to be pulled + RemoteName string + // Remote branch to clone + ReferenceName core.ReferenceName + // Fetch only ReferenceName if true + SingleBranch bool + // Limit fetching to the specified number of commits + Depth int +} + +// Validate validate the fields and set the default values +func (o *RepositoryPullOptions) Validate() error { + if o.RemoteName == "" { + o.RemoteName = DefaultRemoteName + } + + if o.ReferenceName == "" { + o.ReferenceName = core.HEAD + } + + return nil } // RemoteFetchOptions describe how a fetch should be perform type RemoteFetchOptions struct { // Remote branchs to fetch References []*core.Reference + // Local references present on the local storage + LocalReferences []*core.Reference // Limit fetching to the specified number of commits Depth int } + +// Validate validate the fields and set the default values +func (o *RemoteFetchOptions) Validate() error { + if len(o.References) == 0 { + return ErrMissingReferences + } + + return nil +} @@ -80,6 +80,10 @@ func (r *Remote) Capabilities() *common.Capabilities { // Fetch returns a reader using the request func (r *Remote) Fetch(s core.ObjectStorage, o *RemoteFetchOptions) (err error) { + if err := o.Validate(); err != nil { + return err + } + req := &common.GitUploadPackRequest{} req.Depth = o.Depth diff --git a/repository.go b/repository.go index b17bbea..e9aa55a 100644 --- a/repository.go +++ b/repository.go @@ -12,15 +12,14 @@ import ( ) var ( - // ErrObjectNotFound object not found ErrObjectNotFound = errors.New("object not found") + ErrUnknownRemote = errors.New("unknown remote") ) // Repository giturl string, auth common.AuthMethod repository struct type Repository struct { Remotes map[string]*Remote - - s core.Storage + s core.Storage } // NewMemoryRepository creates a new repository, backed by a memory.Storage @@ -45,7 +44,9 @@ func NewRepository(s core.Storage) (*Repository, error) { // Clone clones a remote repository func (r *Repository) Clone(o *RepositoryCloneOptions) error { - o.Default() + if err := o.Validate(); err != nil { + return err + } remote, err := r.createRemote(o.RemoteName, o.URL, o.Auth) if err != nil { @@ -194,6 +195,65 @@ func (r *Repository) createRemoteReference(remote *Remote, ref *core.Reference) return r.s.ReferenceStorage().Set(n) } +// Pull incorporates changes from a remote repository into the current branch +func (r *Repository) Pull(o *RepositoryPullOptions) error { + if err := o.Validate(); err != nil { + return err + } + + remote, ok := r.Remotes[o.RemoteName] + if !ok { + return ErrUnknownRemote + } + + head, err := remote.Ref(o.ReferenceName, true) + if err != nil { + return err + } + + refs, err := r.getLocalReferences() + if err != nil { + return err + } + + err = remote.Fetch(r.s.ObjectStorage(), &RemoteFetchOptions{ + References: []*core.Reference{head}, + LocalReferences: refs, + Depth: o.Depth, + }) + + if err != nil { + return err + } + + return r.createLocalReferences(head) +} + +func (r *Repository) getLocalReferences() ([]*core.Reference, error) { + var refs []*core.Reference + i := r.Refs() + defer i.Close() + + for { + ref, err := i.Next() + if err != nil { + if err == io.EOF { + break + } + + return nil, err + } + + if ref.Type() == core.SymbolicReference { + continue + } + + refs = append(refs, ref) + } + + return refs, nil +} + // Commit return the commit with the given hash func (r *Repository) Commit(h core.Hash) (*Commit, error) { obj, err := r.s.ObjectStorage().Get(h) |