Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
aymanbagabas committed May 9, 2024
1 parent 3185ef2 commit b3886ab
Show file tree
Hide file tree
Showing 23 changed files with 256 additions and 182 deletions.
6 changes: 3 additions & 3 deletions internal/transport/test/upload_pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ package test

import (
"context"
"errors"
"io"
"time"

"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/storage"
"github.com/go-git/go-git/v5/storage/memory"

. "gopkg.in/check.v1"
)
Expand Down Expand Up @@ -50,7 +50,7 @@ func (s *UploadPackSuite) TestAdvertisedReferencesNotExists(c *C) {
}

func (s *UploadPackSuite) TestCallAdvertisedReferenceTwice(c *C) {
r, err := s.Client.NewSession(s.Storer, s.Endpoint, s.EmptyAuth)
r, err := s.Client.NewSession(memory.NewStorage(), s.Endpoint, s.EmptyAuth)
c.Assert(err, IsNil)
conn, err := r.Handshake(context.Background(), false)
c.Assert(err, IsNil)
Expand Down Expand Up @@ -199,7 +199,7 @@ func (s *UploadPackSuite) TestUploadPackNoChanges(c *C) {
}

err = conn.Fetch(context.Background(), req)
c.Assert(errors.Is(err, io.EOF), Equals, true)
c.Assert(err, NotNil)
}

