From cbdb2584da59ec068e0d21e3e61028e54d1726fc Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Mon, 17 Jul 2017 09:33:58 +0200 Subject: remote: fetch, correct behaviour on tags --- remote.go | 139 +++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 83 insertions(+), 56 deletions(-) (limited to 'remote.go') diff --git a/remote.go b/remote.go index 7ebb843..b2c5d1c 100644 --- a/remote.go +++ b/remote.go @@ -134,7 +134,7 @@ func (r *Remote) Push(o *PushOptions) (err error) { return rs.Error() } -func (r *Remote) fetch(o *FetchOptions) (refs storer.ReferenceStorer, err error) { +func (r *Remote) fetch(o *FetchOptions) (storer.ReferenceStorer, error) { if o.RemoteName == "" { o.RemoteName = r.c.Name } @@ -169,7 +169,12 @@ func (r *Remote) fetch(o *FetchOptions) (refs storer.ReferenceStorer, err error) return nil, err } - req.Wants, err = getWants(o.RefSpecs, r.s, remoteRefs) + refs, err := calculateRefs(o.RefSpecs, remoteRefs, o.Tags) + if err != nil { + return nil, err + } + + req.Wants, err = getWants(r.s, refs) if len(req.Wants) > 0 { req.Haves, err = getHaves(r.s) if err != nil { @@ -181,14 +186,15 @@ func (r *Remote) fetch(o *FetchOptions) (refs storer.ReferenceStorer, err error) } } - err = r.updateLocalReferenceStorage(o.RefSpecs, remoteRefs) - if err != nil && err != NoErrAlreadyUpToDate { + updated, err := r.updateLocalReferenceStorage(o.RefSpecs, refs, remoteRefs) + if err != nil { return nil, err } - if len(req.Wants) == 0 { - return remoteRefs, err + if !updated { + return remoteRefs, NoErrAlreadyUpToDate } + return remoteRefs, nil } @@ -372,56 +378,52 @@ func getHaves(localRefs storer.ReferenceStorer) ([]plumbing.Hash, error) { return haves, nil } -func getWants( - spec []config.RefSpec, localStorer storage.Storer, remoteRefs storer.ReferenceStorer, -) ([]plumbing.Hash, error) { - wantTags := true - for _, s := range spec { - if !s.IsWildcard() { - wantTags = false - break - } - } - +func calculateRefs(spec []config.RefSpec, + remoteRefs storer.ReferenceStorer, + tags TagFetchMode, +) (memory.ReferenceStorage, error) { iter, err := remoteRefs.IterReferences() if err != nil { return nil, err } - wants := map[plumbing.Hash]bool{} - err = iter.ForEach(func(ref *plumbing.Reference) error { + refs := make(memory.ReferenceStorage, 0) + return refs, iter.ForEach(func(ref *plumbing.Reference) error { if !config.MatchAny(spec, ref.Name()) { - if !ref.IsTag() || !wantTags { + if !ref.IsTag() || tags != AllTags { return nil } } if ref.Type() == plumbing.SymbolicReference { - ref, err = storer.ResolveReference(remoteRefs, ref.Name()) + target, err := storer.ResolveReference(remoteRefs, ref.Name()) if err != nil { return err } + + ref = plumbing.NewHashReference(ref.Name(), target.Hash()) } if ref.Type() != plumbing.HashReference { return nil } - hash := ref.Hash() + return refs.SetReference(ref) + }) +} - exists, err := objectExists(localStorer, hash) +func getWants(localStorer storage.Storer, refs memory.ReferenceStorage) ([]plumbing.Hash, error) { + wants := map[plumbing.Hash]bool{} + for _, ref := range refs { + hash := ref.Hash() + exists, err := objectExists(localStorer, ref.Hash()) if err != nil { - return err + return nil, err } if !exists { wants[hash] = true } - - return nil - }) - if err != nil { - return nil, err } var result []plumbing.Hash @@ -503,6 +505,19 @@ func (r *Remote) newUploadPackRequest(o *FetchOptions, } } + isWildcard := true + for _, s := range o.RefSpecs { + if !s.IsWildcard() { + isWildcard = false + } + } + + if isWildcard && o.Tags == TagFollowing && ar.Capabilities.Supports(capability.IncludeTag) { + if err := req.Capabilities.Set(capability.IncludeTag); err != nil { + return nil, err + } + } + return req, nil } @@ -524,10 +539,17 @@ func buildSidebandIfSupported(l *capability.List, reader io.Reader, p sideband.P return d } -func (r *Remote) updateLocalReferenceStorage(specs []config.RefSpec, refs memory.ReferenceStorage) error { - updated := false +func (r *Remote) updateLocalReferenceStorage( + specs []config.RefSpec, + fetchedRefs, remoteRefs memory.ReferenceStorage, +) (updated bool, err error) { + isWildcard := true for _, spec := range specs { - for _, ref := range refs { + if !spec.IsWildcard() { + isWildcard = false + } + + for _, ref := range fetchedRefs { if !spec.Match(ref.Name()) { continue } @@ -536,33 +558,36 @@ func (r *Remote) updateLocalReferenceStorage(specs []config.RefSpec, refs memory continue } - name := spec.Dst(ref.Name()) - sref, err := r.s.Reference(name) - if err != nil && err != plumbing.ErrReferenceNotFound { - return err + new := plumbing.NewHashReference(spec.Dst(ref.Name()), ref.Hash()) + + refUpdated, err := updateReferenceStorerIfNeeded(r.s, new) + if err != nil { + return updated, err } - if err == plumbing.ErrReferenceNotFound || sref.Hash() != ref.Hash() { - n := plumbing.NewHashReference(name, ref.Hash()) - if err := r.s.SetReference(n); err != nil { - return err - } + + if refUpdated { updated = true } } } - if err := r.buildFetchedTags(refs); err != nil { - return err + tags := fetchedRefs + if isWildcard { + tags = remoteRefs + } + tagUpdated, err := r.buildFetchedTags(tags) + if err != nil { + return updated, err } - if !updated { - return NoErrAlreadyUpToDate + if tagUpdated { + updated = true } - return nil + + return } -func (r *Remote) buildFetchedTags(refs memory.ReferenceStorage) error { - updated := false +func (r *Remote) buildFetchedTags(refs memory.ReferenceStorage) (updated bool, err error) { for _, ref := range refs { if !ref.IsTag() { continue @@ -574,18 +599,20 @@ func (r *Remote) buildFetchedTags(refs memory.ReferenceStorage) error { } if err != nil { - return err + return false, err } - if err = r.s.SetReference(ref); err != nil { - return err + refUpdated, err := updateReferenceStorerIfNeeded(r.s, ref) + if err != nil { + return updated, err + } + + if refUpdated { + updated = true } - updated = true - } - if !updated { - return NoErrAlreadyUpToDate } - return nil + + return } func objectsToPush(commands []*packp.Command) ([]plumbing.Hash, error) { -- cgit