forked from gitea/gitea
99 lines
2.4 KiB
Go
99 lines
2.4 KiB
Go
|
package packp
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing"
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability"
|
||
|
)
|
||
|
|
||
|
// UploadPackRequest represents a upload-pack request.
|
||
|
// Zero-value is not safe, use NewUploadPackRequest instead.
|
||
|
type UploadPackRequest struct {
|
||
|
UploadRequest
|
||
|
UploadHaves
|
||
|
}
|
||
|
|
||
|
// NewUploadPackRequest creates a new UploadPackRequest and returns a pointer.
|
||
|
func NewUploadPackRequest() *UploadPackRequest {
|
||
|
ur := NewUploadRequest()
|
||
|
return &UploadPackRequest{
|
||
|
UploadHaves: UploadHaves{},
|
||
|
UploadRequest: *ur,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NewUploadPackRequestFromCapabilities creates a new UploadPackRequest and
|
||
|
// returns a pointer. The request capabilities are filled with the most optiomal
|
||
|
// ones, based on the adv value (advertaised capabilities), the UploadPackRequest
|
||
|
// it has no wants, haves or shallows and an infinite depth
|
||
|
func NewUploadPackRequestFromCapabilities(adv *capability.List) *UploadPackRequest {
|
||
|
ur := NewUploadRequestFromCapabilities(adv)
|
||
|
return &UploadPackRequest{
|
||
|
UploadHaves: UploadHaves{},
|
||
|
UploadRequest: *ur,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// IsEmpty a request if empty if Haves are contained in the Wants, or if Wants
|
||
|
// length is zero
|
||
|
func (r *UploadPackRequest) IsEmpty() bool {
|
||
|
return isSubset(r.Wants, r.Haves)
|
||
|
}
|
||
|
|
||
|
func isSubset(needle []plumbing.Hash, haystack []plumbing.Hash) bool {
|
||
|
for _, h := range needle {
|
||
|
found := false
|
||
|
for _, oh := range haystack {
|
||
|
if h == oh {
|
||
|
found = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !found {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// UploadHaves is a message to signal the references that a client has in a
|
||
|
// upload-pack. Do not use this directly. Use UploadPackRequest request instead.
|
||
|
type UploadHaves struct {
|
||
|
Haves []plumbing.Hash
|
||
|
}
|
||
|
|
||
|
// Encode encodes the UploadHaves into the Writer. If flush is true, a flush
|
||
|
// command will be encoded at the end of the writer content.
|
||
|
func (u *UploadHaves) Encode(w io.Writer, flush bool) error {
|
||
|
e := pktline.NewEncoder(w)
|
||
|
|
||
|
plumbing.HashesSort(u.Haves)
|
||
|
|
||
|
var last plumbing.Hash
|
||
|
for _, have := range u.Haves {
|
||
|
if bytes.Equal(last[:], have[:]) {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if err := e.Encodef("have %s\n", have); err != nil {
|
||
|
return fmt.Errorf("sending haves for %q: %s", have, err)
|
||
|
}
|
||
|
|
||
|
last = have
|
||
|
}
|
||
|
|
||
|
if flush && len(u.Haves) != 0 {
|
||
|
if err := e.Flush(); err != nil {
|
||
|
return fmt.Errorf("sending flush-pkt after haves: %s", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|