aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--doc.go49
-rw-r--r--examples/custom_http_client/main.go59
-rw-r--r--plumbing/client/common.go8
-rw-r--r--plumbing/client/common/common.go3
-rw-r--r--plumbing/client/http/common.go27
-rw-r--r--plumbing/client/http/common_test.go19
-rw-r--r--plumbing/client/http/git_upload_pack.go32
-rw-r--r--plumbing/client/http/git_upload_pack_test.go14
-rw-r--r--plumbing/client/ssh/git_upload_pack.go16
-rw-r--r--remote.go7
-rw-r--r--remote_test.go46
12 files changed, 205 insertions, 77 deletions
diff --git a/README.md b/README.md
index a54904e..d5e84dc 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ Installation
The recommended way to install *go-git* is:
```
-go get -u gopkg.in/src-d/go-git.v3/...
+go get -u gopkg.in/src-d/go-git.v4/...
```
diff --git a/doc.go b/doc.go
index 8d00689..03367b8 100644
--- a/doc.go
+++ b/doc.go
@@ -6,31 +6,32 @@
// extensions.
//
// Small example extracting the commits from a repository:
-// func ExampleBasic_printCommits() {
-// r := git.NewMemoryRepository()
-// o := &git.CloneOptions{
-// URL: "https://github.com/src-d/go-git",
-// }
-// if err := r.Clone(o); err != nil {
-// panic(err)
-// }
//
-// iter, err := r.Commits()
-// if err != nil {
-// panic(err)
-// }
-// defer iter.Close()
+// func ExampleBasic_printCommits() {
+// r := git.NewMemoryRepository()
+// o := &git.CloneOptions{
+// URL: "https://github.com/src-d/go-git",
+// }
+// if err := r.Clone(o); err != nil {
+// panic(err)
+// }
//
-// for {
-// commit, err := iter.Next()
-// if err != nil {
-// if err == io.EOF {
-// break
-// }
-// panic(err)
-// }
+// iter, err := r.Commits()
+// if err != nil {
+// panic(err)
+// }
+// defer iter.Close()
//
-// fmt.Println(commit)
-// }
-// }
+// for {
+// commit, err := iter.Next()
+// if err != nil {
+// if err == io.EOF {
+// break
+// }
+// panic(err)
+// }
+//
+// fmt.Println(commit)
+// }
+// }
package git // import "gopkg.in/src-d/go-git.v4"
diff --git a/examples/custom_http_client/main.go b/examples/custom_http_client/main.go
new file mode 100644
index 0000000..f28590f
--- /dev/null
+++ b/examples/custom_http_client/main.go
@@ -0,0 +1,59 @@
+package main
+
+import (
+ "crypto/tls"
+ "net/http"
+ "time"
+
+ "github.com/fatih/color"
+
+ git "gopkg.in/src-d/go-git.v4"
+ "gopkg.in/src-d/go-git.v4/plumbing/client"
+ githttp "gopkg.in/src-d/go-git.v4/plumbing/client/http"
+)
+
+func main() {
+ // Create a custom http(s) client
+ customClient := &http.Client{
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ }, // accept any certificate (might be useful for testing)
+ Timeout: 15 * time.Second, // 15 second timeout
+ CheckRedirect: func(req *http.Request, via []*http.Request) error { // don't follow redirect
+ return http.ErrUseLastResponse
+ },
+ }
+ // Override http(s) default protocol to use our custom client
+ clients.InstallProtocol(
+ "https",
+ githttp.NewGitUploadPackServiceFactory(customClient))
+
+ // Create an in-memory repository
+ r := git.NewMemoryRepository()
+
+ const url = "https://github.com/git-fixtures/basic.git"
+
+ // Clone repo
+ if err := r.Clone(&git.CloneOptions{URL: url}); err != nil {
+ panic(err)
+ }
+
+ // Retrieve the branch pointed by HEAD
+ head, err := r.Head()
+ if err != nil {
+ panic(err)
+ }
+
+ // Print latest commit
+ commit, err := r.Commit(head.Hash())
+ if err != nil {
+ panic(err)
+ }
+ color.Green(commit.String())
+ // Output:
+ // commit 6ecf0ef2c2dffb796033e5a02219af86ec6584e5
+ // Author: Máximo Cuadros Ortiz <mcuadros@gmail.com>
+ // Date: Sun Apr 05 23:30:47 2015 +0200
+ //
+ // vendor stuff
+}
diff --git a/plumbing/client/common.go b/plumbing/client/common.go
index 6a99339..1524753 100644
--- a/plumbing/client/common.go
+++ b/plumbing/client/common.go
@@ -1,4 +1,4 @@
-// Package clients includes the implementation for diferent transport protocols
+// Package clients includes the implementation for different transport protocols
//
// go-git needs the packfile and the refs of the repo. The
// `NewGitUploadPackService` function returns an object that allows to
@@ -21,17 +21,15 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/client/ssh"
)
-type GitUploadPackServiceFactory func(common.Endpoint) common.GitUploadPackService
-
// Protocols are the protocols supported by default.
-var Protocols = map[string]GitUploadPackServiceFactory{
+var Protocols = map[string]common.GitUploadPackServiceFactory{
"http": http.NewGitUploadPackService,
"https": http.NewGitUploadPackService,
"ssh": ssh.NewGitUploadPackService,
}
// InstallProtocol adds or modifies an existing protocol.
-func InstallProtocol(scheme string, f GitUploadPackServiceFactory) {
+func InstallProtocol(scheme string, f common.GitUploadPackServiceFactory) {
Protocols[scheme] = f
}
diff --git a/plumbing/client/common/common.go b/plumbing/client/common/common.go
index 97f78c4..b2d52e8 100644
--- a/plumbing/client/common/common.go
+++ b/plumbing/client/common/common.go
@@ -36,6 +36,9 @@ type GitUploadPackService interface {
Disconnect() error
}
+// GitUploadPackServiceFactory is capable of instantiating GitUploadPackService with given endpoint
+type GitUploadPackServiceFactory func(Endpoint) GitUploadPackService
+
type AuthMethod interface {
Name() string
String() string
diff --git a/plumbing/client/http/common.go b/plumbing/client/http/common.go
index 4c07876..2447995 100644
--- a/plumbing/client/http/common.go
+++ b/plumbing/client/http/common.go
@@ -9,8 +9,8 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/client/common"
)
-// HTTPAuthMethod concrete implementation of common.AuthMethod for HTTP services
-type HTTPAuthMethod interface {
+// AuthMethod is concrete implementation of common.AuthMethod for HTTP services
+type AuthMethod interface {
common.AuthMethod
setAuth(r *http.Request)
}
@@ -29,7 +29,7 @@ func (a *BasicAuth) setAuth(r *http.Request) {
r.SetBasicAuth(a.username, a.password)
}
-// Name name of the auth
+// Name is name of the auth
func (a *BasicAuth) Name() string {
return "http-basic-auth"
}
@@ -43,34 +43,33 @@ func (a *BasicAuth) String() string {
return fmt.Sprintf("%s - %s:%s", a.Name(), a.username, masked)
}
-// HTTPError a dedicated error to return errors bases on status codes
-type HTTPError struct {
+// Err is a dedicated error to return errors based on status code
+type Err struct {
Response *http.Response
}
-// NewHTTPError returns a new HTTPError based on a http response
-func NewHTTPError(r *http.Response) error {
- if r.StatusCode >= 200 && r.StatusCode < 300 {
+// NewErr returns a new Err based on a http response
+func NewErr(r *http.Response) error {
+ if r.StatusCode >= http.StatusOK && r.StatusCode < http.StatusMultipleChoices {
return nil
}
switch r.StatusCode {
- case 401:
+ case http.StatusUnauthorized:
return common.ErrAuthorizationRequired
- case 404:
+ case http.StatusNotFound:
return common.ErrRepositoryNotFound
}
- err := &HTTPError{r}
- return plumbing.NewUnexpectedError(err)
+ return plumbing.NewUnexpectedError(&Err{r})
}
// StatusCode returns the status code of the response
-func (e *HTTPError) StatusCode() int {
+func (e *Err) StatusCode() int {
return e.Response.StatusCode
}
-func (e *HTTPError) Error() string {
+func (e *Err) Error() string {
return fmt.Sprintf("unexpected requesting %q status code: %d",
e.Response.Request.URL, e.Response.StatusCode,
)
diff --git a/plumbing/client/http/common_test.go b/plumbing/client/http/common_test.go
index 287897d..7503d84 100644
--- a/plumbing/client/http/common_test.go
+++ b/plumbing/client/http/common_test.go
@@ -20,23 +20,22 @@ func (s *SuiteCommon) TestNewBasicAuth(c *C) {
c.Assert(a.String(), Equals, "http-basic-auth - foo:*******")
}
-func (s *SuiteCommon) TestNewHTTPError200(c *C) {
- res := &http.Response{StatusCode: 200}
- res.StatusCode = 200
- err := NewHTTPError(res)
+func (s *SuiteCommon) TestNewErrOK(c *C) {
+ res := &http.Response{StatusCode: http.StatusOK}
+ err := NewErr(res)
c.Assert(err, IsNil)
}
-func (s *SuiteCommon) TestNewHTTPError401(c *C) {
- s.testNewHTTPError(c, 401, "authorization required")
+func (s *SuiteCommon) TestNewErrUnauthorized(c *C) {
+ s.testNewHTTPError(c, http.StatusUnauthorized, "authorization required")
}
-func (s *SuiteCommon) TestNewHTTPError404(c *C) {
- s.testNewHTTPError(c, 404, "repository not found")
+func (s *SuiteCommon) TestNewErrNotFound(c *C) {
+ s.testNewHTTPError(c, http.StatusNotFound, "repository not found")
}
func (s *SuiteCommon) TestNewHTTPError40x(c *C) {
- s.testNewHTTPError(c, 402, "unexpected client error.*")
+ s.testNewHTTPError(c, http.StatusPaymentRequired, "unexpected client error.*")
}
func (s *SuiteCommon) testNewHTTPError(c *C, code int, msg string) {
@@ -46,7 +45,7 @@ func (s *SuiteCommon) testNewHTTPError(c *C, code int, msg string) {
Request: req,
}
- err := NewHTTPError(res)
+ err := NewErr(res)
c.Assert(err, NotNil)
c.Assert(err, ErrorMatches, msg)
}
diff --git a/plumbing/client/http/git_upload_pack.go b/plumbing/client/http/git_upload_pack.go
index c1f4a0b..1ecf299 100644
--- a/plumbing/client/http/git_upload_pack.go
+++ b/plumbing/client/http/git_upload_pack.go
@@ -13,26 +13,41 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/format/packp/pktline"
)
-// GitUploadPackService git-upoad-pack service over HTTP
+// GitUploadPackService git-upload-pack service over HTTP
type GitUploadPackService struct {
client *http.Client
endpoint common.Endpoint
- auth HTTPAuthMethod
+ auth AuthMethod
}
// NewGitUploadPackService connects to a git-upload-pack service over HTTP, the
// auth is extracted from the URL, or can be provided using the SetAuth method
func NewGitUploadPackService(endpoint common.Endpoint) common.GitUploadPackService {
+ return newGitUploadPackService(endpoint, http.DefaultClient)
+}
+
+// NewGitUploadPackServiceFactory creates a http client factory with a customizable client
+// See `InstallProtocol` to install and override default http client.
+// Unless a properly initialized client is given, it will fall back into `http.DefaultClient`.
+func NewGitUploadPackServiceFactory(client *http.Client) common.GitUploadPackServiceFactory {
+ return func(endpoint common.Endpoint) common.GitUploadPackService {
+ return newGitUploadPackService(endpoint, client)
+ }
+}
+
+func newGitUploadPackService(endpoint common.Endpoint, client *http.Client) common.GitUploadPackService {
+ if client == nil {
+ client = http.DefaultClient
+ }
s := &GitUploadPackService{
- client: http.DefaultClient,
+ client: client,
endpoint: endpoint,
}
-
s.setBasicAuthFromEndpoint()
return s
}
-// Connect has not any effect, is here just for meet the interface
+// Connect has not any effect, is here to satisfy interface
func (s *GitUploadPackService) Connect() error {
return nil
}
@@ -54,7 +69,7 @@ func (s *GitUploadPackService) setBasicAuthFromEndpoint() {
// SetAuth sets the AuthMethod
func (s *GitUploadPackService) SetAuth(auth common.AuthMethod) error {
- httpAuth, ok := auth.(HTTPAuthMethod)
+ httpAuth, ok := auth.(AuthMethod)
if !ok {
return common.ErrInvalidAuthMethod
}
@@ -139,7 +154,8 @@ func (s *GitUploadPackService) doRequest(method, url string, content *strings.Re
return nil, plumbing.NewUnexpectedError(err)
}
- if err := NewHTTPError(res); err != nil {
+ if err := NewErr(res); err != nil {
+ _ = res.Body.Close()
return nil, err
}
@@ -168,7 +184,7 @@ func (s *GitUploadPackService) applyAuthToRequest(req *http.Request) {
}
// Disconnect do nothing
-func (s *GitUploadPackService) Disconnect() (err error) {
+func (s *GitUploadPackService) Disconnect() error {
return nil
}
diff --git a/plumbing/client/http/git_upload_pack_test.go b/plumbing/client/http/git_upload_pack_test.go
index a50dbdf..8010cea 100644
--- a/plumbing/client/http/git_upload_pack_test.go
+++ b/plumbing/client/http/git_upload_pack_test.go
@@ -1,7 +1,9 @@
package http
import (
+ "crypto/tls"
"io/ioutil"
+ "net/http"
. "gopkg.in/check.v1"
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -30,6 +32,18 @@ func (s *RemoteSuite) TestNewGitUploadPackServiceAuth(c *C) {
c.Assert(auth.String(), Equals, "http-basic-auth - foo:*******")
}
+func (s *RemoteSuite) TestNewGitUploadPackServiceFactory(c *C) {
+ e, err := common.NewEndpoint("https://foo:bar@github.com/git-fixtures/basic")
+ c.Assert(err, IsNil)
+
+ roundTripper := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
+ client := &http.Client{Transport: roundTripper}
+ r := NewGitUploadPackServiceFactory(client)(e).(*GitUploadPackService)
+
+ c.Assert(r.auth.String(), Equals, "http-basic-auth - foo:*******")
+ c.Assert(r.client.Transport, Equals, roundTripper)
+}
+
func (s *RemoteSuite) TestConnect(c *C) {
r := NewGitUploadPackService(s.Endpoint)
c.Assert(r.Connect(), IsNil)
diff --git a/plumbing/client/ssh/git_upload_pack.go b/plumbing/client/ssh/git_upload_pack.go
index e2b73fd..db7fa93 100644
--- a/plumbing/client/ssh/git_upload_pack.go
+++ b/plumbing/client/ssh/git_upload_pack.go
@@ -84,11 +84,7 @@ func (s *GitUploadPackService) setAuthFromEndpoint() error {
var err error
s.auth, err = NewSSHAgentAuth(u)
- if err != nil {
- return err
- }
-
- return nil
+ return err
}
// SetAuth sets the AuthMethod
@@ -105,7 +101,7 @@ func (s *GitUploadPackService) SetAuth(auth common.AuthMethod) error {
// Info returns the GitUploadPackInfo of the repository. The client must be
// connected with the repository (using the ConnectWithAuth() method) before
// using this method.
-func (s *GitUploadPackService) Info() (i *common.GitUploadPackInfo, err error) {
+func (s *GitUploadPackService) Info() (*common.GitUploadPackInfo, error) {
if !s.connected {
return nil, ErrNotConnected
}
@@ -125,12 +121,12 @@ func (s *GitUploadPackService) Info() (i *common.GitUploadPackInfo, err error) {
return nil, err
}
- i = common.NewGitUploadPackInfo()
+ i := common.NewGitUploadPackInfo()
return i, i.Decode(bytes.NewReader(out))
}
// Disconnect the SSH client.
-func (s *GitUploadPackService) Disconnect() (err error) {
+func (s *GitUploadPackService) Disconnect() error {
if !s.connected {
return ErrNotConnected
}
@@ -142,7 +138,7 @@ func (s *GitUploadPackService) Disconnect() (err error) {
// SSH session on a connected GitUploadPackService, sends the given
// upload request to the server and returns a reader for the received
// packfile. Closing the returned reader will close the SSH session.
-func (s *GitUploadPackService) Fetch(req *common.GitUploadPackRequest) (rc io.ReadCloser, err error) {
+func (s *GitUploadPackService) Fetch(req *common.GitUploadPackRequest) (io.ReadCloser, error) {
if !s.connected {
return nil, ErrNotConnected
}
@@ -243,7 +239,7 @@ func sendHaves(w io.Writer, req *common.GitUploadPackRequest) error {
e := pktline.NewEncoder(w)
for _, have := range req.Haves {
if err := e.Encodef("have %s\n", have); err != nil {
- return fmt.Errorf("sending haves for %q: err ", have, err)
+ return fmt.Errorf("sending haves for %q: %s", have, err)
}
}
diff --git a/remote.go b/remote.go
index f5cc7f7..2b0273b 100644
--- a/remote.go
+++ b/remote.go
@@ -60,11 +60,8 @@ func (r *Remote) connectUploadPackService() error {
func (r *Remote) retrieveUpInfo() error {
var err error
- if r.upInfo, err = r.upSrv.Info(); err != nil {
- return err
- }
-
- return nil
+ r.upInfo, err = r.upSrv.Info()
+ return err
}
// Info returns the git-upload-pack info
diff --git a/remote_test.go b/remote_test.go
index f129c68..bfda15d 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -1,12 +1,18 @@
package git
import (
+ "crypto/tls"
+ "fmt"
"io"
"io/ioutil"
+ "net/http"
"os"
+ "time"
"gopkg.in/src-d/go-git.v4/config"
"gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/client"
+ githttp "gopkg.in/src-d/go-git.v4/plumbing/client/http"
"gopkg.in/src-d/go-git.v4/plumbing/storer"
"gopkg.in/src-d/go-git.v4/storage/filesystem"
"gopkg.in/src-d/go-git.v4/storage/memory"
@@ -202,3 +208,43 @@ func (s *RemoteSuite) TestString(c *C) {
"foo\thttps://github.com/git-fixtures/basic.git (push)",
)
}
+
+// Here is an example to configure http client according to our own needs.
+func Example_customHTTPClient() {
+ const url = "https://github.com/git-fixtures/basic.git"
+
+ // Create a custom http(s) client with your config
+ customClient := &http.Client{
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ }, // accept any certificate (might be useful for testing)
+ Timeout: 15 * time.Second, // 15 second timeout
+ CheckRedirect: func(req *http.Request, via []*http.Request) error { // don't follow redirect
+ return http.ErrUseLastResponse
+ },
+ }
+
+ // Override http(s) default protocol to use our custom client
+ clients.InstallProtocol(
+ "https",
+ githttp.NewGitUploadPackServiceFactory(customClient))
+
+ // Create an in-memory repository
+ r := NewMemoryRepository()
+
+ // Clone repo
+ if err := r.Clone(&CloneOptions{URL: url}); err != nil {
+ panic(err)
+ }
+
+ // Retrieve the branch pointed by HEAD
+ head, err := r.Head()
+ if err != nil {
+ panic(err)
+ }
+
+ // Print latest commit hash
+ fmt.Println(head.Hash())
+ // Output:
+ // 6ecf0ef2c2dffb796033e5a02219af86ec6584e5
+}