godepsssss

This commit is contained in:
Chris Brown
2016-02-12 12:31:57 -08:00
parent 638dbc214e
commit 94774a8f32
24 changed files with 301 additions and 46 deletions

18
Godeps/Godeps.json generated
View File

@@ -11,11 +11,11 @@
}, },
{ {
"ImportPath": "github.com/golang/protobuf/proto", "ImportPath": "github.com/golang/protobuf/proto",
"Rev": "45bba206dd5270d96bac4942dcfe515726613249" "Rev": "0dfe8f37844c14cb32c7247925270e0f7ba90973"
}, },
{ {
"ImportPath": "github.com/google/go-github/github", "ImportPath": "github.com/google/go-github/github",
"Rev": "b8b4ac742977310ff6e75140a403a38dab109977" "Rev": "39d75606a4cbec14d6f9f9d4e295dad4e3711682"
}, },
{ {
"ImportPath": "github.com/google/go-querystring/query", "ImportPath": "github.com/google/go-querystring/query",
@@ -27,17 +27,21 @@
}, },
{ {
"ImportPath": "github.com/onsi/ginkgo", "ImportPath": "github.com/onsi/ginkgo",
"Comment": "v1.2.0-36-g3341026", "Comment": "v1.2.0-42-g07d85e6",
"Rev": "33410268c3881642c746ada23c04eeb331212596" "Rev": "07d85e6b10c4289c7d612f9b13f45ba36f66d55b"
}, },
{ {
"ImportPath": "github.com/onsi/gomega", "ImportPath": "github.com/onsi/gomega",
"Comment": "v1.0-77-g28f13bc", "Comment": "v1.0-83-gc72df92",
"Rev": "28f13bc54cf0f72e3fa395ba9d3added0b3b849c" "Rev": "c72df929b80ef4930aaa75d5e486887ff2f3e06a"
},
{
"ImportPath": "github.com/xoebus/statham",
"Rev": "7b5896306a82ba5c78d2b0c8df4d29e36ba9ac2f"
}, },
{ {
"ImportPath": "golang.org/x/net/context", "ImportPath": "golang.org/x/net/context",
"Rev": "04b9de9b512f58addf28c9853d50ebef61c3953e" "Rev": "8968c61983e8f51a91b8c0ef25bf739278c89634"
}, },
{ {
"ImportPath": "golang.org/x/oauth2", "ImportPath": "golang.org/x/oauth2",

View File

@@ -173,6 +173,7 @@ func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order
type Properties struct { type Properties struct {
Name string // name of the field, for error messages Name string // name of the field, for error messages
OrigName string // original name before protocol compiler (always set) OrigName string // original name before protocol compiler (always set)
JSONName string // name to use for JSON; determined by protoc
Wire string Wire string
WireType int WireType int
Tag int Tag int
@@ -229,8 +230,9 @@ func (p *Properties) String() string {
if p.Packed { if p.Packed {
s += ",packed" s += ",packed"
} }
if p.OrigName != p.Name {
s += ",name=" + p.OrigName s += ",name=" + p.OrigName
if p.JSONName != p.OrigName {
s += ",json=" + p.JSONName
} }
if p.proto3 { if p.proto3 {
s += ",proto3" s += ",proto3"
@@ -310,6 +312,8 @@ func (p *Properties) Parse(s string) {
p.Packed = true p.Packed = true
case strings.HasPrefix(f, "name="): case strings.HasPrefix(f, "name="):
p.OrigName = f[5:] p.OrigName = f[5:]
case strings.HasPrefix(f, "json="):
p.JSONName = f[5:]
case strings.HasPrefix(f, "enum="): case strings.HasPrefix(f, "enum="):
p.Enum = f[5:] p.Enum = f[5:]
case f == "proto3": case f == "proto3":

View File

@@ -119,6 +119,14 @@ func isWhitespace(c byte) bool {
return false return false
} }
func isQuote(c byte) bool {
switch c {
case '"', '\'':
return true
}
return false
}
func (p *textParser) skipWhitespace() { func (p *textParser) skipWhitespace() {
i := 0 i := 0
for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
@@ -333,13 +341,13 @@ func (p *textParser) next() *token {
p.advance() p.advance()
if p.done { if p.done {
p.cur.value = "" p.cur.value = ""
} else if len(p.cur.value) > 0 && p.cur.value[0] == '"' { } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) {
// Look for multiple quoted strings separated by whitespace, // Look for multiple quoted strings separated by whitespace,
// and concatenate them. // and concatenate them.
cat := p.cur cat := p.cur
for { for {
p.skipWhitespace() p.skipWhitespace()
if p.done || p.s[0] != '"' { if p.done || !isQuote(p.s[0]) {
break break
} }
p.advance() p.advance()

View File

@@ -49,7 +49,7 @@ type PushEvent struct {
Ref *string `json:"ref,omitempty"` Ref *string `json:"ref,omitempty"`
Size *int `json:"size,omitempty"` Size *int `json:"size,omitempty"`
Commits []PushEventCommit `json:"commits,omitempty"` Commits []PushEventCommit `json:"commits,omitempty"`
Repo *Repository `json:"repository,omitempty"` Repo *PushEventRepository `json:"repository,omitempty"`
} }
func (p PushEvent) String() string { func (p PushEvent) String() string {
@@ -72,6 +72,40 @@ func (p PushEventCommit) String() string {
return Stringify(p) return Stringify(p)
} }
// PushEventRepository represents the repo object in a PushEvent payload
type PushEventRepository struct {
ID *int `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
FullName *string `json:"full_name,omitempty"`
Owner *PushEventRepoOwner `json:"owner,omitempty"`
Private *bool `json:"private,omitempty"`
Description *string `json:"description,omitempty"`
Fork *bool `json:"fork,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
PushedAt *Timestamp `json:"pushed_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
Homepage *string `json:"homepage,omitempty"`
Size *int `json:"size,omitempty"`
StargazersCount *int `json:"stargazers_count,omitempty"`
WatchersCount *int `json:"watchers_count,omitempty"`
Language *string `json:"language,omitempty"`
HasIssues *bool `json:"has_issues,omitempty"`
HasDownloads *bool `json:"has_downloads,omitempty"`
HasWiki *bool `json:"has_wiki,omitempty"`
HasPages *bool `json:"has_pages,omitempty"`
ForksCount *int `json:"forks_count,omitempty"`
OpenIssuesCount *int `json:"open_issues_count,omitempty"`
DefaultBranch *string `json:"default_branch,omitempty"`
MasterBranch *string `json:"master_branch,omitempty"`
Organization *string `json:"organization,omitempty"`
}
// PushEventRepoOwner is a basic reporesntation of user/org in a PushEvent payload
type PushEventRepoOwner struct {
Name *string `json:"name,omitempty"`
Email *string `json:"email,omitempty"`
}
//PullRequestEvent represents the payload delivered by PullRequestEvent webhook //PullRequestEvent represents the payload delivered by PullRequestEvent webhook
type PullRequestEvent struct { type PullRequestEvent struct {
Action *string `json:"action,omitempty"` Action *string `json:"action,omitempty"`

View File

@@ -59,12 +59,19 @@ limited to 60 requests per hour, while authenticated clients can make up to
that are not issued on behalf of a user, use the that are not issued on behalf of a user, use the
UnauthenticatedRateLimitedTransport. UnauthenticatedRateLimitedTransport.
The Rate field on a client tracks the rate limit information based on the most The Rate method on a client returns the rate limit information based on the most
recent API call. This is updated on every call, but may be out of date if it's recent API call. This is updated on every call, but may be out of date if it's
been some time since the last API call and other clients have made subsequent been some time since the last API call and other clients have made subsequent
requests since then. You can always call RateLimit() directly to get the most requests since then. You can always call RateLimits() directly to get the most
up-to-date rate limit data for the client. up-to-date rate limit data for the client.
To detect an API rate limit error, you can check if its type is *github.RateLimitError:
repos, _, err := client.Repositories.List("", nil)
if _, ok := err.(*github.RateLimitError); ok {
log.Println("hit rate limit")
}
Learn more about GitHub rate limiting at Learn more about GitHub rate limiting at
http://developer.github.com/v3/#rate-limiting. http://developer.github.com/v3/#rate-limiting.

View File

@@ -23,6 +23,11 @@ import (
"github.com/google/go-querystring/query" "github.com/google/go-querystring/query"
) )
const (
// StatusUnprocessableEntity is the status code returned when sending a request with invalid fields.
StatusUnprocessableEntity = 422
)
const ( const (
libraryVersion = "0.1" libraryVersion = "0.1"
defaultBaseURL = "https://api.github.com/" defaultBaseURL = "https://api.github.com/"
@@ -70,7 +75,7 @@ type Client struct {
UserAgent string UserAgent string
rateMu sync.Mutex rateMu sync.Mutex
rate Rate rate Rate // Rate limit for the client as determined by the most recent API call.
// Services used for talking to different parts of the GitHub API. // Services used for talking to different parts of the GitHub API.
Activity *ActivityService Activity *ActivityService
@@ -231,12 +236,12 @@ type Response struct {
func newResponse(r *http.Response) *Response { func newResponse(r *http.Response) *Response {
response := &Response{Response: r} response := &Response{Response: r}
response.populatePageValues() response.populatePageValues()
response.populateRate() response.Rate = parseRate(r)
return response return response
} }
// populatePageValues parses the HTTP Link response headers and populates the // populatePageValues parses the HTTP Link response headers and populates the
// various pagination link values in the Reponse. // various pagination link values in the Response.
func (r *Response) populatePageValues() { func (r *Response) populatePageValues() {
if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 { if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 {
for _, link := range strings.Split(links[0], ",") { for _, link := range strings.Split(links[0], ",") {
@@ -279,19 +284,21 @@ func (r *Response) populatePageValues() {
} }
} }
// populateRate parses the rate related headers and populates the response Rate. // parseRate parses the rate related headers.
func (r *Response) populateRate() { func parseRate(r *http.Response) Rate {
var rate Rate
if limit := r.Header.Get(headerRateLimit); limit != "" { if limit := r.Header.Get(headerRateLimit); limit != "" {
r.Rate.Limit, _ = strconv.Atoi(limit) rate.Limit, _ = strconv.Atoi(limit)
} }
if remaining := r.Header.Get(headerRateRemaining); remaining != "" { if remaining := r.Header.Get(headerRateRemaining); remaining != "" {
r.Rate.Remaining, _ = strconv.Atoi(remaining) rate.Remaining, _ = strconv.Atoi(remaining)
} }
if reset := r.Header.Get(headerRateReset); reset != "" { if reset := r.Header.Get(headerRateReset); reset != "" {
if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 { if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 {
r.Rate.Reset = Timestamp{time.Unix(v, 0)} rate.Reset = Timestamp{time.Unix(v, 0)}
} }
} }
return rate
} }
// Rate specifies the current rate limit for the client as determined by the // Rate specifies the current rate limit for the client as determined by the
@@ -368,6 +375,20 @@ type TwoFactorAuthError ErrorResponse
func (r *TwoFactorAuthError) Error() string { return (*ErrorResponse)(r).Error() } func (r *TwoFactorAuthError) Error() string { return (*ErrorResponse)(r).Error() }
// RateLimitError occurs when GitHub returns 403 Forbidden response with a rate limit
// remaining value of 0, and error message starts with "API rate limit exceeded for ".
type RateLimitError struct {
Rate Rate // Rate specifies last known rate limit for the client
Response *http.Response // HTTP response that caused this error
Message string `json:"message"` // error message
}
func (r *RateLimitError) Error() string {
return fmt.Sprintf("%v %v: %d %v; rate reset in %v",
r.Response.Request.Method, sanitizeURL(r.Response.Request.URL),
r.Response.StatusCode, r.Message, r.Rate.Reset.Time.Sub(time.Now()))
}
// sanitizeURL redacts the client_secret parameter from the URL which may be // sanitizeURL redacts the client_secret parameter from the URL which may be
// exposed to the user, specifically in the ErrorResponse error message. // exposed to the user, specifically in the ErrorResponse error message.
func sanitizeURL(uri *url.URL) *url.URL { func sanitizeURL(uri *url.URL) *url.URL {
@@ -413,6 +434,9 @@ func (e *Error) Error() string {
// the 200 range. API error responses are expected to have either no response // the 200 range. API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse. Any other // body, or a JSON response body that maps to ErrorResponse. Any other
// response body will be silently ignored. // response body will be silently ignored.
//
// The error type will be *RateLimitError for rate limit exceeded errors,
// and *TwoFactorAuthError for two-factor authentication errors.
func CheckResponse(r *http.Response) error { func CheckResponse(r *http.Response) error {
if c := r.StatusCode; 200 <= c && c <= 299 { if c := r.StatusCode; 200 <= c && c <= 299 {
return nil return nil
@@ -422,11 +446,19 @@ func CheckResponse(r *http.Response) error {
if err == nil && data != nil { if err == nil && data != nil {
json.Unmarshal(data, errorResponse) json.Unmarshal(data, errorResponse)
} }
if r.StatusCode == http.StatusUnauthorized && strings.HasPrefix(r.Header.Get(headerOTP), "required") { switch {
case r.StatusCode == http.StatusUnauthorized && strings.HasPrefix(r.Header.Get(headerOTP), "required"):
return (*TwoFactorAuthError)(errorResponse) return (*TwoFactorAuthError)(errorResponse)
case r.StatusCode == http.StatusForbidden && r.Header.Get(headerRateRemaining) == "0" && strings.HasPrefix(errorResponse.Message, "API rate limit exceeded for "):
return &RateLimitError{
Rate: parseRate(r),
Response: errorResponse.Response,
Message: errorResponse.Message,
} }
default:
return errorResponse return errorResponse
} }
}
// parseBoolResponse determines the boolean result from a GitHub API response. // parseBoolResponse determines the boolean result from a GitHub API response.
// Several GitHub API methods return boolean responses indicated by the HTTP // Several GitHub API methods return boolean responses indicated by the HTTP
@@ -482,7 +514,7 @@ func (r RateLimits) String() string {
return Stringify(r) return Stringify(r)
} }
// RateLimit is deprecated. Use RateLimits instead. // Deprecated: RateLimit is deprecated, use RateLimits instead.
func (c *Client) RateLimit() (*Rate, *Response, error) { func (c *Client) RateLimit() (*Rate, *Response, error) {
limits, resp, err := c.RateLimits() limits, resp, err := c.RateLimits()
if limits == nil { if limits == nil {

View File

@@ -12,6 +12,7 @@ import "fmt"
type Team struct { type Team struct {
ID *int `json:"id,omitempty"` ID *int `json:"id,omitempty"`
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
URL *string `json:"url,omitempty"` URL *string `json:"url,omitempty"`
Slug *string `json:"slug,omitempty"` Slug *string `json:"slug,omitempty"`

View File

@@ -43,7 +43,7 @@ type RepositoryContentResponse struct {
// RepositoryContentFileOptions specifies optional parameters for CreateFile, UpdateFile, and DeleteFile. // RepositoryContentFileOptions specifies optional parameters for CreateFile, UpdateFile, and DeleteFile.
type RepositoryContentFileOptions struct { type RepositoryContentFileOptions struct {
Message *string `json:"message,omitempty"` Message *string `json:"message,omitempty"`
Content []byte `json:"content,omitempty"` Content []byte `json:"content,omitempty"` // unencoded
SHA *string `json:"sha,omitempty"` SHA *string `json:"sha,omitempty"`
Branch *string `json:"branch,omitempty"` Branch *string `json:"branch,omitempty"`
Author *CommitAuthor `json:"author,omitempty"` Author *CommitAuthor `json:"author,omitempty"`

View File

@@ -29,6 +29,7 @@ type WebHookPayload struct {
Pusher *User `json:"pusher,omitempty"` Pusher *User `json:"pusher,omitempty"`
Ref *string `json:"ref,omitempty"` Ref *string `json:"ref,omitempty"`
Repo *Repository `json:"repository,omitempty"` Repo *Repository `json:"repository,omitempty"`
Sender *User `json:"sender,omitempty"`
} }
func (w WebHookPayload) String() string { func (w WebHookPayload) String() string {

View File

@@ -102,7 +102,7 @@ func (s *RepositoriesService) ListCommitActivity(owner, repo string) ([]WeeklyCo
// ListCodeFrequency returns a weekly aggregate of the number of additions and // ListCodeFrequency returns a weekly aggregate of the number of additions and
// deletions pushed to a repository. Returned WeeklyStats will contain // deletions pushed to a repository. Returned WeeklyStats will contain
// additiona and deletions, but not total commits. // additions and deletions, but not total commits.
// //
// GitHub API Docs: https://developer.github.com/v3/repos/statistics/#code-frequency // GitHub API Docs: https://developer.github.com/v3/repos/statistics/#code-frequency
func (s *RepositoriesService) ListCodeFrequency(owner, repo string) ([]WeeklyStats, *Response, error) { func (s *RepositoriesService) ListCodeFrequency(owner, repo string) ([]WeeklyStats, *Response, error) {
@@ -175,7 +175,7 @@ func (s *RepositoriesService) ListParticipation(owner, repo string) (*Repository
return participation, resp, err return participation, resp, err
} }
// PunchCard respresents the number of commits made during a given hour of a // PunchCard represents the number of commits made during a given hour of a
// day of thew eek. // day of thew eek.
type PunchCard struct { type PunchCard struct {
Day *int // Day of the week (0-6: =Sunday - Saturday). Day *int // Day of the week (0-6: =Sunday - Saturday).

View File

@@ -86,7 +86,7 @@ func (s *RepositoriesService) CreateStatus(owner, repo, ref string, status *Repo
// CombinedStatus represents the combined status of a repository at a particular reference. // CombinedStatus represents the combined status of a repository at a particular reference.
type CombinedStatus struct { type CombinedStatus struct {
// State is the combined state of the repository. Possible values are: // State is the combined state of the repository. Possible values are:
// failture, pending, or success. // failure, pending, or success.
State *string `json:"state,omitempty"` State *string `json:"state,omitempty"`
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`

View File

@@ -35,6 +35,7 @@ type User struct {
Following *int `json:"following,omitempty"` Following *int `json:"following,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"` CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"` UpdatedAt *Timestamp `json:"updated_at,omitempty"`
SuspendedAt *Timestamp `json:"suspended_at,omitempty"`
Type *string `json:"type,omitempty"` Type *string `json:"type,omitempty"`
SiteAdmin *bool `json:"site_admin,omitempty"` SiteAdmin *bool `json:"site_admin,omitempty"`
TotalPrivateRepos *int `json:"total_private_repos,omitempty"` TotalPrivateRepos *int `json:"total_private_repos,omitempty"`

View File

@@ -23,8 +23,17 @@ func (t TableEntry) generateIt(itBody reflect.Value) {
} }
values := []reflect.Value{} values := []reflect.Value{}
for _, param := range t.Parameters { for i, param := range t.Parameters {
values = append(values, reflect.ValueOf(param)) var value reflect.Value
if param == nil {
inType := itBody.Type().In(i)
value = reflect.Zero(inType)
} else {
value = reflect.ValueOf(param)
}
values = append(values, value)
} }
body := func() { body := func() {

View File

@@ -347,6 +347,28 @@ func XIt(text string, _ ...interface{}) bool {
return true return true
} }
//Specify blocks are aliases for It blocks and allow for more natural wording in situations
//which "It" does not fit into a natural sentence flow. All the same protocols apply for Specify blocks
//which apply to It blocks.
func Specify(text string, body interface{}, timeout ...float64) bool {
return It(text, body, timeout...)
}
//You can focus individual Specifys using FSpecify
func FSpecify(text string, body interface{}, timeout ...float64) bool {
return FIt(text, body, timeout...)
}
//You can mark Specifys as pending using PSpecify
func PSpecify(text string, is ...interface{}) bool {
return PIt(text, is...)
}
//You can mark Specifys as pending using XSpecify
func XSpecify(text string, is ...interface{}) bool {
return XIt(text, is...)
}
//By allows you to better document large Its. //By allows you to better document large Its.
// //
//Generally you should try to keep your Its short and to the point. This is not always possible, however, //Generally you should try to keep your Its short and to the point. This is not always possible, however,

View File

@@ -6,7 +6,6 @@ import (
"errors" "errors"
"io/ioutil" "io/ioutil"
"os" "os"
"syscall"
) )
func NewOutputInterceptor() OutputInterceptor { func NewOutputInterceptor() OutputInterceptor {
@@ -31,8 +30,12 @@ func (interceptor *outputInterceptor) StartInterceptingOutput() error {
return err return err
} }
syscall.Dup2(int(interceptor.redirectFile.Fd()), 1) // Call a function in ./syscall_dup_*.go
syscall.Dup2(int(interceptor.redirectFile.Fd()), 2) // If building for everything other than linux_arm64,
// use a "normal" syscall.Dup2(oldfd, newfd) call. If building for linux_arm64 (which doesn't have syscall.Dup2)
// call syscall.Dup3(oldfd, newfd, 0). They are nearly identical, see: http://linux.die.net/man/2/dup3
syscallDup(int(interceptor.redirectFile.Fd()), 1)
syscallDup(int(interceptor.redirectFile.Fd()), 2)
return nil return nil
} }

View File

@@ -0,0 +1,11 @@
// +build linux,arm64
package remote
import "syscall"
// linux_arm64 doesn't have syscall.Dup2 which ginkgo uses, so
// use the nearly identical syscall.Dup3 instead
func syscallDup(oldfd int, newfd int) (err error) {
return syscall.Dup3(oldfd, newfd, 0)
}

View File

@@ -0,0 +1,10 @@
// +build !linux !arm64
// +build !windows
package remote
import "syscall"
func syscallDup(oldfd int, newfd int) (err error) {
return syscall.Dup2(oldfd, newfd)
}

View File

@@ -1,7 +1,7 @@
language: go language: go
go: go:
- 1.4
- 1.5 - 1.5
- tip
install: install:
- go get -v ./... - go get -v ./...

View File

@@ -349,6 +349,17 @@ func (s *Server) GetHandler(index int) http.HandlerFunc {
return s.requestHandlers[index] return s.requestHandlers[index]
} }
func (s *Server) Reset() {
s.writeLock.Lock()
defer s.writeLock.Unlock()
s.HTTPTestServer.CloseClientConnections()
s.calls = 0
s.receivedRequests = nil
s.requestHandlers = nil
s.routedHandlers = nil
}
//WrapHandler combines the passed in handler with the handler registered at the passed in index. //WrapHandler combines the passed in handler with the handler registered at the passed in index.
//This is useful, for example, when a server has been set up in a shared context but must be tweaked //This is useful, for example, when a server has been set up in a shared context but must be tweaked
//for a particular test. //for a particular test.

View File

@@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Chris Brown
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,26 @@
# statham
*jason statham is the per-domain transporter*
![Jason Statham in The Transporter](http://i.imgur.com/9EebofV.jpg)
## installation
``` sh
go get github.com/xoebus/statham
```
## usage
``` go
defaultTransport := &http.Transport{...}
tr1 := &http.Transport{...}
tr2 := &http.Transport{...}
tr := statham.NewTransport(defaultTransport, statham.Mapping{
"github.com": tr1,
"google.com": tr2,
})
client := &http.Client{Transport: tr}
```

View File

@@ -0,0 +1,26 @@
package statham
import "net/http"
func NewTransport(defaultTr http.RoundTripper, mapping Mapping) http.RoundTripper {
return &roundTripper{
defaultTripper: defaultTr,
mapping: mapping,
}
}
type Mapping map[string]http.RoundTripper
type roundTripper struct {
defaultTripper http.RoundTripper
mapping Mapping
}
func (rt *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
transport, found := rt.mapping[req.URL.Host]
if !found {
return rt.defaultTripper.RoundTrip(req)
}
return transport.RoundTrip(req)
}