fork of go-git with some jj specific features
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.13.0 1114 lines 24 kB view raw
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}