func (s *UploadPackSuite) TestUploadPackMulti(c *C) {
Expand Down
43 changes: 37 additions & 6 deletions plumbing/protocol/packp/advrefs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ type AdvRefs struct {
// Capabilities are the capabilities.
Capabilities *capability.List
// References are the hash references.
References []*plumbing.Reference
References map[string]plumbing.Hash
// Peeled are the peeled hash references.
Peeled map[string]plumbing.Hash
// Shallows are the shallow object ids.
Shallows []plumbing.Hash
}
Expand All @@ -30,7 +32,8 @@ type AdvRefs struct {
func NewAdvRefs() *AdvRefs {
return &AdvRefs{
Capabilities: capability.NewList(),
References: make([]*plumbing.Reference, 0),
References: make(map[string]plumbing.Hash),
Peeled: make(map[string]plumbing.Hash),
Shallows: []plumbing.Hash{},
}
}
Expand All @@ -41,16 +44,18 @@ func (a *AdvRefs) AddReference(r *plumbing.Reference) error {
v := fmt.Sprintf("%s:%s", r.Name().String(), r.Target().String())
return a.Capabilities.Add(capability.SymRef, v)
case plumbing.HashReference:
a.References = append(a.References, r)
a.References[r.Name().String()] = r.Hash()
default:
return plumbing.ErrInvalidType
}

return nil
}

// AllReferences returns all references in the AdvRefs as a
// memory.ReferenceStorage.
// XXX: AllReferences doesn't return all the references advertised by the
// server, instead, it only returns non-peeled references.
// Use MakeReferenceSlice to get all the references, their peeled values, and
// symrefs.
func (a *AdvRefs) AllReferences() (memory.ReferenceStorage, error) {
s := memory.ReferenceStorage{}
if err := a.addRefs(s); err != nil {
Expand All @@ -61,7 +66,8 @@ func (a *AdvRefs) AllReferences() (memory.ReferenceStorage, error) {
}

func (a *AdvRefs) addRefs(s storer.ReferenceStorer) error {
for _, ref := range a.References {
for name, hash := range a.References {
ref := plumbing.NewReferenceFromStrings(name, hash.String())
if err := s.SetReference(ref); err != nil {
return err
}
Expand Down Expand Up @@ -190,5 +196,30 @@ func (a *AdvRefs) supportSymrefs() bool {
func (a *AdvRefs) IsEmpty() bool {
return a.Head == nil &&
len(a.References) == 0 &&
len(a.Peeled) == 0 &&
len(a.Shallows) == 0
}

// MakeReferenceSlice returns a sorted slice with all the references, their
// peeled values, and symrefs.
func MakeReferenceSlice(a *AdvRefs) ([]*plumbing.Reference, error) {
allRefs := make([]*plumbing.Reference, 0)
refs, err := a.AllReferences()
if err != nil {
return nil, err
}

for _, ref := range refs {
allRefs = append(allRefs, ref)
if peeled, ok := a.Peeled[ref.Name().String()]; ok {
peeledRef := plumbing.NewReferenceFromStrings(ref.Name().String()+"^{}", peeled.String())
allRefs = append(allRefs, peeledRef)
}
}

sort.Slice(allRefs, func(i, j int) bool {
return allRefs[i].Name() < allRefs[j].Name()
})

return allRefs, nil
}
15 changes: 9 additions & 6 deletions plumbing/protocol/packp/advrefs_decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,10 @@ func decodeFirstRef(l *advRefsDecoder) decoderStateFn {

if bytes.Equal(ref, []byte(head)) {
l.data.Head = &l.hash
} else {
l.data.References[string(ref)] = l.hash
}

// TODO: should we treat the HEAD ref as a special case?
r := plumbing.NewReferenceFromStrings(string(ref), l.hash.String())
l.data.References = append(l.data.References, r)

return decodeCaps
}

Expand Down Expand Up @@ -199,13 +197,18 @@ func decodeOtherRefs(p *advRefsDecoder) decoderStateFn {
return nil
}

saveTo := p.data.References
if bytes.HasSuffix(p.line, peeled) {
p.line = bytes.TrimSuffix(p.line, peeled)
saveTo = p.data.Peeled
}

ref, hash, err := readRef(p.line)
if err != nil {
p.error("%s", err)
return nil
}
r := plumbing.NewReferenceFromStrings(ref, hash.String())
p.data.References = append(p.data.References, r)
saveTo[ref] = hash

return decodeOtherRefs
}
Expand Down
33 changes: 27 additions & 6 deletions plumbing/protocol/packp/advrefs_encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type advRefsEncoder struct {
w io.Writer // where to write the encoded data
firstRefName string // reference name to encode in the first pkt-line (HEAD if present)
firstRefHash plumbing.Hash // hash referenced to encode in the first pkt-line (HEAD if present)
sortedRefs []string // hash references to encode ordered by increasing order
err error // sticky error
}

Expand All @@ -36,6 +37,7 @@ func newAdvRefsEncoder(w io.Writer) *advRefsEncoder {

func (e *advRefsEncoder) Encode(v *AdvRefs) error {
e.data = v
e.sortRefs()
e.setFirstRef()

for state := encodeFirstLine; state != nil; {
Expand All @@ -45,16 +47,29 @@ func (e *advRefsEncoder) Encode(v *AdvRefs) error {
return e.err
}

func (e *advRefsEncoder) sortRefs() {
if len(e.data.References) > 0 {
refs := make([]string, 0, len(e.data.References))
for refName := range e.data.References {
refs = append(refs, refName)
}

sort.Strings(refs)
e.sortedRefs = refs
}
}

func (e *advRefsEncoder) setFirstRef() {
if e.data.Head != nil {
e.firstRefName = head
e.firstRefHash = *e.data.Head
return
}

if len(e.data.References) > 0 {
e.firstRefName = e.data.References[0].Name().String()
e.firstRefHash = e.data.References[0].Hash()
if len(e.sortedRefs) > 0 {
refName := e.sortedRefs[0]
e.firstRefName = refName
e.firstRefHash = e.data.References[refName]
}
}

Expand Down Expand Up @@ -94,15 +109,21 @@ func formatCaps(c *capability.List) string {
// Adds the (sorted) refs: hash SP refname EOL
// and their peeled refs if any.
func encodeRefs(e *advRefsEncoder) encoderStateFn {
for _, r := range e.data.References {
if r.Name().String() == e.firstRefName {
for _, r := range e.sortedRefs {
if r == e.firstRefName {
continue
}

hash := r.Hash()
hash := e.data.References[r]
if _, e.err = pktline.Writef(e.w, "%s %s\n", hash.String(), r); e.err != nil {
return nil
}

if hash, ok := e.data.Peeled[r]; ok {
if _, e.err = pktline.Writef(e.w, "%s %s^{}\n", hash.String(), r); e.err != nil {
return nil
}
}
}

return encodeShallow
Expand Down
23 changes: 19 additions & 4 deletions plumbing/server/loader.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package server

import (
"path/filepath"

"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/plumbing/storer"
"github.com/go-git/go-git/v5/plumbing/transport"
Expand All @@ -12,7 +14,7 @@ import (
)

// DefaultLoader is a filesystem loader ignoring host and resolving paths to /.
var DefaultLoader = NewFilesystemLoader(osfs.New(""))
var DefaultLoader = NewFilesystemLoader(osfs.New(""), false)

// Loader loads repository's storer.Storer based on an optional host and a path.
type Loader interface {
Expand All @@ -23,25 +25,38 @@ type Loader interface {
}

type fsLoader struct {
base billy.Filesystem
base billy.Filesystem
strict bool
}

// NewFilesystemLoader creates a Loader that ignores host and resolves paths
// with a given base filesystem.
func NewFilesystemLoader(base billy.Filesystem) Loader {
return &fsLoader{base}
func NewFilesystemLoader(base billy.Filesystem, strict bool) Loader {
return &fsLoader{base, strict}
}

// Load looks up the endpoint's path in the base file system and returns a
// storer for it. Returns transport.ErrRepositoryNotFound if a repository does
// not exist in the given path.
func (l *fsLoader) Load(ep *transport.Endpoint) (storage.Storer, error) {
return l.load(ep, false)
}

func (l *fsLoader) load(ep *transport.Endpoint, tried bool) (storage.Storer, error) {
fs, err := l.base.Chroot(ep.Path)
if err != nil {
return nil, err
}

if _, err := fs.Stat("config"); err != nil {
if !l.strict && !tried {
if _, err := fs.Stat(".git"); err == nil {
ep.Path = filepath.Join(ep.Path, ".git")
} else {
ep.Path = ep.Path + ".git"
}
return l.load(ep, true)
}
return nil, transport.ErrRepositoryNotFound
}

Expand Down
25 changes: 14 additions & 11 deletions plumbing/server/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package server
import (
"context"
"errors"
"fmt"
"io"
"strconv"
"strings"
Expand Down Expand Up @@ -34,6 +35,7 @@ func AdvertiseReferences(ctx context.Context, st storage.Storer, w io.Writer, fo
} else {
ar.Capabilities.Set(capability.Sideband) // nolint: errcheck
ar.Capabilities.Set(capability.NoProgress) // nolint: errcheck
ar.Capabilities.Set(capability.SymRef) // nolint: errcheck
}

// Set references
Expand All @@ -51,27 +53,28 @@ func addReferences(st storage.Storer, ar *packp.AdvRefs, addHead bool) error {
}

// Add references and their peeled values
if err := iter.ForEach(func(r *plumbing.Reference) (err error) {
ref := r
switch ref.Type() {
if err := iter.ForEach(func(r *plumbing.Reference) error {
hash, name := r.Hash(), r.Name()
switch r.Type() {
case plumbing.SymbolicReference:
ref, err = storer.ResolveReference(st, r.Target())
ref, err := storer.ResolveReference(st, r.Target())
if err != nil {
return err
}
hash = ref.Hash()
}
if ref.Name() == plumbing.HEAD {
if name == plumbing.HEAD {
if !addHead {
return nil
}
hash := ref.Hash()
// Add default branch HEAD symref
ar.Capabilities.Add(capability.SymRef, fmt.Sprintf("%s:%s", name, r.Target()))
ar.Head = &hash
}
ar.References = append(ar.References, ref)
if ref.Name().IsTag() {
if tag, err := object.GetTag(st, ref.Hash()); err == nil {
tagRef := plumbing.NewReferenceFromStrings(ref.Name().String()+"^{}", tag.Target.String())
ar.References = append(ar.References, tagRef)
ar.References[name.String()] = hash
if r.Name().IsTag() {
if tag, err := object.GetTag(st, hash); err == nil {
ar.Peeled[name.String()] = tag.Target
}
}
return nil
Expand Down
3 changes: 2 additions & 1 deletion plumbing/storer/reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ type referenceFilteredIter struct {
// Iterator. This iterator will iterate only references that accomplish the
// provided function.
func NewReferenceFilteredIter(
ff func(r *plumbing.Reference) bool, iter ReferenceIter) ReferenceIter {
ff func(r *plumbing.Reference) bool, iter ReferenceIter,
) ReferenceIter {
return &referenceFilteredIter{ff, iter}
}

Expand Down
4 changes: 2 additions & 2 deletions plumbing/transport/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ type client struct {
cmdr Commander
}

// NewTransport creates a new client using the given Commander.
func NewTransport(runner Commander) Transport {
// NewPackTransport creates a new client using the given Commander.
func NewPackTransport(runner Commander) Transport {
return &client{runner}
}

Expand Down
4 changes: 2 additions & 2 deletions plumbing/transport/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (s *CommonSuite) TestAdvertisedReferencesWithRemoteUnknownError(c *C) {
wantErr = fmt.Errorf("something")
)

client := NewTransport(mockCommander{stderr: stderr})
client := NewPackTransport(mockCommander{stderr: stderr})
sess, err := client.NewSession(nil, nil, nil)
if err != nil {
c.Fatalf("unexpected error: %s", err)
Expand Down Expand Up @@ -50,7 +50,7 @@ remote:`
wantErr *RemoteError
)

client := NewTransport(mockCommander{stderr: stderr})
client := NewPackTransport(mockCommander{stderr: stderr})
sess, err := client.NewSession(nil, nil, nil)
if err != nil {
c.Fatalf("unexpected error: %s", err)
Expand Down

0 comments on commit b3886ab

Please sign in to comment.