// Package transport includes the implementation for different transport // protocols. // // `Client` can be used to fetch and send packfiles to a git server. // The `client` package provides higher level functions to instantiate the // appropiate `Client` based on the repository URL. // // Go-git supports HTTP and SSH (see `Protocols`), but you can also install // your own protocols (see the `client` package). // // Each protocol has its own implementation of `Client`, but you should // generally not use them directly, use `client.NewClient` instead. package transport import ( "errors" "fmt" "io" "net/url" "regexp" "gopkg.in/src-d/go-git.v4/plumbing" ) var ( ErrRepositoryNotFound = errors.New("repository not found") ErrEmptyRemoteRepository = errors.New("remote repository is empty") ErrAuthorizationRequired = errors.New("authorization required") ErrEmptyUploadPackRequest = errors.New("empty git-upload-pack given") ErrInvalidAuthMethod = errors.New("invalid auth method") ErrAdvertistedReferencesAlreadyCalled = errors.New("cannot call AdvertisedReference twice") ) const ( UploadPackServiceName = "git-upload-pack" ) // Client can initiate git-fetch-pack and git-send-pack processes. type Client interface { // NewFetchPackSession starts a git-fetch-pack session for an endpoint. NewFetchPackSession(Endpoint) (FetchPackSession, error) // NewSendPackSession starts a git-send-pack session for an endpoint. NewSendPackSession(Endpoint) (SendPackSession, error) } type Session interface { SetAuth(auth AuthMethod) error io.Closer } type AuthMethod interface { fmt.Stringer Name() string } // FetchPackSession represents a git-fetch-pack session. // A git-fetch-pack session has two steps: reference discovery // (`AdvertisedReferences` function) and fetching pack (`FetchPack` function). // In that order. type FetchPackSession interface { Session // AdvertisedReferences retrieves the advertised references for a // repository. It should be called before FetchPack, and it cannot be // called after FetchPack. AdvertisedReferences() (*UploadPackInfo, error) // FetchPack takes a request and returns a reader for the packfile // received from the server. FetchPack(req *UploadPackRequest) (io.ReadCloser, error) } // FetchPackSession represents a git-send-pack session. // A git-send-pack session has two steps: reference discovery // (`AdvertisedReferences` function) and sending pack (`SendPack` function). // In that order. type SendPackSession interface { Session // AdvertisedReferences retrieves the advertised references for a // repository. It should be called before FetchPack, and it cannot be // called after FetchPack. AdvertisedReferences() (*UploadPackInfo, error) // UpdateReferences sends an update references request and returns a // writer to be used for packfile writing. //TODO: Complete signature. SendPack() (io.WriteCloser, error) } type Endpoint url.URL var ( isSchemeRegExp = regexp.MustCompile("^[^:]+://") scpLikeUrlRegExp = regexp.MustCompile("^(?P[^@]+@)?(?P[^:]+):/?(?P.+)$") ) func NewEndpoint(endpoint string) (Endpoint, error) { endpoint = transformSCPLikeIfNeeded(endpoint) u, err := url.Parse(endpoint) if err != nil { return Endpoint{}, plumbing.NewPermanentError(err) } if !u.IsAbs() { return Endpoint{}, plumbing.NewPermanentError(fmt.Errorf( "invalid endpoint: %s", endpoint, )) } return Endpoint(*u), nil } func (e *Endpoint) String() string { u := url.URL(*e) return u.String() } func transformSCPLikeIfNeeded(endpoint string) string { if !isSchemeRegExp.MatchString(endpoint) && scpLikeUrlRegExp.MatchString(endpoint) { m := scpLikeUrlRegExp.FindStringSubmatch(endpoint) return fmt.Sprintf("ssh://%s%s/%s", m[1], m[2], m[3]) } return endpoint }