fork of go-git with some jj specific features
1package git
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "io"
8
9 "gopkg.in/src-d/go-billy.v4/osfs"
10 "gopkg.in/src-d/go-git.v4/config"
11 "gopkg.in/src-d/go-git.v4/plumbing"
12 "gopkg.in/src-d/go-git.v4/plumbing/cache"
13 "gopkg.in/src-d/go-git.v4/plumbing/format/packfile"
14 "gopkg.in/src-d/go-git.v4/plumbing/object"
15 "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
16 "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability"
17 "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband"
18 "gopkg.in/src-d/go-git.v4/plumbing/revlist"
19 "gopkg.in/src-d/go-git.v4/plumbing/storer"
20 "gopkg.in/src-d/go-git.v4/plumbing/transport"
21 "gopkg.in/src-d/go-git.v4/plumbing/transport/client"
22 "gopkg.in/src-d/go-git.v4/storage"
23 "gopkg.in/src-d/go-git.v4/storage/filesystem"
24 "gopkg.in/src-d/go-git.v4/storage/memory"
25 "gopkg.in/src-d/go-git.v4/utils/ioutil"
26)
27
28var (
29 NoErrAlreadyUpToDate = errors.New("already up-to-date")
30 ErrDeleteRefNotSupported = errors.New("server does not support delete-refs")
31 ErrForceNeeded = errors.New("some refs were not updated")
32)
33
34const (
35 // This describes the maximum number of commits to walk when
36 // computing the haves to send to a server, for each ref in the
37 // repo containing this remote, when not using the multi-ack
38 // protocol. Setting this to 0 means there is no limit.
39 maxHavesToVisitPerRef = 100
40)
41
42// Remote represents a connection to a remote repository.
43type Remote struct {
44 c *config.RemoteConfig
45 s storage.Storer
46}
47
48// NewRemote creates a new Remote.
49// The intended purpose is to use the Remote for tasks such as listing remote references (like using git ls-remote).
50// Otherwise Remotes should be created via the use of a Repository.
51func NewRemote(s storage.Storer, c *config.RemoteConfig) *Remote {
52 return &Remote{s: s, c: c}
53}
54
55// Config returns the RemoteConfig object used to instantiate this Remote.
56func (r *Remote) Config() *config.RemoteConfig {
57 return r.c
58}
59
60func (r *Remote) String() string {
61 var fetch, push string
62 if len(r.c.URLs) > 0 {
63 fetch = r.c.URLs[0]
64 push = r.c.URLs[0]
65 }
66
67 return fmt.Sprintf("%s\t%s (fetch)\n%[1]s\t%[3]s (push)", r.c.Name, fetch, push)
68}
69
70// Push performs a push to the remote. Returns NoErrAlreadyUpToDate if the
71// remote was already up-to-date.
72func (r *Remote) Push(o *PushOptions) error {
73 return r.PushContext(context.Background(), o)
74}
75
76// PushContext performs a push to the remote. Returns NoErrAlreadyUpToDate if
77// the remote was already up-to-date.
78//
79// The provided Context must be non-nil. If the context expires before the
80// operation is complete, an error is returned. The context only affects to the
81// transport operations.
82func (r *Remote) PushContext(ctx context.Context, o *PushOptions) (err error) {
83 if err := o.Validate(); err != nil {
84 return err
85 }
86
87 if o.RemoteName != r.c.Name {
88 return fmt.Errorf("remote names don't match: %s != %s", o.RemoteName, r.c.Name)
89 }
90
91 s, err := newSendPackSession(r.c.URLs[0], o.Auth)
92 if err != nil {
93 return err
94 }
95
96 defer ioutil.CheckClose(s, &err)
97
98 ar, err := s.AdvertisedReferences()
99 if err != nil {
100 return err
101 }
102
103 remoteRefs, err := ar.AllReferences()
104 if err != nil {
105 return err
106 }
107
108 isDelete := false
109 allDelete := true
110 for _, rs := range o.RefSpecs {
111 if rs.IsDelete() {
112 isDelete = true
113 } else {
114 allDelete = false
115 }
116 if isDelete && !allDelete {
117 break
118 }
119 }
120
121 if isDelete && !ar.Capabilities.Supports(capability.DeleteRefs) {
122 return ErrDeleteRefNotSupported
123 }
124
125 localRefs, err := r.references()
126 if err != nil {
127 return err
128 }
129
130 req, err := r.newReferenceUpdateRequest(o, localRefs, remoteRefs, ar)
131 if err != nil {
132 return err
133 }
134
135 if len(req.Commands) == 0 {
136 return NoErrAlreadyUpToDate
137 }
138
139 objects := objectsToPush(req.Commands)
140
141 haves, err := referencesToHashes(remoteRefs)
142 if err != nil {
143 return err
144 }
145
146 stop, err := r.s.Shallow()
147 if err != nil {
148 return err
149 }
150
151 // if we have shallow we should include this as part of the objects that
152 // we are aware.
153 haves = append(haves, stop...)
154
155 var hashesToPush []plumbing.Hash
156 // Avoid the expensive revlist operation if we're only doing deletes.
157 if !allDelete {
158 if r.c.IsFirstURLLocal() {
159 // If we're are pushing to a local repo, it might be much
160 // faster to use a local storage layer to get the commits
161 // to ignore, when calculating the object revlist.
162 localStorer := filesystem.NewStorage(
163 osfs.New(r.c.URLs[0]), cache.NewObjectLRUDefault())
164 hashesToPush, err = revlist.ObjectsWithStorageForIgnores(
165 r.s, localStorer, objects, haves)
166 } else {
167 hashesToPush, err = revlist.Objects(r.s, objects, haves)
168 }
169 if err != nil {
170 return err
171 }
172 }
173
174 if len(hashesToPush) == 0 {
175 allDelete = true
176 for _, command := range req.Commands {
177 if command.Action() != packp.Delete {
178 allDelete = false
179 break
180 }
181 }
182 }
183
184 rs, err := pushHashes(ctx, s, r.s, req, hashesToPush, r.useRefDeltas(ar), allDelete)
185 if err != nil {
186 return err
187 }
188
189 if err = rs.Error(); err != nil {
190 return err
191 }
192
193 return r.updateRemoteReferenceStorage(req, rs)
194}
195
196func (r *Remote) useRefDeltas(ar *packp.AdvRefs) bool {
197 return !ar.Capabilities.Supports(capability.OFSDelta)
198}
199
200func (r *Remote) newReferenceUpdateRequest(
201 o *PushOptions,
202 localRefs []*plumbing.Reference,
203 remoteRefs storer.ReferenceStorer,
204 ar *packp.AdvRefs,
205) (*packp.ReferenceUpdateRequest, error) {
206 req := packp.NewReferenceUpdateRequestFromCapabilities(ar.Capabilities)
207
208 if o.Progress != nil {
209 req.Progress = o.Progress
210 if ar.Capabilities.Supports(capability.Sideband64k) {
211 req.Capabilities.Set(capability.Sideband64k)
212 } else if ar.Capabilities.Supports(capability.Sideband) {
213 req.Capabilities.Set(capability.Sideband)
214 }
215 }
216
217 if err := r.addReferencesToUpdate(o.RefSpecs, localRefs, remoteRefs, req, o.Prune); err != nil {
218 return nil, err
219 }
220
221 return req, nil
222}
223
224func (r *Remote) updateRemoteReferenceStorage(
225 req *packp.ReferenceUpdateRequest,
226 result *packp.ReportStatus,
227) error {
228
229 for _, spec := range r.c.Fetch {
230 for _, c := range req.Commands {
231 if !spec.Match(c.Name) {
232 continue
233 }
234
235 local := spec.Dst(c.Name)
236 ref := plumbing.NewHashReference(local, c.New)
237 switch c.Action() {
238 case packp.Create, packp.Update:
239 if err := r.s.SetReference(ref); err != nil {
240 return err
241 }
242 case packp.Delete:
243 if err := r.s.RemoveReference(local); err != nil {
244 return err
245 }
246 }
247 }
248 }
249
250 return nil
251}
252
253// FetchContext fetches references along with the objects necessary to complete
254// their histories.
255//
256// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
257// no changes to be fetched, or an error.
258//
259// The provided Context must be non-nil. If the context expires before the
260// operation is complete, an error is returned. The context only affects to the
261// transport operations.
262func (r *Remote) FetchContext(ctx context.Context, o *FetchOptions) error {
263 _, err := r.fetch(ctx, o)
264 return err
265}
266
267// Fetch fetches references along with the objects necessary to complete their
268// histories.
269//
270// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
271// no changes to be fetched, or an error.
272func (r *Remote) Fetch(o *FetchOptions) error {
273 return r.FetchContext(context.Background(), o)
274}
275
276func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (sto storer.ReferenceStorer, err error) {
277 if o.RemoteName == "" {
278 o.RemoteName = r.c.Name
279 }
280
281 if err = o.Validate(); err != nil {
282 return nil, err
283 }
284
285 if len(o.RefSpecs) == 0 {
286 o.RefSpecs = r.c.Fetch
287 }
288
289 s, err := newUploadPackSession(r.c.URLs[0], o.Auth)
290 if err != nil {
291 return nil, err
292 }
293
294 defer ioutil.CheckClose(s, &err)
295
296 ar, err := s.AdvertisedReferences()
297 if err != nil {
298 return nil, err
299 }
300
301 req, err := r.newUploadPackRequest(o, ar)
302 if err != nil {
303 return nil, err
304 }
305
306 remoteRefs, err := ar.AllReferences()
307 if err != nil {
308 return nil, err
309 }
310
311 localRefs, err := r.references()
312 if err != nil {
313 return nil, err
314 }
315
316 refs, err := calculateRefs(o.RefSpecs, remoteRefs, o.Tags)
317 if err != nil {
318 return nil, err
319 }
320
321 req.Wants, err = getWants(r.s, refs)
322 if len(req.Wants) > 0 {
323 req.Haves, err = getHaves(localRefs, remoteRefs, r.s)
324 if err != nil {
325 return nil, err
326 }
327
328 if err = r.fetchPack(ctx, o, s, req); err != nil {
329 return nil, err
330 }
331 }
332
333 updated, err := r.updateLocalReferenceStorage(o.RefSpecs, refs, remoteRefs, o.Tags, o.Force)
334 if err != nil {
335 return nil, err
336 }
337
338 if !updated {
339 return remoteRefs, NoErrAlreadyUpToDate
340 }
341
342 return remoteRefs, nil
343}
344
345func newUploadPackSession(url string, auth transport.AuthMethod) (transport.UploadPackSession, error) {
346 c, ep, err := newClient(url)
347 if err != nil {
348 return nil, err
349 }
350
351 return c.NewUploadPackSession(ep, auth)
352}
353
354func newSendPackSession(url string, auth transport.AuthMethod) (transport.ReceivePackSession, error) {
355 c, ep, err := newClient(url)
356 if err != nil {
357 return nil, err
358 }
359
360 return c.NewReceivePackSession(ep, auth)
361}
362
363func newClient(url string) (transport.Transport, *transport.Endpoint, error) {
364 ep, err := transport.NewEndpoint(url)
365 if err != nil {
366 return nil, nil, err
367 }
368
369 c, err := client.NewClient(ep)
370 if err != nil {
371 return nil, nil, err
372 }
373
374 return c, ep, err
375}
376
377func (r *Remote) fetchPack(ctx context.Context, o *FetchOptions, s transport.UploadPackSession,
378 req *packp.UploadPackRequest) (err error) {
379
380 reader, err := s.UploadPack(ctx, req)
381 if err != nil {
382 return err
383 }
384
385 defer ioutil.CheckClose(reader, &err)
386
387 if err = r.updateShallow(o, reader); err != nil {
388 return err
389 }
390
391 if err = packfile.UpdateObjectStorage(r.s,
392 buildSidebandIfSupported(req.Capabilities, reader, o.Progress),
393 ); err != nil {
394 return err
395 }
396
397 return err
398}
399
400func (r *Remote) addReferencesToUpdate(
401 refspecs []config.RefSpec,
402 localRefs []*plumbing.Reference,
403 remoteRefs storer.ReferenceStorer,
404 req *packp.ReferenceUpdateRequest,
405 prune bool,
406) error {
407 // This references dictionary will be used to search references by name.
408 refsDict := make(map[string]*plumbing.Reference)
409 for _, ref := range localRefs {
410 refsDict[ref.Name().String()] = ref
411 }
412
413 for _, rs := range refspecs {
414 if rs.IsDelete() {
415 if err := r.deleteReferences(rs, remoteRefs, refsDict, req, false); err != nil {
416 return err
417 }
418 } else {
419 err := r.addOrUpdateReferences(rs, localRefs, refsDict, remoteRefs, req)
420 if err != nil {
421 return err
422 }
423
424 if prune {
425 if err := r.deleteReferences(rs, remoteRefs, refsDict, req, true); err != nil {
426 return err
427 }
428 }
429 }
430 }
431
432 return nil
433}
434
435func (r *Remote) addOrUpdateReferences(
436 rs config.RefSpec,
437 localRefs []*plumbing.Reference,
438 refsDict map[string]*plumbing.Reference,
439 remoteRefs storer.ReferenceStorer,
440 req *packp.ReferenceUpdateRequest,
441) error {
442 // If it is not a wilcard refspec we can directly search for the reference
443 // in the references dictionary.
444 if !rs.IsWildcard() {
445 ref, ok := refsDict[rs.Src()]
446 if !ok {
447 return nil
448 }
449
450 return r.addReferenceIfRefSpecMatches(rs, remoteRefs, ref, req)
451 }
452
453 for _, ref := range localRefs {
454 err := r.addReferenceIfRefSpecMatches(rs, remoteRefs, ref, req)
455 if err != nil {
456 return err
457 }
458 }
459
460 return nil
461}
462
463func (r *Remote) deleteReferences(rs config.RefSpec,
464 remoteRefs storer.ReferenceStorer,
465 refsDict map[string]*plumbing.Reference,
466 req *packp.ReferenceUpdateRequest,
467 prune bool) error {
468 iter, err := remoteRefs.IterReferences()
469 if err != nil {
470 return err
471 }
472
473 return iter.ForEach(func(ref *plumbing.Reference) error {
474 if ref.Type() != plumbing.HashReference {
475 return nil
476 }
477
478 if prune {
479 rs := rs.Reverse()
480 if !rs.Match(ref.Name()) {
481 return nil
482 }
483
484 if _, ok := refsDict[rs.Dst(ref.Name()).String()]; ok {
485 return nil
486 }
487 } else {
488 if rs.Dst("") != ref.Name() {
489 return nil
490 }
491 }
492
493 cmd := &packp.Command{
494 Name: ref.Name(),
495 Old: ref.Hash(),
496 New: plumbing.ZeroHash,
497 }
498 req.Commands = append(req.Commands, cmd)
499 return nil
500 })
501}
502
503func (r *Remote) addReferenceIfRefSpecMatches(rs config.RefSpec,
504 remoteRefs storer.ReferenceStorer, localRef *plumbing.Reference,
505 req *packp.ReferenceUpdateRequest) error {
506
507 if localRef.Type() != plumbing.HashReference {
508 return nil
509 }
510
511 if !rs.Match(localRef.Name()) {
512 return nil
513 }
514
515 cmd := &packp.Command{
516 Name: rs.Dst(localRef.Name()),
517 Old: plumbing.ZeroHash,
518 New: localRef.Hash(),
519 }
520
521 remoteRef, err := remoteRefs.Reference(cmd.Name)
522 if err == nil {
523 if remoteRef.Type() != plumbing.HashReference {
524 //TODO: check actual git behavior here
525 return nil
526 }
527
528 cmd.Old = remoteRef.Hash()
529 } else if err != plumbing.ErrReferenceNotFound {
530 return err
531 }
532
533 if cmd.Old == cmd.New {
534 return nil
535 }
536
537 if !rs.IsForceUpdate() {
538 if err := checkFastForwardUpdate(r.s, remoteRefs, cmd); err != nil {
539 return err
540 }
541 }
542
543 req.Commands = append(req.Commands, cmd)
544 return nil
545}
546
547func (r *Remote) references() ([]*plumbing.Reference, error) {
548 var localRefs []*plumbing.Reference
549 iter, err := r.s.IterReferences()
550 if err != nil {
551 return nil, err
552 }
553
554 for {
555 ref, err := iter.Next()
556 if err == io.EOF {
557 break
558 }
559
560 if err != nil {
561 return nil, err
562 }
563
564 localRefs = append(localRefs, ref)
565 }
566
567 return localRefs, nil
568}
569
570func getRemoteRefsFromStorer(remoteRefStorer storer.ReferenceStorer) (
571 map[plumbing.Hash]bool, error) {
572 remoteRefs := map[plumbing.Hash]bool{}
573 iter, err := remoteRefStorer.IterReferences()
574 if err != nil {
575 return nil, err
576 }
577 err = iter.ForEach(func(ref *plumbing.Reference) error {
578 if ref.Type() != plumbing.HashReference {
579 return nil
580 }
581 remoteRefs[ref.Hash()] = true
582 return nil
583 })
584 if err != nil {
585 return nil, err
586 }
587 return remoteRefs, nil
588}
589
590// getHavesFromRef populates the given `haves` map with the given
591// reference, and up to `maxHavesToVisitPerRef` ancestor commits.
592func getHavesFromRef(
593 ref *plumbing.Reference,
594 remoteRefs map[plumbing.Hash]bool,
595 s storage.Storer,
596 haves map[plumbing.Hash]bool,
597) error {
598 h := ref.Hash()
599 if haves[h] {
600 return nil
601 }
602
603 // No need to load the commit if we know the remote already
604 // has this hash.
605 if remoteRefs[h] {
606 haves[h] = true
607 return nil
608 }
609
610 commit, err := object.GetCommit(s, h)
611 if err != nil {
612 // Ignore the error if this isn't a commit.
613 haves[ref.Hash()] = true
614 return nil
615 }
616
617 // Until go-git supports proper commit negotiation during an
618 // upload pack request, include up to `maxHavesToVisitPerRef`
619 // commits from the history of each ref.
620 walker := object.NewCommitPreorderIter(commit, haves, nil)
621 toVisit := maxHavesToVisitPerRef
622 return walker.ForEach(func(c *object.Commit) error {
623 haves[c.Hash] = true
624 toVisit--
625 // If toVisit starts out at 0 (indicating there is no
626 // max), then it will be negative here and we won't stop
627 // early.
628 if toVisit == 0 || remoteRefs[c.Hash] {
629 return storer.ErrStop
630 }
631 return nil
632 })
633}
634
635func getHaves(
636 localRefs []*plumbing.Reference,
637 remoteRefStorer storer.ReferenceStorer,
638 s storage.Storer,
639) ([]plumbing.Hash, error) {
640 haves := map[plumbing.Hash]bool{}
641
642 // Build a map of all the remote references, to avoid loading too
643 // many parent commits for references we know don't need to be
644 // transferred.
645 remoteRefs, err := getRemoteRefsFromStorer(remoteRefStorer)
646 if err != nil {
647 return nil, err
648 }
649
650 for _, ref := range localRefs {
651 if haves[ref.Hash()] {
652 continue
653 }
654
655 if ref.Type() != plumbing.HashReference {
656 continue
657 }
658
659 err = getHavesFromRef(ref, remoteRefs, s, haves)
660 if err != nil {
661 return nil, err
662 }
663 }
664
665 var result []plumbing.Hash
666 for h := range haves {
667 result = append(result, h)
668 }
669
670 return result, nil
671}
672
673const refspecAllTags = "+refs/tags/*:refs/tags/*"
674
675func calculateRefs(
676 spec []config.RefSpec,
677 remoteRefs storer.ReferenceStorer,
678 tagMode TagMode,
679) (memory.ReferenceStorage, error) {
680 if tagMode == AllTags {
681 spec = append(spec, refspecAllTags)
682 }
683
684 refs := make(memory.ReferenceStorage)
685 for _, s := range spec {
686 if err := doCalculateRefs(s, remoteRefs, refs); err != nil {
687 return nil, err
688 }
689 }
690
691 return refs, nil
692}
693
694func doCalculateRefs(
695 s config.RefSpec,
696 remoteRefs storer.ReferenceStorer,
697 refs memory.ReferenceStorage,
698) error {
699 iter, err := remoteRefs.IterReferences()
700 if err != nil {
701 return err
702 }
703
704 var matched bool
705 err = iter.ForEach(func(ref *plumbing.Reference) error {
706 if !s.Match(ref.Name()) {
707 return nil
708 }
709
710 if ref.Type() == plumbing.SymbolicReference {
711 target, err := storer.ResolveReference(remoteRefs, ref.Name())
712 if err != nil {
713 return err
714 }
715
716 ref = plumbing.NewHashReference(ref.Name(), target.Hash())
717 }
718
719 if ref.Type() != plumbing.HashReference {
720 return nil
721 }
722
723 matched = true
724 if err := refs.SetReference(ref); err != nil {
725 return err
726 }
727
728 if !s.IsWildcard() {
729 return storer.ErrStop
730 }
731
732 return nil
733 })
734
735 if !matched && !s.IsWildcard() {
736 return fmt.Errorf("couldn't find remote ref %q", s.Src())
737 }
738
739 return err
740}
741
742func getWants(localStorer storage.Storer, refs memory.ReferenceStorage) ([]plumbing.Hash, error) {
743 wants := map[plumbing.Hash]bool{}
744 for _, ref := range refs {
745 hash := ref.Hash()
746 exists, err := objectExists(localStorer, ref.Hash())
747 if err != nil {
748 return nil, err
749 }
750
751 if !exists {
752 wants[hash] = true
753 }
754 }
755
756 var result []plumbing.Hash
757 for h := range wants {
758 result = append(result, h)
759 }
760
761 return result, nil
762}
763
764func objectExists(s storer.EncodedObjectStorer, h plumbing.Hash) (bool, error) {
765 _, err := s.EncodedObject(plumbing.AnyObject, h)
766 if err == plumbing.ErrObjectNotFound {
767 return false, nil
768 }
769
770 return true, err
771}
772
773func checkFastForwardUpdate(s storer.EncodedObjectStorer, remoteRefs storer.ReferenceStorer, cmd *packp.Command) error {
774 if cmd.Old == plumbing.ZeroHash {
775 _, err := remoteRefs.Reference(cmd.Name)
776 if err == plumbing.ErrReferenceNotFound {
777 return nil
778 }
779
780 if err != nil {
781 return err
782 }
783
784 return fmt.Errorf("non-fast-forward update: %s", cmd.Name.String())
785 }
786
787 ff, err := isFastForward(s, cmd.Old, cmd.New)
788 if err != nil {
789 return err
790 }
791
792 if !ff {
793 return fmt.Errorf("non-fast-forward update: %s", cmd.Name.String())
794 }
795
796 return nil
797}
798
799func isFastForward(s storer.EncodedObjectStorer, old, new plumbing.Hash) (bool, error) {
800 c, err := object.GetCommit(s, new)
801 if err != nil {
802 return false, err
803 }
804
805 found := false
806 iter := object.NewCommitPreorderIter(c, nil, nil)
807 err = iter.ForEach(func(c *object.Commit) error {
808 if c.Hash != old {
809 return nil
810 }
811
812 found = true
813 return storer.ErrStop
814 })
815 return found, err
816}
817
818func (r *Remote) newUploadPackRequest(o *FetchOptions,
819 ar *packp.AdvRefs) (*packp.UploadPackRequest, error) {
820
821 req := packp.NewUploadPackRequestFromCapabilities(ar.Capabilities)
822
823 if o.Depth != 0 {
824 req.Depth = packp.DepthCommits(o.Depth)
825 if err := req.Capabilities.Set(capability.Shallow); err != nil {
826 return nil, err
827 }
828 }
829
830 if o.Progress == nil && ar.Capabilities.Supports(capability.NoProgress) {
831 if err := req.Capabilities.Set(capability.NoProgress); err != nil {
832 return nil, err
833 }
834 }
835
836 isWildcard := true
837 for _, s := range o.RefSpecs {
838 if !s.IsWildcard() {
839 isWildcard = false
840 break
841 }
842 }
843
844 if isWildcard && o.Tags == TagFollowing && ar.Capabilities.Supports(capability.IncludeTag) {
845 if err := req.Capabilities.Set(capability.IncludeTag); err != nil {
846 return nil, err
847 }
848 }
849
850 return req, nil
851}
852
853func buildSidebandIfSupported(l *capability.List, reader io.Reader, p sideband.Progress) io.Reader {
854 var t sideband.Type
855
856 switch {
857 case l.Supports(capability.Sideband):
858 t = sideband.Sideband
859 case l.Supports(capability.Sideband64k):
860 t = sideband.Sideband64k
861 default:
862 return reader
863 }
864
865 d := sideband.NewDemuxer(t, reader)
866 d.Progress = p
867
868 return d
869}
870
871func (r *Remote) updateLocalReferenceStorage(
872 specs []config.RefSpec,
873 fetchedRefs, remoteRefs memory.ReferenceStorage,
874 tagMode TagMode,
875 force bool,
876) (updated bool, err error) {
877 isWildcard := true
878 forceNeeded := false
879
880 for _, spec := range specs {
881 if !spec.IsWildcard() {
882 isWildcard = false
883 }
884
885 for _, ref := range fetchedRefs {
886 if !spec.Match(ref.Name()) {
887 continue
888 }
889
890 if ref.Type() != plumbing.HashReference {
891 continue
892 }
893
894 localName := spec.Dst(ref.Name())
895 old, _ := storer.ResolveReference(r.s, localName)
896 new := plumbing.NewHashReference(localName, ref.Hash())
897
898 // If the ref exists locally as a branch and force is not specified,
899 // only update if the new ref is an ancestor of the old
900 if old != nil && old.Name().IsBranch() && !force && !spec.IsForceUpdate() {
901 ff, err := isFastForward(r.s, old.Hash(), new.Hash())
902 if err != nil {
903 return updated, err
904 }
905
906 if !ff {
907 forceNeeded = true
908 continue
909 }
910 }
911
912 refUpdated, err := checkAndUpdateReferenceStorerIfNeeded(r.s, new, old)
913 if err != nil {
914 return updated, err
915 }
916
917 if refUpdated {
918 updated = true
919 }
920 }
921 }
922
923 if tagMode == NoTags {
924 return updated, nil
925 }
926
927 tags := fetchedRefs
928 if isWildcard {
929 tags = remoteRefs
930 }
931 tagUpdated, err := r.buildFetchedTags(tags)
932 if err != nil {
933 return updated, err
934 }
935
936 if tagUpdated {
937 updated = true
938 }
939
940 if forceNeeded {
941 err = ErrForceNeeded
942 }
943
944 return
945}
946
947func (r *Remote) buildFetchedTags(refs memory.ReferenceStorage) (updated bool, err error) {
948 for _, ref := range refs {
949 if !ref.Name().IsTag() {
950 continue
951 }
952
953 _, err := r.s.EncodedObject(plumbing.AnyObject, ref.Hash())
954 if err == plumbing.ErrObjectNotFound {
955 continue
956 }
957
958 if err != nil {
959 return false, err
960 }
961
962 refUpdated, err := updateReferenceStorerIfNeeded(r.s, ref)
963 if err != nil {
964 return updated, err
965 }
966
967 if refUpdated {
968 updated = true
969 }
970 }
971
972 return
973}
974
975// List the references on the remote repository.
976func (r *Remote) List(o *ListOptions) (rfs []*plumbing.Reference, err error) {
977 s, err := newUploadPackSession(r.c.URLs[0], o.Auth)
978 if err != nil {
979 return nil, err
980 }
981
982 defer ioutil.CheckClose(s, &err)
983
984 ar, err := s.AdvertisedReferences()
985 if err != nil {
986 return nil, err
987 }
988
989 allRefs, err := ar.AllReferences()
990 if err != nil {
991 return nil, err
992 }
993
994 refs, err := allRefs.IterReferences()
995 if err != nil {
996 return nil, err
997 }
998
999 var resultRefs []*plumbing.Reference
1000 refs.ForEach(func(ref *plumbing.Reference) error {
1001 resultRefs = append(resultRefs, ref)
1002 return nil
1003 })
1004
1005 return resultRefs, nil
1006}
1007
1008func objectsToPush(commands []*packp.Command) []plumbing.Hash {
1009 var objects []plumbing.Hash
1010 for _, cmd := range commands {
1011 if cmd.New == plumbing.ZeroHash {
1012 continue
1013 }
1014
1015 objects = append(objects, cmd.New)
1016 }
1017 return objects
1018}
1019
1020func referencesToHashes(refs storer.ReferenceStorer) ([]plumbing.Hash, error) {
1021 iter, err := refs.IterReferences()
1022 if err != nil {
1023 return nil, err
1024 }
1025
1026 var hs []plumbing.Hash
1027 err = iter.ForEach(func(ref *plumbing.Reference) error {
1028 if ref.Type() != plumbing.HashReference {
1029 return nil
1030 }
1031
1032 hs = append(hs, ref.Hash())
1033 return nil
1034 })
1035 if err != nil {
1036 return nil, err
1037 }
1038
1039 return hs, nil
1040}
1041
1042func pushHashes(
1043 ctx context.Context,
1044 sess transport.ReceivePackSession,
1045 s storage.Storer,
1046 req *packp.ReferenceUpdateRequest,
1047 hs []plumbing.Hash,
1048 useRefDeltas bool,
1049 allDelete bool,
1050) (*packp.ReportStatus, error) {
1051
1052 rd, wr := io.Pipe()
1053
1054 config, err := s.Config()
1055 if err != nil {
1056 return nil, err
1057 }
1058
1059 // Set buffer size to 1 so the error message can be written when
1060 // ReceivePack fails. Otherwise the goroutine will be blocked writing
1061 // to the channel.
1062 done := make(chan error, 1)
1063
1064 if !allDelete {
1065 req.Packfile = rd
1066 go func() {
1067 e := packfile.NewEncoder(wr, s, useRefDeltas)
1068 if _, err := e.Encode(hs, config.Pack.Window); err != nil {
1069 done <- wr.CloseWithError(err)
1070 return
1071 }
1072
1073 done <- wr.Close()
1074 }()
1075 } else {
1076 close(done)
1077 }
1078
1079 rs, err := sess.ReceivePack(ctx, req)
1080 if err != nil {
1081 // close the pipe to unlock encode write
1082 _ = rd.Close()
1083 return nil, err
1084 }
1085
1086 if err := <-done; err != nil {
1087 return nil, err
1088 }
1089
1090 return rs, nil
1091}
1092
1093func (r *Remote) updateShallow(o *FetchOptions, resp *packp.UploadPackResponse) error {
1094 if o.Depth == 0 || len(resp.Shallows) == 0 {
1095 return nil
1096 }
1097
1098 shallows, err := r.s.Shallow()
1099 if err != nil {
1100 return err
1101 }
1102
1103outer:
1104 for _, s := range resp.Shallows {
1105 for _, oldS := range shallows {
1106 if s == oldS {
1107 continue outer
1108 }
1109 }
1110 shallows = append(shallows, s)
1111 }
1112
1113 return r.s.SetShallow(shallows)
1114}