Skip to content

Instantly share code, notes, and snippets.

@aymanbagabas
Last active June 8, 2024 20:06
Show Gist options
  • Save aymanbagabas/1b5ccc265ee62dd574c62d378b4b57bb to your computer and use it in GitHub Desktop.
Save aymanbagabas/1b5ccc265ee62dd574c62d378b4b57bb to your computer and use it in GitHub Desktop.
Go-git transport API
package transport
// Transport is an interface for creating Git protocol transfer sessions.
type Transport interface {
// SupportedProtocols returns a list of supported Git protocol versions by
// the transport client.
SupportedProtocols() []protocol.Version
// NewSession creates a new Git service session using the given storer and
// endpoint.
NewSession(st storage.Storer, ep *Endpoint, auth AuthMethod) (Session, error)
}
// Service represents a Git transport service.
// All services are prefixed with "git-".
type Service string
// String returns the string representation of the service.
func (s Service) String() string {
return string(s)
}
// Name returns the name of the service without the "git-" prefix.
func (s Service) Name() string {
return string(s)[4:]
}
// Git service names.
const (
UploadPackService Service = "git-upload-pack"
ReceivePackService Service = "git-receive-pack"
)
// Session is a Git protocol transfer session.
// This is used by all protocols.
type Session interface {
// Handshake starts the connection with the remote to get version and
// capabilities of the server.
// Params are the optional extra parameters to be sent to the server. Use
// this to send the protocol version of the client and any other extra parameters.
Handshake(ctx context.Context, service Service, params ...string) (Connection, error)
// Archive requests an archive from the remote using git-upload-archive. This
// is only supported by transports that use the pack-protocol, http transport is
// not supported.
// TODO: TBD
// Archive(ctx context.Context, req *ArchiveRequest, params ...string) (*ArchiveResponse, error)
}
// Connection represents a session endpoint connection.
type Connection interface {
// io.ReadWriter support?
// Close closes the connection.
Close() error
// Capabilities returns the list of capabilities supported by the server.
Capabilities() *capability.List
// Version returns the Git protocol version the server supports.
Version() protocol.Version
// IsStatelessRPC indicates that the connection is a half-duplex connection
// and should operate in half-duplex mode i.e. performs a single read-write
// cycle. This fits with the HTTP POST request process where session may
// read the request, write a response, and exit.
IsStatelessRPC() bool
// GetRemoteRefs returns the references advertised by the remote.
// Using protocol v0 or v1, this returns the references advertised by the
// remote during the handshake. Using protocol v2, this runs the ls-refs
// command on the remote.
// This will error if the session is not already established using
// Handshake.
GetRemoteRefs(ctx context.Context) (map[string]plumbing.Hash, error)
// Fetch sends a fetch-pack request to the server.
Fetch(ctx context.Context, req *FetchRequest) error
// Push sends a send-pack request to the server.
Push(ctx context.Context, req *PushRequest) error
// Command execute protocol v2 command.
// TODO: TBD
// Command(ctx context.Context, req CommandRequest) (CommandResponse, error)
}
// FetchRequest contains the parameters for a fetch-pack request.
// This is used during the pack negotiation phase of the fetch operation.
// See https://git-scm.com/docs/pack-protocol#_packfile_negotiation
type FetchRequest struct {
// Progress is the progress sideband.
Progress sideband.Progress
// Wants is the list of references to fetch.
Wants []plumbing.Hash
// Haves is the list of references the client already has.
Haves []plumbing.Hash
// Depth is the depth of the fetch.
Depth int
// IncludeTags indicates whether tags should be fetched.
IncludeTags bool
}
// PushRequest contains the parameters for a push request.
type PushRequest struct {
// Packfile is the packfile reader.
Packfile io.ReadCloser
// Commands is the list of push commands to be sent to the server.
Commands []*packp.Command
// Progress is the progress sideband.
Progress sideband.Progress
// Options is a set of push-options to be sent to the server during push.
Options map[string]string
// Atomic indicates an atomic push.
// If the server supports atomic push, it will update the refs in one
// atomic transaction. Either all refs are updated or none.
Atomic bool
}
@pjbgf
Copy link

pjbgf commented Apr 30, 2024

  1. Session.Archive I think that could be an interface of its own, as IIRC Archive would not apply to all session implementations.
  2. Session.Handshake do we need a forPush? I was wondering whether we can do a Options pattern and make this func signature more extensible instead.
  3. FetchRequest should this not include a FilterRequest as well? Or would that be a follow-up when we add partial clones?

@aymanbagabas
Copy link
Author

aymanbagabas commented Apr 30, 2024

@pjbgf

  1. Session.Archive I think that could be an interface of its own, as IIRC Archive would not apply to all session implementations.

True, originally, Git didn't support remote archive for using the HTTP transport. But that is changing, someone added support for that recently https://stackoverflow.com/a/78094737/10913628

  1. Session.Handshake do we need a forPush? I was wondering whether we can do a Options pattern and make this func signature more extensible instead.

That was my initial thought. However, we only have two services that need back-and-forth communications. git-upload-archive is a read-only service and doesn't need reference discovery for instance. Hence the forPush, false means git-upload-pack and true means git-receive-pack

  1. FetchRequest should this not include a FilterRequest as well? Or would that be a follow-up when we add partial clones?

This can be a follow-up

@pjbgf
Copy link

pjbgf commented May 16, 2024

True, originally, Git didn't support remote archive for using the HTTP transport. But that is changing, someone added support for that recently https://stackoverflow.com/a/78094737/10913628

👍 That's OK then. I was mostly concerned with a LSP violation, or conceptually creating an interface that our own implementations do not fully support. If you think we can support it then that's fine.

Hence the forPush, false means git-upload-pack and true means git-receive-pack

I like the pragmatism of the approach, my only challenge is that we can't extent this without breaking backwards compatibility. Would you oppose to having a new type that (i.e. enum-like) so that we have the two types we require for now, but also can expand if needed in the future if needed?

@aymanbagabas
Copy link
Author

I like the pragmatism of the approach, my only challenge is that we can't extent this without breaking backwards compatibility. Would you oppose to having a new type that (i.e. enum-like) so that we have the two types we require for now, but also can expand if needed in the future if needed?

Fair enough. I think this will come handy when we implement git-upload-archive and possibly when we add support to LFS and git-lfs-transfer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment