deps
This commit is contained in:
29
Godeps/Godeps.json
generated
29
Godeps/Godeps.json
generated
@@ -1,22 +1,21 @@
|
|||||||
{
|
{
|
||||||
"ImportPath": "github.com/concourse/github-release-resource",
|
"ImportPath": "github.com/concourse/github-release-resource",
|
||||||
"GoVersion": "go1.5.1",
|
"GoVersion": "go1.5",
|
||||||
"Packages": [
|
"Packages": [
|
||||||
"./..."
|
"./..."
|
||||||
],
|
],
|
||||||
"Deps": [
|
"Deps": [
|
||||||
{
|
|
||||||
"ImportPath": "code.google.com/p/goauth2/oauth",
|
|
||||||
"Comment": "weekly-57",
|
|
||||||
"Rev": "'222e66a2882ef45c3153c86c0aa82fe65fc29a78'"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cppforlife/go-semi-semantic/version",
|
"ImportPath": "github.com/cppforlife/go-semi-semantic/version",
|
||||||
"Rev": "a7ba07c61e58e6df7693d49a13d24f533182518a"
|
"Rev": "a7ba07c61e58e6df7693d49a13d24f533182518a"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/golang/protobuf/proto",
|
"ImportPath": "github.com/golang/protobuf/proto",
|
||||||
"Rev": "d3d78384b82d449651d2435ed329d70f7c48aa56"
|
"Rev": "45bba206dd5270d96bac4942dcfe515726613249"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/google/go-github/github",
|
||||||
|
"Rev": "b8b4ac742977310ff6e75140a403a38dab109977"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/go-querystring/query",
|
"ImportPath": "github.com/google/go-querystring/query",
|
||||||
@@ -28,17 +27,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/onsi/ginkgo",
|
"ImportPath": "github.com/onsi/ginkgo",
|
||||||
"Comment": "v1.2.0-22-g39d2c24",
|
"Comment": "v1.2.0-36-g3341026",
|
||||||
"Rev": "39d2c24f8a92c88f7e7f4d8ec6c80d3cc8f5ac65"
|
"Rev": "33410268c3881642c746ada23c04eeb331212596"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/onsi/gomega",
|
"ImportPath": "github.com/onsi/gomega",
|
||||||
"Comment": "v1.0-71-g2152b45",
|
"Comment": "v1.0-77-g28f13bc",
|
||||||
"Rev": "2152b45fa28a361beba9aab0885972323a444e28"
|
"Rev": "28f13bc54cf0f72e3fa395ba9d3added0b3b849c"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/zachgersh/go-github/github",
|
"ImportPath": "golang.org/x/net/context",
|
||||||
"Rev": "f47a8b33261f10482dfede3cc839c4fcf34da04f"
|
"Rev": "04b9de9b512f58addf28c9853d50ebef61c3953e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/oauth2",
|
||||||
|
"Rev": "8a57ed94ffd43444c0879fe75701732a38afc985"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
100
Godeps/_workspace/src/code.google.com/p/goauth2/oauth/example/oauthreq.go
generated
vendored
100
Godeps/_workspace/src/code.google.com/p/goauth2/oauth/example/oauthreq.go
generated
vendored
@@ -1,100 +0,0 @@
|
|||||||
// Copyright 2011 The goauth2 Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// This program makes a call to the specified API, authenticated with OAuth2.
|
|
||||||
// a list of example APIs can be found at https://code.google.com/oauthplayground/
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"code.google.com/p/goauth2/oauth"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
clientId = flag.String("id", "", "Client ID")
|
|
||||||
clientSecret = flag.String("secret", "", "Client Secret")
|
|
||||||
scope = flag.String("scope", "https://www.googleapis.com/auth/userinfo.profile", "OAuth scope")
|
|
||||||
redirectURL = flag.String("redirect_url", "oob", "Redirect URL")
|
|
||||||
authURL = flag.String("auth_url", "https://accounts.google.com/o/oauth2/auth", "Authentication URL")
|
|
||||||
tokenURL = flag.String("token_url", "https://accounts.google.com/o/oauth2/token", "Token URL")
|
|
||||||
requestURL = flag.String("request_url", "https://www.googleapis.com/oauth2/v1/userinfo", "API request")
|
|
||||||
code = flag.String("code", "", "Authorization Code")
|
|
||||||
cachefile = flag.String("cache", "cache.json", "Token cache file")
|
|
||||||
)
|
|
||||||
|
|
||||||
const usageMsg = `
|
|
||||||
To obtain a request token you must specify both -id and -secret.
|
|
||||||
|
|
||||||
To obtain Client ID and Secret, see the "OAuth 2 Credentials" section under
|
|
||||||
the "API Access" tab on this page: https://code.google.com/apis/console/
|
|
||||||
|
|
||||||
Once you have completed the OAuth flow, the credentials should be stored inside
|
|
||||||
the file specified by -cache and you may run without the -id and -secret flags.
|
|
||||||
`
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
// Set up a configuration.
|
|
||||||
config := &oauth.Config{
|
|
||||||
ClientId: *clientId,
|
|
||||||
ClientSecret: *clientSecret,
|
|
||||||
RedirectURL: *redirectURL,
|
|
||||||
Scope: *scope,
|
|
||||||
AuthURL: *authURL,
|
|
||||||
TokenURL: *tokenURL,
|
|
||||||
TokenCache: oauth.CacheFile(*cachefile),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up a Transport using the config.
|
|
||||||
transport := &oauth.Transport{Config: config}
|
|
||||||
|
|
||||||
// Try to pull the token from the cache; if this fails, we need to get one.
|
|
||||||
token, err := config.TokenCache.Token()
|
|
||||||
if err != nil {
|
|
||||||
if *clientId == "" || *clientSecret == "" {
|
|
||||||
flag.Usage()
|
|
||||||
fmt.Fprint(os.Stderr, usageMsg)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
if *code == "" {
|
|
||||||
// Get an authorization code from the data provider.
|
|
||||||
// ("Please ask the user if I can access this resource.")
|
|
||||||
url := config.AuthCodeURL("")
|
|
||||||
fmt.Print("Visit this URL to get a code, then run again with -code=YOUR_CODE\n\n")
|
|
||||||
fmt.Println(url)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Exchange the authorization code for an access token.
|
|
||||||
// ("Here's the code you gave the user, now give me a token!")
|
|
||||||
token, err = transport.Exchange(*code)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Exchange:", err)
|
|
||||||
}
|
|
||||||
// (The Exchange method will automatically cache the token.)
|
|
||||||
fmt.Printf("Token is cached in %v\n", config.TokenCache)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the actual request using the cached token to authenticate.
|
|
||||||
// ("Here's the token, let me in!")
|
|
||||||
transport.Token = token
|
|
||||||
|
|
||||||
// Make the request.
|
|
||||||
r, err := transport.Client().Get(*requestURL)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Get:", err)
|
|
||||||
}
|
|
||||||
defer r.Body.Close()
|
|
||||||
|
|
||||||
// Write the response to standard output.
|
|
||||||
io.Copy(os.Stdout, r.Body)
|
|
||||||
|
|
||||||
// Send final carriage return, just to be neat.
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
{"web":{"auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","client_email":"XXXXXXXXXXXX@developer.gserviceaccount.com","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/XXXXXXXXXXXX@developer.gserviceaccount.com","client_id":"XXXXXXXXXXXX.apps.googleusercontent.com","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs"}}
|
|
20
Godeps/_workspace/src/code.google.com/p/goauth2/oauth/jwt/example/example.pem
generated
vendored
20
Godeps/_workspace/src/code.google.com/p/goauth2/oauth/jwt/example/example.pem
generated
vendored
@@ -1,20 +0,0 @@
|
|||||||
Bag Attributes
|
|
||||||
friendlyName: privatekey
|
|
||||||
localKeyID: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
||||||
Key Attributes: <No Attributes>
|
|
||||||
-----BEGIN PRIVATE KEY-----
|
|
||||||
XXXXxyXXXXXXXxxyxxxX9y0XXYXXXXYXXxXyxxXxXxXXXyXXXXx4yx1xy1xyYxxY
|
|
||||||
1XxYy38YxXxxxyXxyyxx+xxxxyx1Y1xYx7yx2/Y1XyyXYYYxY5YXxX0xY/Y642yX
|
|
||||||
zYYxYXzXYxY0Y8y9YxyYXxxX40YyXxxXX4XXxx7XxXxxXyXxYYXxXyxX5XY0Yy2X
|
|
||||||
1YX0XXyy6YXyXx9XxXxyXX9XXYXxXxXXXXXXxYXYY3Y8Yy311XYYY81XyY14Xyyx
|
|
||||||
xXyx7xxXXXxxxxyyyX4YYYXyYyYXyxX4XYXYyxXYyx9xy23xXYyXyxYxXxx1XXXY
|
|
||||||
y98yX6yYxyyyX4Xyx1Xy/0yxxYxXxYYx2xx7yYXXXxYXXXxyXyyYYxx5XX2xxyxy
|
|
||||||
y6Yyyx0XX3YYYyx9YYXXXX7y0yxXXy+90XYz1y2xyx7yXxX+8X0xYxXXYxxyxYYy
|
|
||||||
YXx8Yy4yX0Xyxxx6yYX92yxy1YYYzyyyyxy55x/yyXXXYYXYXXzXXxYYxyXY8XXX
|
|
||||||
+y9+yXxX7XxxyYYxxXYxyY623xxXxYX59x5Y6yYyXYY4YxXXYXXXYxXYxXxXXx6x
|
|
||||||
YXX7XxXX2X0XY7YXyYy1XXxYXxXxYY1xXXxxxyy+07zXYxYxxXyyxxyxXx1XYy5X
|
|
||||||
5XYzyxYxXXYyX9XX7xX8xXxx+XXYyYXXXX5YY1x8Yxyx54Xy/1XXyyYXY5YxYyxY
|
|
||||||
XyyxXyX/YxxXXXxXXYXxyxx63xX/xxyYXXyYzx0XY+YxX5xyYyyxxxXXYX/94XXy
|
|
||||||
Xx63xYxXyXY3/XXxyyXX15XXXyz08XYY5YYXY/YXy/96x68XyyXXxYyXy4xYXx5x
|
|
||||||
7yxxyxxYxXxyx3y=
|
|
||||||
-----END PRIVATE KEY-----
|
|
114
Godeps/_workspace/src/code.google.com/p/goauth2/oauth/jwt/example/main.go
generated
vendored
114
Godeps/_workspace/src/code.google.com/p/goauth2/oauth/jwt/example/main.go
generated
vendored
@@ -1,114 +0,0 @@
|
|||||||
// Copyright 2011 The goauth2 Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// This program makes a read only call to the Google Cloud Storage API,
|
|
||||||
// authenticated with OAuth2. A list of example APIs can be found at
|
|
||||||
// https://code.google.com/oauthplayground/
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.google.com/p/goauth2/oauth/jwt"
|
|
||||||
)
|
|
||||||
|
|
||||||
const scope = "https://www.googleapis.com/auth/devstorage.read_only"
|
|
||||||
|
|
||||||
var (
|
|
||||||
secretsFile = flag.String("s", "", "JSON encoded secrets for the service account")
|
|
||||||
pemFile = flag.String("k", "", "private pem key file for the service account")
|
|
||||||
)
|
|
||||||
|
|
||||||
const usageMsg = `
|
|
||||||
You must specify -k and -s.
|
|
||||||
|
|
||||||
To obtain client secrets and pem, see the "OAuth 2 Credentials" section under
|
|
||||||
the "API Access" tab on this page: https://code.google.com/apis/console/
|
|
||||||
|
|
||||||
Google Cloud Storage must also be turned on in the API console.
|
|
||||||
`
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if *secretsFile == "" || *pemFile == "" {
|
|
||||||
flag.Usage()
|
|
||||||
fmt.Println(usageMsg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the secret file bytes into the config.
|
|
||||||
secretBytes, err := ioutil.ReadFile(*secretsFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("error reading secerets file:", err)
|
|
||||||
}
|
|
||||||
var config struct {
|
|
||||||
Web struct {
|
|
||||||
ClientEmail string `json:"client_email"`
|
|
||||||
ClientID string `json:"client_id"`
|
|
||||||
TokenURI string `json:"token_uri"`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(secretBytes, &config)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("error unmarshalling secerets:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the project ID from the client ID.
|
|
||||||
projectID := strings.SplitN(config.Web.ClientID, "-", 2)[0]
|
|
||||||
|
|
||||||
// Read the pem file bytes for the private key.
|
|
||||||
keyBytes, err := ioutil.ReadFile(*pemFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("error reading private key file:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Craft the ClaimSet and JWT token.
|
|
||||||
t := jwt.NewToken(config.Web.ClientEmail, scope, keyBytes)
|
|
||||||
t.ClaimSet.Aud = config.Web.TokenURI
|
|
||||||
|
|
||||||
// We need to provide a client.
|
|
||||||
c := &http.Client{}
|
|
||||||
|
|
||||||
// Get the access token.
|
|
||||||
o, err := t.Assert(c)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("assertion error:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh token will be missing, but this access_token will be good
|
|
||||||
// for one hour.
|
|
||||||
fmt.Printf("access_token = %v\n", o.AccessToken)
|
|
||||||
fmt.Printf("refresh_token = %v\n", o.RefreshToken)
|
|
||||||
fmt.Printf("expires %v\n", o.Expiry)
|
|
||||||
|
|
||||||
// Form the request to list Google Cloud Storage buckets.
|
|
||||||
req, err := http.NewRequest("GET", "https://storage.googleapis.com/", nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("http.NewRequest:", err)
|
|
||||||
}
|
|
||||||
req.Header.Set("Authorization", "OAuth "+o.AccessToken)
|
|
||||||
req.Header.Set("x-goog-api-version", "2")
|
|
||||||
req.Header.Set("x-goog-project-id", projectID)
|
|
||||||
|
|
||||||
// Make the request.
|
|
||||||
r, err := c.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("API request error:", err)
|
|
||||||
}
|
|
||||||
defer r.Body.Close()
|
|
||||||
|
|
||||||
// Write the response to standard output.
|
|
||||||
res, err := ioutil.ReadAll(r.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("error reading API request results:", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("\nRESULT:\n%s\n", res)
|
|
||||||
}
|
|
511
Godeps/_workspace/src/code.google.com/p/goauth2/oauth/jwt/jwt.go
generated
vendored
511
Godeps/_workspace/src/code.google.com/p/goauth2/oauth/jwt/jwt.go
generated
vendored
@@ -1,511 +0,0 @@
|
|||||||
// Copyright 2012 The goauth2 Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// The jwt package provides support for creating credentials for OAuth2 service
|
|
||||||
// account requests.
|
|
||||||
//
|
|
||||||
// For examples of the package usage please see jwt_test.go.
|
|
||||||
// Example usage (error handling omitted for brevity):
|
|
||||||
//
|
|
||||||
// // Craft the ClaimSet and JWT token.
|
|
||||||
// iss := "XXXXXXXXXXXX@developer.gserviceaccount.com"
|
|
||||||
// scope := "https://www.googleapis.com/auth/devstorage.read_only"
|
|
||||||
// t := jwt.NewToken(iss, scope, pemKeyBytes)
|
|
||||||
//
|
|
||||||
// // We need to provide a client.
|
|
||||||
// c := &http.Client{}
|
|
||||||
//
|
|
||||||
// // Get the access token.
|
|
||||||
// o, _ := t.Assert(c)
|
|
||||||
//
|
|
||||||
// // Form the request to the service.
|
|
||||||
// req, _ := http.NewRequest("GET", "https://storage.googleapis.com/", nil)
|
|
||||||
// req.Header.Set("Authorization", "OAuth "+o.AccessToken)
|
|
||||||
// req.Header.Set("x-goog-api-version", "2")
|
|
||||||
// req.Header.Set("x-goog-project-id", "XXXXXXXXXXXX")
|
|
||||||
//
|
|
||||||
// // Make the request.
|
|
||||||
// result, _ := c.Do(req)
|
|
||||||
//
|
|
||||||
// For info on OAuth2 service accounts please see the online documentation.
|
|
||||||
// https://developers.google.com/accounts/docs/OAuth2ServiceAccount
|
|
||||||
//
|
|
||||||
package jwt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"encoding/pem"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.google.com/p/goauth2/oauth"
|
|
||||||
)
|
|
||||||
|
|
||||||
// These are the default/standard values for this to work for Google service accounts.
|
|
||||||
const (
|
|
||||||
stdAlgorithm = "RS256"
|
|
||||||
stdType = "JWT"
|
|
||||||
stdAssertionType = "http://oauth.net/grant_type/jwt/1.0/bearer"
|
|
||||||
stdGrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
|
||||||
stdAud = "https://accounts.google.com/o/oauth2/token"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrInvalidKey = errors.New("Invalid Key")
|
|
||||||
)
|
|
||||||
|
|
||||||
// base64Encode returns and Base64url encoded version of the input string with any
|
|
||||||
// trailing "=" stripped.
|
|
||||||
func base64Encode(b []byte) string {
|
|
||||||
return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
|
|
||||||
}
|
|
||||||
|
|
||||||
// base64Decode decodes the Base64url encoded string
|
|
||||||
func base64Decode(s string) ([]byte, error) {
|
|
||||||
// add back missing padding
|
|
||||||
switch len(s) % 4 {
|
|
||||||
case 2:
|
|
||||||
s += "=="
|
|
||||||
case 3:
|
|
||||||
s += "="
|
|
||||||
}
|
|
||||||
return base64.URLEncoding.DecodeString(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The JWT claim set contains information about the JWT including the
|
|
||||||
// permissions being requested (scopes), the target of the token, the issuer,
|
|
||||||
// the time the token was issued, and the lifetime of the token.
|
|
||||||
//
|
|
||||||
// Aud is usually https://accounts.google.com/o/oauth2/token
|
|
||||||
type ClaimSet struct {
|
|
||||||
Iss string `json:"iss"` // email address of the client_id of the application making the access token request
|
|
||||||
Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests
|
|
||||||
Aud string `json:"aud"` // descriptor of the intended target of the assertion (Optional).
|
|
||||||
Prn string `json:"prn,omitempty"` // email for which the application is requesting delegated access (Optional).
|
|
||||||
Exp int64 `json:"exp"`
|
|
||||||
Iat int64 `json:"iat"`
|
|
||||||
Typ string `json:"typ,omitempty"`
|
|
||||||
Sub string `json:"sub,omitempty"` // Add support for googleapi delegation support
|
|
||||||
|
|
||||||
// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
|
|
||||||
// This array is marshalled using custom code (see (c *ClaimSet) encode()).
|
|
||||||
PrivateClaims map[string]interface{} `json:"-"`
|
|
||||||
|
|
||||||
exp time.Time
|
|
||||||
iat time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// setTimes sets iat and exp to time.Now() and iat.Add(time.Hour) respectively.
|
|
||||||
//
|
|
||||||
// Note that these times have nothing to do with the expiration time for the
|
|
||||||
// access_token returned by the server. These have to do with the lifetime of
|
|
||||||
// the encoded JWT.
|
|
||||||
//
|
|
||||||
// A JWT can be re-used for up to one hour after it was encoded. The access
|
|
||||||
// token that is granted will also be good for one hour so there is little point
|
|
||||||
// in trying to use the JWT a second time.
|
|
||||||
func (c *ClaimSet) setTimes(t time.Time) {
|
|
||||||
c.iat = t
|
|
||||||
c.exp = c.iat.Add(time.Hour)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
jsonStart = []byte{'{'}
|
|
||||||
jsonEnd = []byte{'}'}
|
|
||||||
)
|
|
||||||
|
|
||||||
// encode returns the Base64url encoded form of the Signature.
|
|
||||||
func (c *ClaimSet) encode() string {
|
|
||||||
if c.exp.IsZero() || c.iat.IsZero() {
|
|
||||||
c.setTimes(time.Now())
|
|
||||||
}
|
|
||||||
if c.Aud == "" {
|
|
||||||
c.Aud = stdAud
|
|
||||||
}
|
|
||||||
c.Exp = c.exp.Unix()
|
|
||||||
c.Iat = c.iat.Unix()
|
|
||||||
|
|
||||||
b, err := json.Marshal(c)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.PrivateClaims) == 0 {
|
|
||||||
return base64Encode(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal private claim set and then append it to b.
|
|
||||||
prv, err := json.Marshal(c.PrivateClaims)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Errorf("Invalid map of private claims %v", c.PrivateClaims))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Concatenate public and private claim JSON objects.
|
|
||||||
if !bytes.HasSuffix(b, jsonEnd) {
|
|
||||||
panic(fmt.Errorf("Invalid JSON %s", b))
|
|
||||||
}
|
|
||||||
if !bytes.HasPrefix(prv, jsonStart) {
|
|
||||||
panic(fmt.Errorf("Invalid JSON %s", prv))
|
|
||||||
}
|
|
||||||
b[len(b)-1] = ',' // Replace closing curly brace with a comma.
|
|
||||||
b = append(b, prv[1:]...) // Append private claims.
|
|
||||||
|
|
||||||
return base64Encode(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Header describes the algorithm and type of token being generated,
|
|
||||||
// and optionally a KeyID describing additional parameters for the
|
|
||||||
// signature.
|
|
||||||
type Header struct {
|
|
||||||
Algorithm string `json:"alg"`
|
|
||||||
Type string `json:"typ"`
|
|
||||||
KeyId string `json:"kid,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Header) encode() string {
|
|
||||||
b, err := json.Marshal(h)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return base64Encode(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A JWT is composed of three parts: a header, a claim set, and a signature.
|
|
||||||
// The well formed and encoded JWT can then be exchanged for an access token.
|
|
||||||
//
|
|
||||||
// The Token is not a JWT, but is is encoded to produce a well formed JWT.
|
|
||||||
//
|
|
||||||
// When obtaining a key from the Google API console it will be downloaded in a
|
|
||||||
// PKCS12 encoding. To use this key you will need to convert it to a PEM file.
|
|
||||||
// This can be achieved with openssl.
|
|
||||||
//
|
|
||||||
// $ openssl pkcs12 -in <key.p12> -nocerts -passin pass:notasecret -nodes -out <key.pem>
|
|
||||||
//
|
|
||||||
// The contents of this file can then be used as the Key.
|
|
||||||
type Token struct {
|
|
||||||
ClaimSet *ClaimSet // claim set used to construct the JWT
|
|
||||||
Header *Header // header used to construct the JWT
|
|
||||||
Key []byte // PEM printable encoding of the private key
|
|
||||||
pKey *rsa.PrivateKey
|
|
||||||
|
|
||||||
header string
|
|
||||||
claim string
|
|
||||||
sig string
|
|
||||||
|
|
||||||
useExternalSigner bool
|
|
||||||
signer Signer
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewToken returns a filled in *Token based on the standard header,
|
|
||||||
// and sets the Iat and Exp times based on when the call to Assert is
|
|
||||||
// made.
|
|
||||||
func NewToken(iss, scope string, key []byte) *Token {
|
|
||||||
c := &ClaimSet{
|
|
||||||
Iss: iss,
|
|
||||||
Scope: scope,
|
|
||||||
Aud: stdAud,
|
|
||||||
}
|
|
||||||
h := &Header{
|
|
||||||
Algorithm: stdAlgorithm,
|
|
||||||
Type: stdType,
|
|
||||||
}
|
|
||||||
t := &Token{
|
|
||||||
ClaimSet: c,
|
|
||||||
Header: h,
|
|
||||||
Key: key,
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signer is an interface that given a JWT token, returns the header &
|
|
||||||
// claim (serialized and urlEncoded to a byte slice), along with the
|
|
||||||
// signature and an error (if any occured). It could modify any data
|
|
||||||
// to sign (typically the KeyID).
|
|
||||||
//
|
|
||||||
// Example usage where a SHA256 hash of the original url-encoded token
|
|
||||||
// with an added KeyID and secret data is used as a signature:
|
|
||||||
//
|
|
||||||
// var privateData = "secret data added to hash, indexed by KeyID"
|
|
||||||
//
|
|
||||||
// type SigningService struct{}
|
|
||||||
//
|
|
||||||
// func (ss *SigningService) Sign(in *jwt.Token) (newTokenData, sig []byte, err error) {
|
|
||||||
// in.Header.KeyID = "signing service"
|
|
||||||
// newTokenData = in.EncodeWithoutSignature()
|
|
||||||
// dataToSign := fmt.Sprintf("%s.%s", newTokenData, privateData)
|
|
||||||
// h := sha256.New()
|
|
||||||
// _, err := h.Write([]byte(dataToSign))
|
|
||||||
// sig = h.Sum(nil)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
type Signer interface {
|
|
||||||
Sign(in *Token) (tokenData, signature []byte, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSignerToken returns a *Token, using an external signer function
|
|
||||||
func NewSignerToken(iss, scope string, signer Signer) *Token {
|
|
||||||
t := NewToken(iss, scope, nil)
|
|
||||||
t.useExternalSigner = true
|
|
||||||
t.signer = signer
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expired returns a boolean value letting us know if the token has expired.
|
|
||||||
func (t *Token) Expired() bool {
|
|
||||||
return t.ClaimSet.exp.Before(time.Now())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode constructs and signs a Token returning a JWT ready to use for
|
|
||||||
// requesting an access token.
|
|
||||||
func (t *Token) Encode() (string, error) {
|
|
||||||
var tok string
|
|
||||||
t.header = t.Header.encode()
|
|
||||||
t.claim = t.ClaimSet.encode()
|
|
||||||
err := t.sign()
|
|
||||||
if err != nil {
|
|
||||||
return tok, err
|
|
||||||
}
|
|
||||||
tok = fmt.Sprintf("%s.%s.%s", t.header, t.claim, t.sig)
|
|
||||||
return tok, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeWithoutSignature returns the url-encoded value of the Token
|
|
||||||
// before signing has occured (typically for use by external signers).
|
|
||||||
func (t *Token) EncodeWithoutSignature() string {
|
|
||||||
t.header = t.Header.encode()
|
|
||||||
t.claim = t.ClaimSet.encode()
|
|
||||||
return fmt.Sprintf("%s.%s", t.header, t.claim)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sign computes the signature for a Token. The details for this can be found
|
|
||||||
// in the OAuth2 Service Account documentation.
|
|
||||||
// https://developers.google.com/accounts/docs/OAuth2ServiceAccount#computingsignature
|
|
||||||
func (t *Token) sign() error {
|
|
||||||
if t.useExternalSigner {
|
|
||||||
fulldata, sig, err := t.signer.Sign(t)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
split := strings.Split(string(fulldata), ".")
|
|
||||||
if len(split) != 2 {
|
|
||||||
return errors.New("no token returned")
|
|
||||||
}
|
|
||||||
t.header = split[0]
|
|
||||||
t.claim = split[1]
|
|
||||||
t.sig = base64Encode(sig)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ss := fmt.Sprintf("%s.%s", t.header, t.claim)
|
|
||||||
if t.pKey == nil {
|
|
||||||
err := t.parsePrivateKey()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write([]byte(ss))
|
|
||||||
b, err := rsa.SignPKCS1v15(rand.Reader, t.pKey, crypto.SHA256, h.Sum(nil))
|
|
||||||
t.sig = base64Encode(b)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// parsePrivateKey converts the Token's Key ([]byte) into a parsed
|
|
||||||
// rsa.PrivateKey. If the key is not well formed this method will return an
|
|
||||||
// ErrInvalidKey error.
|
|
||||||
func (t *Token) parsePrivateKey() error {
|
|
||||||
block, _ := pem.Decode(t.Key)
|
|
||||||
if block == nil {
|
|
||||||
return ErrInvalidKey
|
|
||||||
}
|
|
||||||
parsedKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
t.pKey, ok = parsedKey.(*rsa.PrivateKey)
|
|
||||||
if !ok {
|
|
||||||
return ErrInvalidKey
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assert obtains an *oauth.Token from the remote server by encoding and sending
|
|
||||||
// a JWT. The access_token will expire in one hour (3600 seconds) and cannot be
|
|
||||||
// refreshed (no refresh_token is returned with the response). Once this token
|
|
||||||
// expires call this method again to get a fresh one.
|
|
||||||
func (t *Token) Assert(c *http.Client) (*oauth.Token, error) {
|
|
||||||
var o *oauth.Token
|
|
||||||
t.ClaimSet.setTimes(time.Now())
|
|
||||||
u, v, err := t.buildRequest()
|
|
||||||
if err != nil {
|
|
||||||
return o, err
|
|
||||||
}
|
|
||||||
resp, err := c.PostForm(u, v)
|
|
||||||
if err != nil {
|
|
||||||
return o, err
|
|
||||||
}
|
|
||||||
o, err = handleResponse(resp)
|
|
||||||
return o, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildRequest sets up the URL values and the proper URL string for making our
|
|
||||||
// access_token request.
|
|
||||||
func (t *Token) buildRequest() (string, url.Values, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
j, err := t.Encode()
|
|
||||||
if err != nil {
|
|
||||||
return t.ClaimSet.Aud, v, err
|
|
||||||
}
|
|
||||||
v.Set("grant_type", stdGrantType)
|
|
||||||
v.Set("assertion", j)
|
|
||||||
return t.ClaimSet.Aud, v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used for decoding the response body.
|
|
||||||
type respBody struct {
|
|
||||||
IdToken string `json:"id_token"`
|
|
||||||
Access string `json:"access_token"`
|
|
||||||
Type string `json:"token_type"`
|
|
||||||
ExpiresIn time.Duration `json:"expires_in"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleResponse returns a filled in *oauth.Token given the *http.Response from
|
|
||||||
// a *http.Request created by buildRequest.
|
|
||||||
func handleResponse(r *http.Response) (*oauth.Token, error) {
|
|
||||||
o := &oauth.Token{}
|
|
||||||
defer r.Body.Close()
|
|
||||||
if r.StatusCode != 200 {
|
|
||||||
return o, errors.New("invalid response: " + r.Status)
|
|
||||||
}
|
|
||||||
b := &respBody{}
|
|
||||||
err := json.NewDecoder(r.Body).Decode(b)
|
|
||||||
if err != nil {
|
|
||||||
return o, err
|
|
||||||
}
|
|
||||||
o.AccessToken = b.Access
|
|
||||||
if b.IdToken != "" {
|
|
||||||
// decode returned id token to get expiry
|
|
||||||
o.AccessToken = b.IdToken
|
|
||||||
s := strings.Split(b.IdToken, ".")
|
|
||||||
if len(s) < 2 {
|
|
||||||
return nil, errors.New("invalid token received")
|
|
||||||
}
|
|
||||||
d, err := base64Decode(s[1])
|
|
||||||
if err != nil {
|
|
||||||
return o, err
|
|
||||||
}
|
|
||||||
c := &ClaimSet{}
|
|
||||||
err = json.NewDecoder(bytes.NewBuffer(d)).Decode(c)
|
|
||||||
if err != nil {
|
|
||||||
return o, err
|
|
||||||
}
|
|
||||||
o.Expiry = time.Unix(c.Exp, 0)
|
|
||||||
return o, nil
|
|
||||||
}
|
|
||||||
o.Expiry = time.Now().Add(b.ExpiresIn * time.Second)
|
|
||||||
return o, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transport implements http.RoundTripper. When configured with a valid
|
|
||||||
// JWT and OAuth tokens it can be used to make authenticated HTTP requests.
|
|
||||||
//
|
|
||||||
// t := &jwt.Transport{jwtToken, oauthToken}
|
|
||||||
// r, _, err := t.Client().Get("http://example.org/url/requiring/auth")
|
|
||||||
//
|
|
||||||
// It will automatically refresh the OAuth token if it can, updating in place.
|
|
||||||
type Transport struct {
|
|
||||||
JWTToken *Token
|
|
||||||
OAuthToken *oauth.Token
|
|
||||||
|
|
||||||
// Transport is the HTTP transport to use when making requests.
|
|
||||||
// It will default to http.DefaultTransport if nil.
|
|
||||||
Transport http.RoundTripper
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a new authenticated transport.
|
|
||||||
func NewTransport(token *Token) (*Transport, error) {
|
|
||||||
oa, err := token.Assert(new(http.Client))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &Transport{
|
|
||||||
JWTToken: token,
|
|
||||||
OAuthToken: oa,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client returns an *http.Client that makes OAuth-authenticated requests.
|
|
||||||
func (t *Transport) Client() *http.Client {
|
|
||||||
return &http.Client{Transport: t}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetches the internal transport.
|
|
||||||
func (t *Transport) transport() http.RoundTripper {
|
|
||||||
if t.Transport != nil {
|
|
||||||
return t.Transport
|
|
||||||
}
|
|
||||||
return http.DefaultTransport
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoundTrip executes a single HTTP transaction using the Transport's
|
|
||||||
// OAuthToken as authorization headers.
|
|
||||||
//
|
|
||||||
// This method will attempt to renew the token if it has expired and may return
|
|
||||||
// an error related to that token renewal before attempting the client request.
|
|
||||||
// If the token cannot be renewed a non-nil os.Error value will be returned.
|
|
||||||
// If the token is invalid callers should expect HTTP-level errors,
|
|
||||||
// as indicated by the Response's StatusCode.
|
|
||||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
// Sanity check the two tokens
|
|
||||||
if t.JWTToken == nil {
|
|
||||||
return nil, fmt.Errorf("no JWT token supplied")
|
|
||||||
}
|
|
||||||
if t.OAuthToken == nil {
|
|
||||||
return nil, fmt.Errorf("no OAuth token supplied")
|
|
||||||
}
|
|
||||||
// Refresh the OAuth token if it has expired
|
|
||||||
if t.OAuthToken.Expired() {
|
|
||||||
if oa, err := t.JWTToken.Assert(new(http.Client)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
t.OAuthToken = oa
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// To set the Authorization header, we must make a copy of the Request
|
|
||||||
// so that we don't modify the Request we were given.
|
|
||||||
// This is required by the specification of http.RoundTripper.
|
|
||||||
req = cloneRequest(req)
|
|
||||||
req.Header.Set("Authorization", "Bearer "+t.OAuthToken.AccessToken)
|
|
||||||
|
|
||||||
// Make the HTTP request.
|
|
||||||
return t.transport().RoundTrip(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// cloneRequest returns a clone of the provided *http.Request.
|
|
||||||
// The clone is a shallow copy of the struct and its Header map.
|
|
||||||
func cloneRequest(r *http.Request) *http.Request {
|
|
||||||
// shallow copy of the struct
|
|
||||||
r2 := new(http.Request)
|
|
||||||
*r2 = *r
|
|
||||||
// deep copy of the Header
|
|
||||||
r2.Header = make(http.Header)
|
|
||||||
for k, s := range r.Header {
|
|
||||||
r2.Header[k] = s
|
|
||||||
}
|
|
||||||
return r2
|
|
||||||
}
|
|
480
Godeps/_workspace/src/code.google.com/p/goauth2/oauth/oauth.go
generated
vendored
480
Godeps/_workspace/src/code.google.com/p/goauth2/oauth/oauth.go
generated
vendored
@@ -1,480 +0,0 @@
|
|||||||
// Copyright 2011 The goauth2 Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package oauth supports making OAuth2-authenticated HTTP requests.
|
|
||||||
//
|
|
||||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
// !!! DEPRECATED. Use golang.org/x/oauth2 instead. !!!
|
|
||||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
//
|
|
||||||
// Example usage:
|
|
||||||
//
|
|
||||||
// // Specify your configuration. (typically as a global variable)
|
|
||||||
// var config = &oauth.Config{
|
|
||||||
// ClientId: YOUR_CLIENT_ID,
|
|
||||||
// ClientSecret: YOUR_CLIENT_SECRET,
|
|
||||||
// Scope: "https://www.googleapis.com/auth/buzz",
|
|
||||||
// AuthURL: "https://accounts.google.com/o/oauth2/auth",
|
|
||||||
// TokenURL: "https://accounts.google.com/o/oauth2/token",
|
|
||||||
// RedirectURL: "http://you.example.org/handler",
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // A landing page redirects to the OAuth provider to get the auth code.
|
|
||||||
// func landing(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// http.Redirect(w, r, config.AuthCodeURL("foo"), http.StatusFound)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // The user will be redirected back to this handler, that takes the
|
|
||||||
// // "code" query parameter and Exchanges it for an access token.
|
|
||||||
// func handler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// t := &oauth.Transport{Config: config}
|
|
||||||
// t.Exchange(r.FormValue("code"))
|
|
||||||
// // The Transport now has a valid Token. Create an *http.Client
|
|
||||||
// // with which we can make authenticated API requests.
|
|
||||||
// c := t.Client()
|
|
||||||
// c.Post(...)
|
|
||||||
// // ...
|
|
||||||
// // btw, r.FormValue("state") == "foo"
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
package oauth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"mime"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OAuthError is the error type returned by many operations.
|
|
||||||
//
|
|
||||||
// In retrospect it should not exist. Don't depend on it.
|
|
||||||
type OAuthError struct {
|
|
||||||
prefix string
|
|
||||||
msg string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oe OAuthError) Error() string {
|
|
||||||
return "OAuthError: " + oe.prefix + ": " + oe.msg
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache specifies the methods that implement a Token cache.
|
|
||||||
type Cache interface {
|
|
||||||
Token() (*Token, error)
|
|
||||||
PutToken(*Token) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// CacheFile implements Cache. Its value is the name of the file in which
|
|
||||||
// the Token is stored in JSON format.
|
|
||||||
type CacheFile string
|
|
||||||
|
|
||||||
func (f CacheFile) Token() (*Token, error) {
|
|
||||||
file, err := os.Open(string(f))
|
|
||||||
if err != nil {
|
|
||||||
return nil, OAuthError{"CacheFile.Token", err.Error()}
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
tok := &Token{}
|
|
||||||
if err := json.NewDecoder(file).Decode(tok); err != nil {
|
|
||||||
return nil, OAuthError{"CacheFile.Token", err.Error()}
|
|
||||||
}
|
|
||||||
return tok, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f CacheFile) PutToken(tok *Token) error {
|
|
||||||
file, err := os.OpenFile(string(f), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return OAuthError{"CacheFile.PutToken", err.Error()}
|
|
||||||
}
|
|
||||||
if err := json.NewEncoder(file).Encode(tok); err != nil {
|
|
||||||
file.Close()
|
|
||||||
return OAuthError{"CacheFile.PutToken", err.Error()}
|
|
||||||
}
|
|
||||||
if err := file.Close(); err != nil {
|
|
||||||
return OAuthError{"CacheFile.PutToken", err.Error()}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config is the configuration of an OAuth consumer.
|
|
||||||
type Config struct {
|
|
||||||
// ClientId is the OAuth client identifier used when communicating with
|
|
||||||
// the configured OAuth provider.
|
|
||||||
ClientId string
|
|
||||||
|
|
||||||
// ClientSecret is the OAuth client secret used when communicating with
|
|
||||||
// the configured OAuth provider.
|
|
||||||
ClientSecret string
|
|
||||||
|
|
||||||
// Scope identifies the level of access being requested. Multiple scope
|
|
||||||
// values should be provided as a space-delimited string.
|
|
||||||
Scope string
|
|
||||||
|
|
||||||
// AuthURL is the URL the user will be directed to in order to grant
|
|
||||||
// access.
|
|
||||||
AuthURL string
|
|
||||||
|
|
||||||
// TokenURL is the URL used to retrieve OAuth tokens.
|
|
||||||
TokenURL string
|
|
||||||
|
|
||||||
// RedirectURL is the URL to which the user will be returned after
|
|
||||||
// granting (or denying) access.
|
|
||||||
RedirectURL string
|
|
||||||
|
|
||||||
// TokenCache allows tokens to be cached for subsequent requests.
|
|
||||||
TokenCache Cache
|
|
||||||
|
|
||||||
// AccessType is an OAuth extension that gets sent as the
|
|
||||||
// "access_type" field in the URL from AuthCodeURL.
|
|
||||||
// See https://developers.google.com/accounts/docs/OAuth2WebServer.
|
|
||||||
// It may be "online" (the default) or "offline".
|
|
||||||
// If your application needs to refresh access tokens when the
|
|
||||||
// user is not present at the browser, then use offline. This
|
|
||||||
// will result in your application obtaining a refresh token
|
|
||||||
// the first time your application exchanges an authorization
|
|
||||||
// code for a user.
|
|
||||||
AccessType string
|
|
||||||
|
|
||||||
// ApprovalPrompt indicates whether the user should be
|
|
||||||
// re-prompted for consent. If set to "auto" (default) the
|
|
||||||
// user will be prompted only if they haven't previously
|
|
||||||
// granted consent and the code can only be exchanged for an
|
|
||||||
// access token.
|
|
||||||
// If set to "force" the user will always be prompted, and the
|
|
||||||
// code can be exchanged for a refresh token.
|
|
||||||
ApprovalPrompt string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token contains an end-user's tokens.
|
|
||||||
// This is the data you must store to persist authentication.
|
|
||||||
type Token struct {
|
|
||||||
AccessToken string
|
|
||||||
RefreshToken string
|
|
||||||
Expiry time.Time // If zero the token has no (known) expiry time.
|
|
||||||
|
|
||||||
// Extra optionally contains extra metadata from the server
|
|
||||||
// when updating a token. The only current key that may be
|
|
||||||
// populated is "id_token". It may be nil and will be
|
|
||||||
// initialized as needed.
|
|
||||||
Extra map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expired reports whether the token has expired or is invalid.
|
|
||||||
func (t *Token) Expired() bool {
|
|
||||||
if t.AccessToken == "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if t.Expiry.IsZero() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return t.Expiry.Before(time.Now())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transport implements http.RoundTripper. When configured with a valid
|
|
||||||
// Config and Token it can be used to make authenticated HTTP requests.
|
|
||||||
//
|
|
||||||
// t := &oauth.Transport{config}
|
|
||||||
// t.Exchange(code)
|
|
||||||
// // t now contains a valid Token
|
|
||||||
// r, _, err := t.Client().Get("http://example.org/url/requiring/auth")
|
|
||||||
//
|
|
||||||
// It will automatically refresh the Token if it can,
|
|
||||||
// updating the supplied Token in place.
|
|
||||||
type Transport struct {
|
|
||||||
*Config
|
|
||||||
*Token
|
|
||||||
|
|
||||||
// mu guards modifying the token.
|
|
||||||
mu sync.Mutex
|
|
||||||
|
|
||||||
// Transport is the HTTP transport to use when making requests.
|
|
||||||
// It will default to http.DefaultTransport if nil.
|
|
||||||
// (It should never be an oauth.Transport.)
|
|
||||||
Transport http.RoundTripper
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client returns an *http.Client that makes OAuth-authenticated requests.
|
|
||||||
func (t *Transport) Client() *http.Client {
|
|
||||||
return &http.Client{Transport: t}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Transport) transport() http.RoundTripper {
|
|
||||||
if t.Transport != nil {
|
|
||||||
return t.Transport
|
|
||||||
}
|
|
||||||
return http.DefaultTransport
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthCodeURL returns a URL that the end-user should be redirected to,
|
|
||||||
// so that they may obtain an authorization code.
|
|
||||||
func (c *Config) AuthCodeURL(state string) string {
|
|
||||||
url_, err := url.Parse(c.AuthURL)
|
|
||||||
if err != nil {
|
|
||||||
panic("AuthURL malformed: " + err.Error())
|
|
||||||
}
|
|
||||||
q := url.Values{
|
|
||||||
"response_type": {"code"},
|
|
||||||
"client_id": {c.ClientId},
|
|
||||||
"state": condVal(state),
|
|
||||||
"scope": condVal(c.Scope),
|
|
||||||
"redirect_uri": condVal(c.RedirectURL),
|
|
||||||
"access_type": condVal(c.AccessType),
|
|
||||||
"approval_prompt": condVal(c.ApprovalPrompt),
|
|
||||||
}.Encode()
|
|
||||||
if url_.RawQuery == "" {
|
|
||||||
url_.RawQuery = q
|
|
||||||
} else {
|
|
||||||
url_.RawQuery += "&" + q
|
|
||||||
}
|
|
||||||
return url_.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func condVal(v string) []string {
|
|
||||||
if v == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return []string{v}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exchange takes a code and gets access Token from the remote server.
|
|
||||||
func (t *Transport) Exchange(code string) (*Token, error) {
|
|
||||||
if t.Config == nil {
|
|
||||||
return nil, OAuthError{"Exchange", "no Config supplied"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the transport or the cache already has a token, it is
|
|
||||||
// passed to `updateToken` to preserve existing refresh token.
|
|
||||||
tok := t.Token
|
|
||||||
if tok == nil && t.TokenCache != nil {
|
|
||||||
tok, _ = t.TokenCache.Token()
|
|
||||||
}
|
|
||||||
if tok == nil {
|
|
||||||
tok = new(Token)
|
|
||||||
}
|
|
||||||
err := t.updateToken(tok, url.Values{
|
|
||||||
"grant_type": {"authorization_code"},
|
|
||||||
"redirect_uri": {t.RedirectURL},
|
|
||||||
"scope": {t.Scope},
|
|
||||||
"code": {code},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t.Token = tok
|
|
||||||
if t.TokenCache != nil {
|
|
||||||
return tok, t.TokenCache.PutToken(tok)
|
|
||||||
}
|
|
||||||
return tok, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoundTrip executes a single HTTP transaction using the Transport's
|
|
||||||
// Token as authorization headers.
|
|
||||||
//
|
|
||||||
// This method will attempt to renew the Token if it has expired and may return
|
|
||||||
// an error related to that Token renewal before attempting the client request.
|
|
||||||
// If the Token cannot be renewed a non-nil os.Error value will be returned.
|
|
||||||
// If the Token is invalid callers should expect HTTP-level errors,
|
|
||||||
// as indicated by the Response's StatusCode.
|
|
||||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
accessToken, err := t.getAccessToken()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// To set the Authorization header, we must make a copy of the Request
|
|
||||||
// so that we don't modify the Request we were given.
|
|
||||||
// This is required by the specification of http.RoundTripper.
|
|
||||||
req = cloneRequest(req)
|
|
||||||
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
||||||
|
|
||||||
// Make the HTTP request.
|
|
||||||
return t.transport().RoundTrip(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Transport) getAccessToken() (string, error) {
|
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
|
|
||||||
if t.Token == nil {
|
|
||||||
if t.Config == nil {
|
|
||||||
return "", OAuthError{"RoundTrip", "no Config supplied"}
|
|
||||||
}
|
|
||||||
if t.TokenCache == nil {
|
|
||||||
return "", OAuthError{"RoundTrip", "no Token supplied"}
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
t.Token, err = t.TokenCache.Token()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh the Token if it has expired.
|
|
||||||
if t.Expired() {
|
|
||||||
if err := t.Refresh(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if t.AccessToken == "" {
|
|
||||||
return "", errors.New("no access token obtained from refresh")
|
|
||||||
}
|
|
||||||
return t.AccessToken, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// cloneRequest returns a clone of the provided *http.Request.
|
|
||||||
// The clone is a shallow copy of the struct and its Header map.
|
|
||||||
func cloneRequest(r *http.Request) *http.Request {
|
|
||||||
// shallow copy of the struct
|
|
||||||
r2 := new(http.Request)
|
|
||||||
*r2 = *r
|
|
||||||
// deep copy of the Header
|
|
||||||
r2.Header = make(http.Header)
|
|
||||||
for k, s := range r.Header {
|
|
||||||
r2.Header[k] = s
|
|
||||||
}
|
|
||||||
return r2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh renews the Transport's AccessToken using its RefreshToken.
|
|
||||||
func (t *Transport) Refresh() error {
|
|
||||||
if t.Token == nil {
|
|
||||||
return OAuthError{"Refresh", "no existing Token"}
|
|
||||||
}
|
|
||||||
if t.RefreshToken == "" {
|
|
||||||
return OAuthError{"Refresh", "Token expired; no Refresh Token"}
|
|
||||||
}
|
|
||||||
if t.Config == nil {
|
|
||||||
return OAuthError{"Refresh", "no Config supplied"}
|
|
||||||
}
|
|
||||||
|
|
||||||
err := t.updateToken(t.Token, url.Values{
|
|
||||||
"grant_type": {"refresh_token"},
|
|
||||||
"refresh_token": {t.RefreshToken},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if t.TokenCache != nil {
|
|
||||||
return t.TokenCache.PutToken(t.Token)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthenticateClient gets an access Token using the client_credentials grant
|
|
||||||
// type.
|
|
||||||
func (t *Transport) AuthenticateClient() error {
|
|
||||||
if t.Config == nil {
|
|
||||||
return OAuthError{"Exchange", "no Config supplied"}
|
|
||||||
}
|
|
||||||
if t.Token == nil {
|
|
||||||
t.Token = &Token{}
|
|
||||||
}
|
|
||||||
return t.updateToken(t.Token, url.Values{"grant_type": {"client_credentials"}})
|
|
||||||
}
|
|
||||||
|
|
||||||
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
|
|
||||||
// implements the OAuth2 spec correctly
|
|
||||||
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
|
|
||||||
// In summary:
|
|
||||||
// - Reddit only accepts client secret in the Authorization header
|
|
||||||
// - Dropbox accepts either it in URL param or Auth header, but not both.
|
|
||||||
// - Google only accepts URL param (not spec compliant?), not Auth header
|
|
||||||
func providerAuthHeaderWorks(tokenURL string) bool {
|
|
||||||
if strings.HasPrefix(tokenURL, "https://accounts.google.com/") ||
|
|
||||||
strings.HasPrefix(tokenURL, "https://github.com/") ||
|
|
||||||
strings.HasPrefix(tokenURL, "https://api.instagram.com/") ||
|
|
||||||
strings.HasPrefix(tokenURL, "https://www.douban.com/") {
|
|
||||||
// Some sites fail to implement the OAuth2 spec fully.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assume the provider implements the spec properly
|
|
||||||
// otherwise. We can add more exceptions as they're
|
|
||||||
// discovered. We will _not_ be adding configurable hooks
|
|
||||||
// to this package to let users select server bugs.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateToken mutates both tok and v.
|
|
||||||
func (t *Transport) updateToken(tok *Token, v url.Values) error {
|
|
||||||
v.Set("client_id", t.ClientId)
|
|
||||||
bustedAuth := !providerAuthHeaderWorks(t.TokenURL)
|
|
||||||
if bustedAuth {
|
|
||||||
v.Set("client_secret", t.ClientSecret)
|
|
||||||
}
|
|
||||||
client := &http.Client{Transport: t.transport()}
|
|
||||||
req, err := http.NewRequest("POST", t.TokenURL, strings.NewReader(v.Encode()))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
if !bustedAuth {
|
|
||||||
req.SetBasicAuth(t.ClientId, t.ClientSecret)
|
|
||||||
}
|
|
||||||
r, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer r.Body.Close()
|
|
||||||
if r.StatusCode != 200 {
|
|
||||||
return OAuthError{"updateToken", "Unexpected HTTP status " + r.Status}
|
|
||||||
}
|
|
||||||
var b struct {
|
|
||||||
Access string `json:"access_token"`
|
|
||||||
Refresh string `json:"refresh_token"`
|
|
||||||
ExpiresIn int64 `json:"expires_in"` // seconds
|
|
||||||
Id string `json:"id_token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
|
||||||
switch content {
|
|
||||||
case "application/x-www-form-urlencoded", "text/plain":
|
|
||||||
vals, err := url.ParseQuery(string(body))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Access = vals.Get("access_token")
|
|
||||||
b.Refresh = vals.Get("refresh_token")
|
|
||||||
b.ExpiresIn, _ = strconv.ParseInt(vals.Get("expires_in"), 10, 64)
|
|
||||||
b.Id = vals.Get("id_token")
|
|
||||||
default:
|
|
||||||
if err = json.Unmarshal(body, &b); err != nil {
|
|
||||||
return fmt.Errorf("got bad response from server: %q", body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if b.Access == "" {
|
|
||||||
return errors.New("received empty access token from authorization server")
|
|
||||||
}
|
|
||||||
tok.AccessToken = b.Access
|
|
||||||
// Don't overwrite `RefreshToken` with an empty value
|
|
||||||
if b.Refresh != "" {
|
|
||||||
tok.RefreshToken = b.Refresh
|
|
||||||
}
|
|
||||||
if b.ExpiresIn == 0 {
|
|
||||||
tok.Expiry = time.Time{}
|
|
||||||
} else {
|
|
||||||
tok.Expiry = time.Now().Add(time.Duration(b.ExpiresIn) * time.Second)
|
|
||||||
}
|
|
||||||
if b.Id != "" {
|
|
||||||
if tok.Extra == nil {
|
|
||||||
tok.Extra = make(map[string]string)
|
|
||||||
}
|
|
||||||
tok.Extra["id_token"] = b.Id
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
2
Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go
generated
vendored
2
Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go
generated
vendored
@@ -30,7 +30,7 @@
|
|||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Protocol buffer deep copy and merge.
|
// Protocol buffer deep copy and merge.
|
||||||
// TODO: MessageSet and RawMessage.
|
// TODO: RawMessage.
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
|
|
||||||
|
26
Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go
generated
vendored
26
Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go
generated
vendored
@@ -105,6 +105,11 @@ func (p *Buffer) EncodeVarint(x uint64) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SizeVarint returns the varint encoding size of an integer.
|
||||||
|
func SizeVarint(x uint64) int {
|
||||||
|
return sizeVarint(x)
|
||||||
|
}
|
||||||
|
|
||||||
func sizeVarint(x uint64) (n int) {
|
func sizeVarint(x uint64) (n int) {
|
||||||
for {
|
for {
|
||||||
n++
|
n++
|
||||||
@@ -1248,24 +1253,9 @@ func size_struct(prop *StructProperties, base structPointer) (n int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Factor in any oneof fields.
|
// Factor in any oneof fields.
|
||||||
// TODO: This could be faster and use less reflection.
|
if prop.oneofSizer != nil {
|
||||||
if prop.oneofMarshaler != nil {
|
m := structPointer_Interface(base, prop.stype).(Message)
|
||||||
sv := reflect.ValueOf(structPointer_Interface(base, prop.stype)).Elem()
|
n += prop.oneofSizer(m)
|
||||||
for i := 0; i < prop.stype.NumField(); i++ {
|
|
||||||
fv := sv.Field(i)
|
|
||||||
if fv.Kind() != reflect.Interface || fv.IsNil() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if prop.stype.Field(i).Tag.Get("protobuf_oneof") == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
spv := fv.Elem() // interface -> *T
|
|
||||||
sv := spv.Elem() // *T -> T
|
|
||||||
sf := sv.Type().Field(0) // StructField inside T
|
|
||||||
var prop Properties
|
|
||||||
prop.Init(sf.Type, "whatever", sf.Tag.Get("protobuf"), &sf)
|
|
||||||
n += prop.size(&prop, toStructPointer(spv))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
29
Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go
generated
vendored
29
Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go
generated
vendored
@@ -30,7 +30,6 @@
|
|||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Protocol buffer comparison.
|
// Protocol buffer comparison.
|
||||||
// TODO: MessageSet.
|
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
|
|
||||||
@@ -51,7 +50,9 @@ Equality is defined in this way:
|
|||||||
are equal, and extensions sets are equal.
|
are equal, and extensions sets are equal.
|
||||||
- Two set scalar fields are equal iff their values are equal.
|
- Two set scalar fields are equal iff their values are equal.
|
||||||
If the fields are of a floating-point type, remember that
|
If the fields are of a floating-point type, remember that
|
||||||
NaN != x for all x, including NaN.
|
NaN != x for all x, including NaN. If the message is defined
|
||||||
|
in a proto3 .proto file, fields are not "set"; specifically,
|
||||||
|
zero length proto3 "bytes" fields are equal (nil == {}).
|
||||||
- Two repeated fields are equal iff their lengths are the same,
|
- Two repeated fields are equal iff their lengths are the same,
|
||||||
and their corresponding elements are equal (a "bytes" field,
|
and their corresponding elements are equal (a "bytes" field,
|
||||||
although represented by []byte, is not a repeated field)
|
although represented by []byte, is not a repeated field)
|
||||||
@@ -89,6 +90,7 @@ func Equal(a, b Message) bool {
|
|||||||
|
|
||||||
// v1 and v2 are known to have the same type.
|
// v1 and v2 are known to have the same type.
|
||||||
func equalStruct(v1, v2 reflect.Value) bool {
|
func equalStruct(v1, v2 reflect.Value) bool {
|
||||||
|
sprop := GetProperties(v1.Type())
|
||||||
for i := 0; i < v1.NumField(); i++ {
|
for i := 0; i < v1.NumField(); i++ {
|
||||||
f := v1.Type().Field(i)
|
f := v1.Type().Field(i)
|
||||||
if strings.HasPrefix(f.Name, "XXX_") {
|
if strings.HasPrefix(f.Name, "XXX_") {
|
||||||
@@ -114,7 +116,7 @@ func equalStruct(v1, v2 reflect.Value) bool {
|
|||||||
}
|
}
|
||||||
f1, f2 = f1.Elem(), f2.Elem()
|
f1, f2 = f1.Elem(), f2.Elem()
|
||||||
}
|
}
|
||||||
if !equalAny(f1, f2) {
|
if !equalAny(f1, f2, sprop.Prop[i]) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,7 +143,8 @@ func equalStruct(v1, v2 reflect.Value) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// v1 and v2 are known to have the same type.
|
// v1 and v2 are known to have the same type.
|
||||||
func equalAny(v1, v2 reflect.Value) bool {
|
// prop may be nil.
|
||||||
|
func equalAny(v1, v2 reflect.Value, prop *Properties) bool {
|
||||||
if v1.Type() == protoMessageType {
|
if v1.Type() == protoMessageType {
|
||||||
m1, _ := v1.Interface().(Message)
|
m1, _ := v1.Interface().(Message)
|
||||||
m2, _ := v2.Interface().(Message)
|
m2, _ := v2.Interface().(Message)
|
||||||
@@ -164,7 +167,7 @@ func equalAny(v1, v2 reflect.Value) bool {
|
|||||||
if e1.Type() != e2.Type() {
|
if e1.Type() != e2.Type() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return equalAny(e1, e2)
|
return equalAny(e1, e2, nil)
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
if v1.Len() != v2.Len() {
|
if v1.Len() != v2.Len() {
|
||||||
return false
|
return false
|
||||||
@@ -175,16 +178,22 @@ func equalAny(v1, v2 reflect.Value) bool {
|
|||||||
// This key was not found in the second map.
|
// This key was not found in the second map.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !equalAny(v1.MapIndex(key), val2) {
|
if !equalAny(v1.MapIndex(key), val2, nil) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
return equalAny(v1.Elem(), v2.Elem())
|
return equalAny(v1.Elem(), v2.Elem(), prop)
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if v1.Type().Elem().Kind() == reflect.Uint8 {
|
if v1.Type().Elem().Kind() == reflect.Uint8 {
|
||||||
// short circuit: []byte
|
// short circuit: []byte
|
||||||
|
|
||||||
|
// Edge case: if this is in a proto3 message, a zero length
|
||||||
|
// bytes field is considered the zero value.
|
||||||
|
if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if v1.IsNil() != v2.IsNil() {
|
if v1.IsNil() != v2.IsNil() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -195,7 +204,7 @@ func equalAny(v1, v2 reflect.Value) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i := 0; i < v1.Len(); i++ {
|
for i := 0; i < v1.Len(); i++ {
|
||||||
if !equalAny(v1.Index(i), v2.Index(i)) {
|
if !equalAny(v1.Index(i), v2.Index(i), prop) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,7 +239,7 @@ func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
|
|||||||
|
|
||||||
if m1 != nil && m2 != nil {
|
if m1 != nil && m2 != nil {
|
||||||
// Both are unencoded.
|
// Both are unencoded.
|
||||||
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
|
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
@@ -258,7 +267,7 @@ func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
|
|||||||
log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err)
|
log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
|
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go
generated
vendored
3
Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go
generated
vendored
@@ -301,7 +301,6 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
|
|||||||
o := NewBuffer(b)
|
o := NewBuffer(b)
|
||||||
|
|
||||||
t := reflect.TypeOf(extension.ExtensionType)
|
t := reflect.TypeOf(extension.ExtensionType)
|
||||||
rep := extension.repeated()
|
|
||||||
|
|
||||||
props := extensionProperties(extension)
|
props := extensionProperties(extension)
|
||||||
|
|
||||||
@@ -323,7 +322,7 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !rep || o.index >= len(o.buf) {
|
if o.index >= len(o.buf) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go
generated
vendored
11
Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go
generated
vendored
@@ -70,6 +70,12 @@ for a protocol buffer variable v:
|
|||||||
with distinguished wrapper types for each possible field value.
|
with distinguished wrapper types for each possible field value.
|
||||||
- Marshal and Unmarshal are functions to encode and decode the wire format.
|
- Marshal and Unmarshal are functions to encode and decode the wire format.
|
||||||
|
|
||||||
|
When the .proto file specifies `syntax="proto3"`, there are some differences:
|
||||||
|
|
||||||
|
- Non-repeated fields of non-message type are values instead of pointers.
|
||||||
|
- Getters are only generated for message and oneof fields.
|
||||||
|
- Enum types do not get an Enum method.
|
||||||
|
|
||||||
The simplest way to describe this is to see an example.
|
The simplest way to describe this is to see an example.
|
||||||
Given file test.proto, containing
|
Given file test.proto, containing
|
||||||
|
|
||||||
@@ -229,6 +235,7 @@ To create and play with a Test object:
|
|||||||
test := &pb.Test{
|
test := &pb.Test{
|
||||||
Label: proto.String("hello"),
|
Label: proto.String("hello"),
|
||||||
Type: proto.Int32(17),
|
Type: proto.Int32(17),
|
||||||
|
Reps: []int64{1, 2, 3},
|
||||||
Optionalgroup: &pb.Test_OptionalGroup{
|
Optionalgroup: &pb.Test_OptionalGroup{
|
||||||
RequiredField: proto.String("good bye"),
|
RequiredField: proto.String("good bye"),
|
||||||
},
|
},
|
||||||
@@ -881,3 +888,7 @@ func isProto3Zero(v reflect.Value) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
|
||||||
|
// to assert that that code is compatible with this version of the proto package.
|
||||||
|
const ProtoPackageIsVersion1 = true
|
||||||
|
41
Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go
generated
vendored
41
Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go
generated
vendored
@@ -44,11 +44,11 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNoMessageTypeId occurs when a protocol buffer does not have a message type ID.
|
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
|
||||||
// A message type ID is required for storing a protocol buffer in a message set.
|
// A message type ID is required for storing a protocol buffer in a message set.
|
||||||
var ErrNoMessageTypeId = errors.New("proto does not have a message type ID")
|
var errNoMessageTypeID = errors.New("proto does not have a message type ID")
|
||||||
|
|
||||||
// The first two types (_MessageSet_Item and MessageSet)
|
// The first two types (_MessageSet_Item and messageSet)
|
||||||
// model what the protocol compiler produces for the following protocol message:
|
// model what the protocol compiler produces for the following protocol message:
|
||||||
// message MessageSet {
|
// message MessageSet {
|
||||||
// repeated group Item = 1 {
|
// repeated group Item = 1 {
|
||||||
@@ -58,27 +58,20 @@ var ErrNoMessageTypeId = errors.New("proto does not have a message type ID")
|
|||||||
// }
|
// }
|
||||||
// That is the MessageSet wire format. We can't use a proto to generate these
|
// That is the MessageSet wire format. We can't use a proto to generate these
|
||||||
// because that would introduce a circular dependency between it and this package.
|
// because that would introduce a circular dependency between it and this package.
|
||||||
//
|
|
||||||
// When a proto1 proto has a field that looks like:
|
|
||||||
// optional message<MessageSet> info = 3;
|
|
||||||
// the protocol compiler produces a field in the generated struct that looks like:
|
|
||||||
// Info *_proto_.MessageSet `protobuf:"bytes,3,opt,name=info"`
|
|
||||||
// The package is automatically inserted so there is no need for that proto file to
|
|
||||||
// import this package.
|
|
||||||
|
|
||||||
type _MessageSet_Item struct {
|
type _MessageSet_Item struct {
|
||||||
TypeId *int32 `protobuf:"varint,2,req,name=type_id"`
|
TypeId *int32 `protobuf:"varint,2,req,name=type_id"`
|
||||||
Message []byte `protobuf:"bytes,3,req,name=message"`
|
Message []byte `protobuf:"bytes,3,req,name=message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MessageSet struct {
|
type messageSet struct {
|
||||||
Item []*_MessageSet_Item `protobuf:"group,1,rep"`
|
Item []*_MessageSet_Item `protobuf:"group,1,rep"`
|
||||||
XXX_unrecognized []byte
|
XXX_unrecognized []byte
|
||||||
// TODO: caching?
|
// TODO: caching?
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure MessageSet is a Message.
|
// Make sure messageSet is a Message.
|
||||||
var _ Message = (*MessageSet)(nil)
|
var _ Message = (*messageSet)(nil)
|
||||||
|
|
||||||
// messageTypeIder is an interface satisfied by a protocol buffer type
|
// messageTypeIder is an interface satisfied by a protocol buffer type
|
||||||
// that may be stored in a MessageSet.
|
// that may be stored in a MessageSet.
|
||||||
@@ -86,7 +79,7 @@ type messageTypeIder interface {
|
|||||||
MessageTypeId() int32
|
MessageTypeId() int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MessageSet) find(pb Message) *_MessageSet_Item {
|
func (ms *messageSet) find(pb Message) *_MessageSet_Item {
|
||||||
mti, ok := pb.(messageTypeIder)
|
mti, ok := pb.(messageTypeIder)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
@@ -100,24 +93,24 @@ func (ms *MessageSet) find(pb Message) *_MessageSet_Item {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MessageSet) Has(pb Message) bool {
|
func (ms *messageSet) Has(pb Message) bool {
|
||||||
if ms.find(pb) != nil {
|
if ms.find(pb) != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MessageSet) Unmarshal(pb Message) error {
|
func (ms *messageSet) Unmarshal(pb Message) error {
|
||||||
if item := ms.find(pb); item != nil {
|
if item := ms.find(pb); item != nil {
|
||||||
return Unmarshal(item.Message, pb)
|
return Unmarshal(item.Message, pb)
|
||||||
}
|
}
|
||||||
if _, ok := pb.(messageTypeIder); !ok {
|
if _, ok := pb.(messageTypeIder); !ok {
|
||||||
return ErrNoMessageTypeId
|
return errNoMessageTypeID
|
||||||
}
|
}
|
||||||
return nil // TODO: return error instead?
|
return nil // TODO: return error instead?
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MessageSet) Marshal(pb Message) error {
|
func (ms *messageSet) Marshal(pb Message) error {
|
||||||
msg, err := Marshal(pb)
|
msg, err := Marshal(pb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -130,7 +123,7 @@ func (ms *MessageSet) Marshal(pb Message) error {
|
|||||||
|
|
||||||
mti, ok := pb.(messageTypeIder)
|
mti, ok := pb.(messageTypeIder)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrNoMessageTypeId
|
return errNoMessageTypeID
|
||||||
}
|
}
|
||||||
|
|
||||||
mtid := mti.MessageTypeId()
|
mtid := mti.MessageTypeId()
|
||||||
@@ -141,9 +134,9 @@ func (ms *MessageSet) Marshal(pb Message) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MessageSet) Reset() { *ms = MessageSet{} }
|
func (ms *messageSet) Reset() { *ms = messageSet{} }
|
||||||
func (ms *MessageSet) String() string { return CompactTextString(ms) }
|
func (ms *messageSet) String() string { return CompactTextString(ms) }
|
||||||
func (*MessageSet) ProtoMessage() {}
|
func (*messageSet) ProtoMessage() {}
|
||||||
|
|
||||||
// Support for the message_set_wire_format message option.
|
// Support for the message_set_wire_format message option.
|
||||||
|
|
||||||
@@ -169,7 +162,7 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
sort.Ints(ids)
|
sort.Ints(ids)
|
||||||
|
|
||||||
ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
|
ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
e := m[int32(id)]
|
e := m[int32(id)]
|
||||||
// Remove the wire type and field number varint, as well as the length varint.
|
// Remove the wire type and field number varint, as well as the length varint.
|
||||||
@@ -186,7 +179,7 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
|
|||||||
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
||||||
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error {
|
func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error {
|
||||||
ms := new(MessageSet)
|
ms := new(messageSet)
|
||||||
if err := Unmarshal(buf, ms); err != nil {
|
if err := Unmarshal(buf, ms); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
8
Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go
generated
vendored
8
Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go
generated
vendored
@@ -91,6 +91,9 @@ type oneofMarshaler func(Message, *Buffer) error
|
|||||||
// A oneofUnmarshaler does the unmarshaling for a oneof field in a message.
|
// A oneofUnmarshaler does the unmarshaling for a oneof field in a message.
|
||||||
type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error)
|
type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error)
|
||||||
|
|
||||||
|
// A oneofSizer does the sizing for all oneof fields in a message.
|
||||||
|
type oneofSizer func(Message) int
|
||||||
|
|
||||||
// tagMap is an optimization over map[int]int for typical protocol buffer
|
// tagMap is an optimization over map[int]int for typical protocol buffer
|
||||||
// use-cases. Encoded protocol buffers are often in tag order with small tag
|
// use-cases. Encoded protocol buffers are often in tag order with small tag
|
||||||
// numbers.
|
// numbers.
|
||||||
@@ -142,6 +145,7 @@ type StructProperties struct {
|
|||||||
|
|
||||||
oneofMarshaler oneofMarshaler
|
oneofMarshaler oneofMarshaler
|
||||||
oneofUnmarshaler oneofUnmarshaler
|
oneofUnmarshaler oneofUnmarshaler
|
||||||
|
oneofSizer oneofSizer
|
||||||
stype reflect.Type
|
stype reflect.Type
|
||||||
|
|
||||||
// OneofTypes contains information about the oneof fields in this message.
|
// OneofTypes contains information about the oneof fields in this message.
|
||||||
@@ -712,11 +716,11 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
|
|||||||
sort.Sort(prop)
|
sort.Sort(prop)
|
||||||
|
|
||||||
type oneofMessage interface {
|
type oneofMessage interface {
|
||||||
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), []interface{})
|
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
|
||||||
}
|
}
|
||||||
if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
|
if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
|
||||||
var oots []interface{}
|
var oots []interface{}
|
||||||
prop.oneofMarshaler, prop.oneofUnmarshaler, oots = om.XXX_OneofFuncs()
|
prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs()
|
||||||
prop.stype = t
|
prop.stype = t
|
||||||
|
|
||||||
// Interpret oneof metadata.
|
// Interpret oneof metadata.
|
||||||
|
46
Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go
generated
vendored
46
Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go
generated
vendored
@@ -170,20 +170,12 @@ func writeName(w *textWriter, props *Properties) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
|
|
||||||
)
|
|
||||||
|
|
||||||
// raw is the interface satisfied by RawMessage.
|
// raw is the interface satisfied by RawMessage.
|
||||||
type raw interface {
|
type raw interface {
|
||||||
Bytes() []byte
|
Bytes() []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeStruct(w *textWriter, sv reflect.Value) error {
|
func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
if sv.Type() == messageSetType {
|
|
||||||
return writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
|
|
||||||
}
|
|
||||||
|
|
||||||
st := sv.Type()
|
st := sv.Type()
|
||||||
sprops := GetProperties(st)
|
sprops := GetProperties(st)
|
||||||
for i := 0; i < sv.NumField(); i++ {
|
for i := 0; i < sv.NumField(); i++ {
|
||||||
@@ -525,44 +517,6 @@ func writeString(w *textWriter, s string) error {
|
|||||||
return w.WriteByte('"')
|
return w.WriteByte('"')
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeMessageSet(w *textWriter, ms *MessageSet) error {
|
|
||||||
for _, item := range ms.Item {
|
|
||||||
id := *item.TypeId
|
|
||||||
if msd, ok := messageSetMap[id]; ok {
|
|
||||||
// Known message set type.
|
|
||||||
if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.indent()
|
|
||||||
|
|
||||||
pb := reflect.New(msd.t.Elem())
|
|
||||||
if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil {
|
|
||||||
if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := writeStruct(w, pb.Elem()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Unknown type.
|
|
||||||
if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.indent()
|
|
||||||
if err := writeUnknownStruct(w, item.Message); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.unindent()
|
|
||||||
if _, err := w.Write(gtNewline); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeUnknownStruct(w *textWriter, data []byte) (err error) {
|
func writeUnknownStruct(w *textWriter, data []byte) (err error) {
|
||||||
if !w.compact {
|
if !w.compact {
|
||||||
if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
|
if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
|
||||||
|
@@ -249,11 +249,11 @@ func (s *ActivityService) ListEventsPerformedByUser(user string, publicOnly bool
|
|||||||
return *events, resp, err
|
return *events, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListEventsRecievedByUser lists the events recieved by a user. If publicOnly is
|
// ListEventsReceivedByUser lists the events received by a user. If publicOnly is
|
||||||
// true, only public events will be returned.
|
// true, only public events will be returned.
|
||||||
//
|
//
|
||||||
// GitHub API docs: http://developer.github.com/v3/activity/events/#list-events-that-a-user-has-received
|
// GitHub API docs: http://developer.github.com/v3/activity/events/#list-events-that-a-user-has-received
|
||||||
func (s *ActivityService) ListEventsRecievedByUser(user string, publicOnly bool, opt *ListOptions) ([]Event, *Response, error) {
|
func (s *ActivityService) ListEventsReceivedByUser(user string, publicOnly bool, opt *ListOptions) ([]Event, *Response, error) {
|
||||||
var u string
|
var u string
|
||||||
if publicOnly {
|
if publicOnly {
|
||||||
u = fmt.Sprintf("users/%v/received_events/public", user)
|
u = fmt.Sprintf("users/%v/received_events/public", user)
|
@@ -41,6 +41,7 @@ type NotificationListOptions struct {
|
|||||||
All bool `url:"all,omitempty"`
|
All bool `url:"all,omitempty"`
|
||||||
Participating bool `url:"participating,omitempty"`
|
Participating bool `url:"participating,omitempty"`
|
||||||
Since time.Time `url:"since,omitempty"`
|
Since time.Time `url:"since,omitempty"`
|
||||||
|
Before time.Time `url:"before,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListNotifications lists all notifications for the authenticated user.
|
// ListNotifications lists all notifications for the authenticated user.
|
@@ -50,13 +50,18 @@ func (s *ActivityService) ListWatchers(owner, repo string, opt *ListOptions) ([]
|
|||||||
// the empty string will fetch watched repos for the authenticated user.
|
// the empty string will fetch watched repos for the authenticated user.
|
||||||
//
|
//
|
||||||
// GitHub API Docs: https://developer.github.com/v3/activity/watching/#list-repositories-being-watched
|
// GitHub API Docs: https://developer.github.com/v3/activity/watching/#list-repositories-being-watched
|
||||||
func (s *ActivityService) ListWatched(user string) ([]Repository, *Response, error) {
|
func (s *ActivityService) ListWatched(user string, opt *ListOptions) ([]Repository, *Response, error) {
|
||||||
var u string
|
var u string
|
||||||
if user != "" {
|
if user != "" {
|
||||||
u = fmt.Sprintf("users/%v/subscriptions", user)
|
u = fmt.Sprintf("users/%v/subscriptions", user)
|
||||||
} else {
|
} else {
|
||||||
u = "user/subscriptions"
|
u = "user/subscriptions"
|
||||||
}
|
}
|
||||||
|
u, err := addOptions(u, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
req, err := s.client.NewRequest("GET", u, nil)
|
req, err := s.client.NewRequest("GET", u, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
@@ -74,7 +74,7 @@ The GitHub API has good support for conditional requests which will help
|
|||||||
prevent you from burning through your rate limit, as well as help speed up your
|
prevent you from burning through your rate limit, as well as help speed up your
|
||||||
application. go-github does not handle conditional requests directly, but is
|
application. go-github does not handle conditional requests directly, but is
|
||||||
instead designed to work with a caching http.Transport. We recommend using
|
instead designed to work with a caching http.Transport. We recommend using
|
||||||
https://github.com/gregjones/httpcache, which can be used in conjuction with
|
https://github.com/gregjones/httpcache, which can be used in conjunction with
|
||||||
https://github.com/sourcegraph/apiproxy to provide additional flexibility and
|
https://github.com/sourcegraph/apiproxy to provide additional flexibility and
|
||||||
control of caching rules.
|
control of caching rules.
|
||||||
|
|
@@ -33,7 +33,7 @@ func (s *GitService) GetBlob(owner string, repo string, sha string) (*Blob, *Res
|
|||||||
|
|
||||||
// CreateBlob creates a blob object.
|
// CreateBlob creates a blob object.
|
||||||
//
|
//
|
||||||
// GitHub API docs: http://developer.github.com/v3/git/blobs/#create-a-blob
|
// GitHub API docs: https://developer.github.com/v3/git/blobs/#create-a-blob
|
||||||
func (s *GitService) CreateBlob(owner string, repo string, blob *Blob) (*Blob, *Response, error) {
|
func (s *GitService) CreateBlob(owner string, repo string, blob *Blob) (*Blob, *Response, error) {
|
||||||
u := fmt.Sprintf("repos/%v/%v/git/blobs", owner, repo)
|
u := fmt.Sprintf("repos/%v/%v/git/blobs", owner, repo)
|
||||||
req, err := s.client.NewRequest("POST", u, blob)
|
req, err := s.client.NewRequest("POST", u, blob)
|
@@ -17,6 +17,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-querystring/query"
|
"github.com/google/go-querystring/query"
|
||||||
@@ -31,6 +32,7 @@ const (
|
|||||||
headerRateLimit = "X-RateLimit-Limit"
|
headerRateLimit = "X-RateLimit-Limit"
|
||||||
headerRateRemaining = "X-RateLimit-Remaining"
|
headerRateRemaining = "X-RateLimit-Remaining"
|
||||||
headerRateReset = "X-RateLimit-Reset"
|
headerRateReset = "X-RateLimit-Reset"
|
||||||
|
headerOTP = "X-GitHub-OTP"
|
||||||
|
|
||||||
mediaTypeV3 = "application/vnd.github.v3+json"
|
mediaTypeV3 = "application/vnd.github.v3+json"
|
||||||
defaultMediaType = "application/octet-stream"
|
defaultMediaType = "application/octet-stream"
|
||||||
@@ -46,6 +48,9 @@ const (
|
|||||||
// https://developer.github.com/changes/2015-06-24-api-enhancements-for-working-with-organization-permissions/
|
// https://developer.github.com/changes/2015-06-24-api-enhancements-for-working-with-organization-permissions/
|
||||||
mediaTypeOrgPermissionPreview = "application/vnd.github.ironman-preview+json"
|
mediaTypeOrgPermissionPreview = "application/vnd.github.ironman-preview+json"
|
||||||
mediaTypeOrgPermissionRepoPreview = "application/vnd.github.ironman-preview.repository+json"
|
mediaTypeOrgPermissionRepoPreview = "application/vnd.github.ironman-preview.repository+json"
|
||||||
|
|
||||||
|
// https://developer.github.com/changes/2015-11-11-protected-branches-api/
|
||||||
|
mediaTypeProtectedBranchesPreview = "application/vnd.github.loki-preview+json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Client manages communication with the GitHub API.
|
// A Client manages communication with the GitHub API.
|
||||||
@@ -64,11 +69,8 @@ type Client struct {
|
|||||||
// User agent used when communicating with the GitHub API.
|
// User agent used when communicating with the GitHub API.
|
||||||
UserAgent string
|
UserAgent string
|
||||||
|
|
||||||
// Rate specifies the current rate limit for the client as determined by the
|
rateMu sync.Mutex
|
||||||
// most recent API call. If the client is used in a multi-user application,
|
rate Rate
|
||||||
// this rate may not always be up-to-date. Call RateLimit() to check the
|
|
||||||
// current rate.
|
|
||||||
Rate Rate
|
|
||||||
|
|
||||||
// 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
|
||||||
@@ -292,6 +294,17 @@ func (r *Response) populateRate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rate specifies the current rate limit for the client as determined by the
|
||||||
|
// most recent API call. If the client is used in a multi-user application,
|
||||||
|
// this rate may not always be up-to-date. Call RateLimits() to check the
|
||||||
|
// current rate.
|
||||||
|
func (c *Client) Rate() Rate {
|
||||||
|
c.rateMu.Lock()
|
||||||
|
rate := c.rate
|
||||||
|
c.rateMu.Unlock()
|
||||||
|
return rate
|
||||||
|
}
|
||||||
|
|
||||||
// Do sends an API request and returns the API response. The API response is
|
// Do sends an API request and returns the API response. The API response is
|
||||||
// JSON decoded and stored in the value pointed to by v, or returned as an
|
// JSON decoded and stored in the value pointed to by v, or returned as an
|
||||||
// error if an API error has occurred. If v implements the io.Writer
|
// error if an API error has occurred. If v implements the io.Writer
|
||||||
@@ -307,7 +320,9 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
|
|||||||
|
|
||||||
response := newResponse(resp)
|
response := newResponse(resp)
|
||||||
|
|
||||||
c.Rate = response.Rate
|
c.rateMu.Lock()
|
||||||
|
c.rate = response.Rate
|
||||||
|
c.rateMu.Unlock()
|
||||||
|
|
||||||
err = CheckResponse(resp)
|
err = CheckResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -321,6 +336,9 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
|
|||||||
io.Copy(w, resp.Body)
|
io.Copy(w, resp.Body)
|
||||||
} else {
|
} else {
|
||||||
err = json.NewDecoder(resp.Body).Decode(v)
|
err = json.NewDecoder(resp.Body).Decode(v)
|
||||||
|
if err == io.EOF {
|
||||||
|
err = nil // ignore EOF errors caused by empty response body
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return response, err
|
return response, err
|
||||||
@@ -343,8 +361,15 @@ func (r *ErrorResponse) Error() string {
|
|||||||
r.Response.StatusCode, r.Message, r.Errors)
|
r.Response.StatusCode, r.Message, r.Errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sanitizeURL redacts the client_id and client_secret tokens from the URL which
|
// TwoFactorAuthError occurs when using HTTP Basic Authentication for a user
|
||||||
// may be exposed to the user, specifically in the ErrorResponse error message.
|
// that has two-factor authentication enabled. The request can be reattempted
|
||||||
|
// by providing a one-time password in the request.
|
||||||
|
type TwoFactorAuthError ErrorResponse
|
||||||
|
|
||||||
|
func (r *TwoFactorAuthError) Error() string { return (*ErrorResponse)(r).Error() }
|
||||||
|
|
||||||
|
// sanitizeURL redacts the client_secret parameter from the URL which may be
|
||||||
|
// exposed to the user, specifically in the ErrorResponse error message.
|
||||||
func sanitizeURL(uri *url.URL) *url.URL {
|
func sanitizeURL(uri *url.URL) *url.URL {
|
||||||
if uri == nil {
|
if uri == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -397,6 +422,9 @@ 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") {
|
||||||
|
return (*TwoFactorAuthError)(errorResponse)
|
||||||
|
}
|
||||||
return errorResponse
|
return errorResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,6 +576,43 @@ func (t *UnauthenticatedRateLimitedTransport) transport() http.RoundTripper {
|
|||||||
return http.DefaultTransport
|
return http.DefaultTransport
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BasicAuthTransport is an http.RoundTripper that authenticates all requests
|
||||||
|
// using HTTP Basic Authentication with the provided username and password. It
|
||||||
|
// additionally supports users who have two-factor authentication enabled on
|
||||||
|
// their GitHub account.
|
||||||
|
type BasicAuthTransport struct {
|
||||||
|
Username string // GitHub username
|
||||||
|
Password string // GitHub password
|
||||||
|
OTP string // one-time password for users with two-factor auth enabled
|
||||||
|
|
||||||
|
// Transport is the underlying HTTP transport to use when making requests.
|
||||||
|
// It will default to http.DefaultTransport if nil.
|
||||||
|
Transport http.RoundTripper
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundTrip implements the RoundTripper interface.
|
||||||
|
func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
req = cloneRequest(req) // per RoundTrip contract
|
||||||
|
req.SetBasicAuth(t.Username, t.Password)
|
||||||
|
if t.OTP != "" {
|
||||||
|
req.Header.Add(headerOTP, t.OTP)
|
||||||
|
}
|
||||||
|
return t.transport().RoundTrip(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client returns an *http.Client that makes requests that are authenticated
|
||||||
|
// using HTTP Basic Authentication.
|
||||||
|
func (t *BasicAuthTransport) Client() *http.Client {
|
||||||
|
return &http.Client{Transport: t}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *BasicAuthTransport) transport() http.RoundTripper {
|
||||||
|
if t.Transport != nil {
|
||||||
|
return t.Transport
|
||||||
|
}
|
||||||
|
return http.DefaultTransport
|
||||||
|
}
|
||||||
|
|
||||||
// cloneRequest returns a clone of the provided *http.Request. The clone is a
|
// cloneRequest returns a clone of the provided *http.Request. The clone is a
|
||||||
// shallow copy of the struct and its Header map.
|
// shallow copy of the struct and its Header map.
|
||||||
func cloneRequest(r *http.Request) *http.Request {
|
func cloneRequest(r *http.Request) *http.Request {
|
||||||
@@ -555,9 +620,9 @@ func cloneRequest(r *http.Request) *http.Request {
|
|||||||
r2 := new(http.Request)
|
r2 := new(http.Request)
|
||||||
*r2 = *r
|
*r2 = *r
|
||||||
// deep copy of the Header
|
// deep copy of the Header
|
||||||
r2.Header = make(http.Header)
|
r2.Header = make(http.Header, len(r.Header))
|
||||||
for k, s := range r.Header {
|
for k, s := range r.Header {
|
||||||
r2.Header[k] = s
|
r2.Header[k] = append([]string(nil), s...)
|
||||||
}
|
}
|
||||||
return r2
|
return r2
|
||||||
}
|
}
|
@@ -65,7 +65,7 @@ type IssueListOptions struct {
|
|||||||
Filter string `url:"filter,omitempty"`
|
Filter string `url:"filter,omitempty"`
|
||||||
|
|
||||||
// State filters issues based on their state. Possible values are: open,
|
// State filters issues based on their state. Possible values are: open,
|
||||||
// closed. Default is "open".
|
// closed, all. Default is "open".
|
||||||
State string `url:"state,omitempty"`
|
State string `url:"state,omitempty"`
|
||||||
|
|
||||||
// Labels filters issues based on their label.
|
// Labels filters issues based on their label.
|
||||||
@@ -76,7 +76,7 @@ type IssueListOptions struct {
|
|||||||
Sort string `url:"sort,omitempty"`
|
Sort string `url:"sort,omitempty"`
|
||||||
|
|
||||||
// Direction in which to sort issues. Possible values are: asc, desc.
|
// Direction in which to sort issues. Possible values are: asc, desc.
|
||||||
// Default is "asc".
|
// Default is "desc".
|
||||||
Direction string `url:"direction,omitempty"`
|
Direction string `url:"direction,omitempty"`
|
||||||
|
|
||||||
// Since filters issues by time.
|
// Since filters issues by time.
|
||||||
@@ -148,7 +148,7 @@ type IssueListByRepoOptions struct {
|
|||||||
Milestone string `url:"milestone,omitempty"`
|
Milestone string `url:"milestone,omitempty"`
|
||||||
|
|
||||||
// State filters issues based on their state. Possible values are: open,
|
// State filters issues based on their state. Possible values are: open,
|
||||||
// closed. Default is "open".
|
// closed, all. Default is "open".
|
||||||
State string `url:"state,omitempty"`
|
State string `url:"state,omitempty"`
|
||||||
|
|
||||||
// Assignee filters issues based on their assignee. Possible values are a
|
// Assignee filters issues based on their assignee. Possible values are a
|
||||||
@@ -156,10 +156,10 @@ type IssueListByRepoOptions struct {
|
|||||||
// any assigned user.
|
// any assigned user.
|
||||||
Assignee string `url:"assignee,omitempty"`
|
Assignee string `url:"assignee,omitempty"`
|
||||||
|
|
||||||
// Assignee filters issues based on their creator.
|
// Creator filters issues based on their creator.
|
||||||
Creator string `url:"creator,omitempty"`
|
Creator string `url:"creator,omitempty"`
|
||||||
|
|
||||||
// Assignee filters issues to those mentioned a specific user.
|
// Mentioned filters issues to those mentioned a specific user.
|
||||||
Mentioned string `url:"mentioned,omitempty"`
|
Mentioned string `url:"mentioned,omitempty"`
|
||||||
|
|
||||||
// Labels filters issues based on their label.
|
// Labels filters issues based on their label.
|
||||||
@@ -170,7 +170,7 @@ type IssueListByRepoOptions struct {
|
|||||||
Sort string `url:"sort,omitempty"`
|
Sort string `url:"sort,omitempty"`
|
||||||
|
|
||||||
// Direction in which to sort issues. Possible values are: asc, desc.
|
// Direction in which to sort issues. Possible values are: asc, desc.
|
||||||
// Default is "asc".
|
// Default is "desc".
|
||||||
Direction string `url:"direction,omitempty"`
|
Direction string `url:"direction,omitempty"`
|
||||||
|
|
||||||
// Since filters issues by time.
|
// Since filters issues by time.
|
@@ -22,40 +22,52 @@ type IssueEvent struct {
|
|||||||
// values are:
|
// values are:
|
||||||
//
|
//
|
||||||
// closed
|
// closed
|
||||||
// The issue was closed by the actor. When the commit_id is
|
// The Actor closed the issue.
|
||||||
// present, it identifies the commit that closed the issue using
|
// If the issue was closed by commit message, CommitID holds the SHA1 hash of the commit.
|
||||||
// “closes / fixes #NN” syntax.
|
|
||||||
//
|
|
||||||
// reopened
|
|
||||||
// The issue was reopened by the actor.
|
|
||||||
//
|
|
||||||
// subscribed
|
|
||||||
// The actor subscribed to receive notifications for an issue.
|
|
||||||
//
|
//
|
||||||
// merged
|
// merged
|
||||||
// The issue was merged by the actor. The commit_id attribute is the SHA1 of the HEAD commit that was merged.
|
// The Actor merged into master a branch containing a commit mentioning the issue.
|
||||||
|
// CommitID holds the SHA1 of the merge commit.
|
||||||
//
|
//
|
||||||
// referenced
|
// referenced
|
||||||
// The issue was referenced from a commit message. The commit_id attribute is the commit SHA1 of where that happened.
|
// The Actor committed to master a commit mentioning the issue in its commit message.
|
||||||
|
// CommitID holds the SHA1 of the commit.
|
||||||
|
//
|
||||||
|
// reopened, locked, unlocked
|
||||||
|
// The Actor did that to the issue.
|
||||||
|
//
|
||||||
|
// renamed
|
||||||
|
// The Actor changed the issue title from Rename.From to Rename.To.
|
||||||
//
|
//
|
||||||
// mentioned
|
// mentioned
|
||||||
// The actor was @mentioned in an issue body.
|
// Someone unspecified @mentioned the Actor [sic] in an issue comment body.
|
||||||
//
|
//
|
||||||
// assigned
|
// assigned, unassigned
|
||||||
// The issue was assigned to the actor.
|
// The Actor assigned the issue to or removed the assignment from the Assignee.
|
||||||
//
|
//
|
||||||
// head_ref_deleted
|
// labeled, unlabeled
|
||||||
// The pull request’s branch was deleted.
|
// The Actor added or removed the Label from the issue.
|
||||||
|
//
|
||||||
|
// milestoned, demilestoned
|
||||||
|
// The Actor added or removed the issue from the Milestone.
|
||||||
|
//
|
||||||
|
// subscribed, unsubscribed
|
||||||
|
// The Actor subscribed to or unsubscribed from notifications for an issue.
|
||||||
|
//
|
||||||
|
// head_ref_deleted, head_ref_restored
|
||||||
|
// The pull request’s branch was deleted or restored.
|
||||||
//
|
//
|
||||||
// head_ref_restored
|
|
||||||
// The pull request’s branch was restored.
|
|
||||||
Event *string `json:"event,omitempty"`
|
Event *string `json:"event,omitempty"`
|
||||||
|
|
||||||
// The SHA of the commit that referenced this commit, if applicable.
|
|
||||||
CommitID *string `json:"commit_id,omitempty"`
|
|
||||||
|
|
||||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||||
Issue *Issue `json:"issue,omitempty"`
|
Issue *Issue `json:"issue,omitempty"`
|
||||||
|
|
||||||
|
// Only present on certain events; see above.
|
||||||
|
Assignee *User `json:"assignee,omitempty"`
|
||||||
|
CommitID *string `json:"commit_id,omitempty"`
|
||||||
|
Milestone *Milestone `json:"milestone,omitempty"`
|
||||||
|
Label *Label `json:"label,omitempty"`
|
||||||
|
Rename *Rename `json:"rename,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListIssueEvents lists events for the specified issue.
|
// ListIssueEvents lists events for the specified issue.
|
||||||
@@ -125,3 +137,13 @@ func (s *IssuesService) GetEvent(owner, repo string, id int) (*IssueEvent, *Resp
|
|||||||
|
|
||||||
return event, resp, err
|
return event, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rename contains details for 'renamed' events.
|
||||||
|
type Rename struct {
|
||||||
|
From *string `json:"from,omitempty"`
|
||||||
|
To *string `json:"to,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Rename) String() string {
|
||||||
|
return Stringify(r)
|
||||||
|
}
|
@@ -49,7 +49,7 @@ type MilestoneListOptions struct {
|
|||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository
|
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository
|
||||||
func (s *IssuesService) ListMilestones(owner string, repo string, opt *MilestoneListOptions) ([]Milestone, *Response, error) {
|
func (s *IssuesService) ListMilestones(owner string, repo string, opt *MilestoneListOptions) ([]Milestone, *Response, error) {
|
||||||
u := fmt.Sprintf("/repos/%v/%v/milestones", owner, repo)
|
u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo)
|
||||||
u, err := addOptions(u, opt)
|
u, err := addOptions(u, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -73,7 +73,7 @@ func (s *IssuesService) ListMilestones(owner string, repo string, opt *Milestone
|
|||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#get-a-single-milestone
|
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#get-a-single-milestone
|
||||||
func (s *IssuesService) GetMilestone(owner string, repo string, number int) (*Milestone, *Response, error) {
|
func (s *IssuesService) GetMilestone(owner string, repo string, number int) (*Milestone, *Response, error) {
|
||||||
u := fmt.Sprintf("/repos/%v/%v/milestones/%d", owner, repo, number)
|
u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number)
|
||||||
req, err := s.client.NewRequest("GET", u, nil)
|
req, err := s.client.NewRequest("GET", u, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -92,7 +92,7 @@ func (s *IssuesService) GetMilestone(owner string, repo string, number int) (*Mi
|
|||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#create-a-milestone
|
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#create-a-milestone
|
||||||
func (s *IssuesService) CreateMilestone(owner string, repo string, milestone *Milestone) (*Milestone, *Response, error) {
|
func (s *IssuesService) CreateMilestone(owner string, repo string, milestone *Milestone) (*Milestone, *Response, error) {
|
||||||
u := fmt.Sprintf("/repos/%v/%v/milestones", owner, repo)
|
u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo)
|
||||||
req, err := s.client.NewRequest("POST", u, milestone)
|
req, err := s.client.NewRequest("POST", u, milestone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
@@ -52,7 +52,7 @@ type ListMembersOptions struct {
|
|||||||
// 2fa_disabled, all. Default is "all".
|
// 2fa_disabled, all. Default is "all".
|
||||||
Filter string `url:"filter,omitempty"`
|
Filter string `url:"filter,omitempty"`
|
||||||
|
|
||||||
// Role filters memebers returned by their role in the organization.
|
// Role filters members returned by their role in the organization.
|
||||||
// Possible values are:
|
// Possible values are:
|
||||||
// all - all members of the organization, regardless of role
|
// all - all members of the organization, regardless of role
|
||||||
// admin - organization owners
|
// admin - organization owners
|
||||||
@@ -172,7 +172,7 @@ func (s *OrganizationsService) ConcealMembership(org, user string) (*Response, e
|
|||||||
// ListOrgMembershipsOptions specifies optional parameters to the
|
// ListOrgMembershipsOptions specifies optional parameters to the
|
||||||
// OrganizationsService.ListOrgMemberships method.
|
// OrganizationsService.ListOrgMemberships method.
|
||||||
type ListOrgMembershipsOptions struct {
|
type ListOrgMembershipsOptions struct {
|
||||||
// Filter memberships to include only those withe the specified state.
|
// Filter memberships to include only those with the specified state.
|
||||||
// Possible values are: "active", "pending".
|
// Possible values are: "active", "pending".
|
||||||
State string `url:"state,omitempty"`
|
State string `url:"state,omitempty"`
|
||||||
|
|
||||||
@@ -238,14 +238,16 @@ func (s *OrganizationsService) GetOrgMembership(user, org string) (*Membership,
|
|||||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership
|
// GitHub API docs: https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership
|
||||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#edit-your-organization-membership
|
// GitHub API docs: https://developer.github.com/v3/orgs/members/#edit-your-organization-membership
|
||||||
func (s *OrganizationsService) EditOrgMembership(user, org string, membership *Membership) (*Membership, *Response, error) {
|
func (s *OrganizationsService) EditOrgMembership(user, org string, membership *Membership) (*Membership, *Response, error) {
|
||||||
var u string
|
var u, method string
|
||||||
if user != "" {
|
if user != "" {
|
||||||
u = fmt.Sprintf("orgs/%v/memberships/%v", org, user)
|
u = fmt.Sprintf("orgs/%v/memberships/%v", org, user)
|
||||||
|
method = "PUT"
|
||||||
} else {
|
} else {
|
||||||
u = fmt.Sprintf("user/memberships/orgs/%v", org)
|
u = fmt.Sprintf("user/memberships/orgs/%v", org)
|
||||||
|
method = "PATCH"
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := s.client.NewRequest("PATCH", u, membership)
|
req, err := s.client.NewRequest(method, u, membership)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
@@ -12,14 +12,17 @@ import (
|
|||||||
|
|
||||||
// PullRequestComment represents a comment left on a pull request.
|
// PullRequestComment represents a comment left on a pull request.
|
||||||
type PullRequestComment struct {
|
type PullRequestComment struct {
|
||||||
ID *int `json:"id,omitempty"`
|
ID *int `json:"id,omitempty"`
|
||||||
Body *string `json:"body,omitempty"`
|
Body *string `json:"body,omitempty"`
|
||||||
Path *string `json:"path,omitempty"`
|
Path *string `json:"path,omitempty"`
|
||||||
Position *int `json:"position,omitempty"`
|
DiffHunk *string `json:"diff_hunk,omitempty"`
|
||||||
CommitID *string `json:"commit_id,omitempty"`
|
Position *int `json:"position,omitempty"`
|
||||||
User *User `json:"user,omitempty"`
|
OriginalPosition *int `json:"original_position,omitempty"`
|
||||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
CommitID *string `json:"commit_id,omitempty"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
OriginalCommitID *string `json:"original_commit_id,omitempty"`
|
||||||
|
User *User `json:"user,omitempty"`
|
||||||
|
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||||
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p PullRequestComment) String() string {
|
func (p PullRequestComment) String() string {
|
@@ -146,6 +146,9 @@ func (s *RepositoriesService) List(user string, opt *RepositoryListOptions) ([]R
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove custom Accept header when license support fully launches
|
||||||
|
req.Header.Set("Accept", mediaTypeLicensesPreview)
|
||||||
|
|
||||||
repos := new([]Repository)
|
repos := new([]Repository)
|
||||||
resp, err := s.client.Do(req, repos)
|
resp, err := s.client.Do(req, repos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -180,6 +183,9 @@ func (s *RepositoriesService) ListByOrg(org string, opt *RepositoryListByOrgOpti
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove custom Accept header when license support fully launches
|
||||||
|
req.Header.Set("Accept", mediaTypeLicensesPreview)
|
||||||
|
|
||||||
repos := new([]Repository)
|
repos := new([]Repository)
|
||||||
resp, err := s.client.Do(req, repos)
|
resp, err := s.client.Do(req, repos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -442,8 +448,27 @@ func (s *RepositoriesService) ListTags(owner string, repo string, opt *ListOptio
|
|||||||
|
|
||||||
// Branch represents a repository branch
|
// Branch represents a repository branch
|
||||||
type Branch struct {
|
type Branch struct {
|
||||||
Name *string `json:"name,omitempty"`
|
Name *string `json:"name,omitempty"`
|
||||||
Commit *Commit `json:"commit,omitempty"`
|
Commit *Commit `json:"commit,omitempty"`
|
||||||
|
Protection *Protection `json:"protection,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protection represents a repository branch's protection
|
||||||
|
type Protection struct {
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequiredStatusChecks represents the protection status of a individual branch
|
||||||
|
type RequiredStatusChecks struct {
|
||||||
|
// Who required status checks apply to.
|
||||||
|
// Possible values are:
|
||||||
|
// off
|
||||||
|
// non_admins
|
||||||
|
// everyone
|
||||||
|
EnforcementLevel *string `json:"enforcement_level,omitempty"`
|
||||||
|
// The list of status checks which are required
|
||||||
|
Contexts *[]string `json:"contexts,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListBranches lists branches for the specified repository.
|
// ListBranches lists branches for the specified repository.
|
||||||
@@ -480,6 +505,29 @@ func (s *RepositoriesService) GetBranch(owner, repo, branch string) (*Branch, *R
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
|
||||||
|
|
||||||
|
b := new(Branch)
|
||||||
|
resp, err := s.client.Do(req, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditBranch edits the branch (currently only Branch Protection)
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/repos/#enabling-and-disabling-branch-protection
|
||||||
|
func (s *RepositoriesService) EditBranch(owner, repo, branchName string, branch *Branch) (*Branch, *Response, error) {
|
||||||
|
u := fmt.Sprintf("repos/%v/%v/branches/%v", owner, repo, branchName)
|
||||||
|
req, err := s.client.NewRequest("PATCH", u, branch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
|
||||||
|
|
||||||
b := new(Branch)
|
b := new(Branch)
|
||||||
resp, err := s.client.Do(req, b)
|
resp, err := s.client.Do(req, b)
|
||||||
if err != nil {
|
if err != nil {
|
@@ -70,6 +70,7 @@ type Hook struct {
|
|||||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
Name *string `json:"name,omitempty"`
|
Name *string `json:"name,omitempty"`
|
||||||
|
URL *string `json:"url,omitempty"`
|
||||||
Events []string `json:"events,omitempty"`
|
Events []string `json:"events,omitempty"`
|
||||||
Active *bool `json:"active,omitempty"`
|
Active *bool `json:"active,omitempty"`
|
||||||
Config map[string]interface{} `json:"config,omitempty"`
|
Config map[string]interface{} `json:"config,omitempty"`
|
@@ -10,7 +10,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
@@ -213,9 +212,9 @@ func (s *RepositoriesService) GetReleaseAsset(owner, repo string, id int) (*Rele
|
|||||||
return asset, resp, err
|
return asset, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DowloadReleaseAsset downloads a release asset.
|
// DownloadReleaseAsset downloads a release asset.
|
||||||
//
|
//
|
||||||
// DowloadReleaseAsset returns an io.ReadCloser that reads the contents of the
|
// DownloadReleaseAsset returns an io.ReadCloser that reads the contents of the
|
||||||
// specified release asset. It is the caller's responsibility to close the ReadCloser.
|
// specified release asset. It is the caller's responsibility to close the ReadCloser.
|
||||||
//
|
//
|
||||||
// GitHub API docs : http://developer.github.com/v3/repos/releases/#get-a-single-release-asset
|
// GitHub API docs : http://developer.github.com/v3/repos/releases/#get-a-single-release-asset
|
||||||
@@ -228,32 +227,7 @@ func (s *RepositoriesService) DownloadReleaseAsset(owner, repo string, id int) (
|
|||||||
}
|
}
|
||||||
req.Header.Set("Accept", defaultMediaType)
|
req.Header.Set("Accept", defaultMediaType)
|
||||||
|
|
||||||
var resp *http.Response
|
resp, err := s.client.client.Do(req)
|
||||||
if s.client.client.Transport == nil {
|
|
||||||
resp, err = http.DefaultTransport.RoundTrip(req)
|
|
||||||
} else {
|
|
||||||
resp, err = s.client.client.Transport.RoundTrip(req)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GitHub API streamed the asset directly
|
|
||||||
if resp.StatusCode == http.StatusOK {
|
|
||||||
return resp.Body, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusFound {
|
|
||||||
return nil, fmt.Errorf("Expected status code 200 or 302, got %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GitHub API redirected to pre-signed S3 URL
|
|
||||||
downloadURL, err := resp.Location()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err = http.Get(downloadURL.String())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
@@ -113,7 +113,7 @@ func (s *UsersService) Edit(user *User) (*User, *Response, error) {
|
|||||||
return uResp, resp, err
|
return uResp, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserListOptions specifies optional parameters to the UsersService.List
|
// UserListOptions specifies optional parameters to the UsersService.ListAll
|
||||||
// method.
|
// method.
|
||||||
type UserListOptions struct {
|
type UserListOptions struct {
|
||||||
// ID of the last user seen
|
// ID of the last user seen
|
2
Godeps/_workspace/src/github.com/onsi/ginkgo/config/config.go
generated
vendored
2
Godeps/_workspace/src/github.com/onsi/ginkgo/config/config.go
generated
vendored
@@ -79,7 +79,7 @@ func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
flagSet.BoolVar(&(DefaultReporterConfig.NoColor), prefix+"noColor", false, "If set, suppress color output in default reporter.")
|
flagSet.BoolVar(&(DefaultReporterConfig.NoColor), prefix+"noColor", false, "If set, suppress color output in default reporter.")
|
||||||
flagSet.Float64Var(&(DefaultReporterConfig.SlowSpecThreshold), prefix+"slowSpecThreshold", 5.0, "(in seconds) Specs that take longer to run than this threshold are flagged as slow by the default reporter (default: 5 seconds).")
|
flagSet.Float64Var(&(DefaultReporterConfig.SlowSpecThreshold), prefix+"slowSpecThreshold", 5.0, "(in seconds) Specs that take longer to run than this threshold are flagged as slow by the default reporter.")
|
||||||
flagSet.BoolVar(&(DefaultReporterConfig.NoisyPendings), prefix+"noisyPendings", true, "If set, default reporter will shout about pending tests.")
|
flagSet.BoolVar(&(DefaultReporterConfig.NoisyPendings), prefix+"noisyPendings", true, "If set, default reporter will shout about pending tests.")
|
||||||
flagSet.BoolVar(&(DefaultReporterConfig.Verbose), prefix+"v", false, "If set, default reporter print out all specs as they begin.")
|
flagSet.BoolVar(&(DefaultReporterConfig.Verbose), prefix+"v", false, "If set, default reporter print out all specs as they begin.")
|
||||||
flagSet.BoolVar(&(DefaultReporterConfig.Succinct), prefix+"succinct", false, "If set, default reporter prints out a very succinct report")
|
flagSet.BoolVar(&(DefaultReporterConfig.Succinct), prefix+"succinct", false, "If set, default reporter prints out a very succinct report")
|
||||||
|
2
Godeps/_workspace/src/github.com/onsi/ginkgo/ginkgo/nodot_command.go
generated
vendored
2
Godeps/_workspace/src/github.com/onsi/ginkgo/ginkgo/nodot_command.go
generated
vendored
@@ -63,6 +63,8 @@ func findSuiteFile() (string, os.FileMode) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
complainAndQuit("Could not find suite file for nodot: " + err.Error())
|
complainAndQuit("Could not find suite file for nodot: " + err.Error())
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
if re.MatchReader(bufio.NewReader(f)) {
|
if re.MatchReader(bufio.NewReader(f)) {
|
||||||
return path, file.Mode()
|
return path, file.Mode()
|
||||||
}
|
}
|
||||||
|
10
Godeps/_workspace/src/github.com/onsi/ginkgo/ginkgo/testsuite/test_suite.go
generated
vendored
10
Godeps/_workspace/src/github.com/onsi/ginkgo/ginkgo/testsuite/test_suite.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -47,6 +48,15 @@ func PrecompiledTestSuite(path string) (TestSuite, error) {
|
|||||||
|
|
||||||
func SuitesInDir(dir string, recurse bool) []TestSuite {
|
func SuitesInDir(dir string, recurse bool) []TestSuite {
|
||||||
suites := []TestSuite{}
|
suites := []TestSuite{}
|
||||||
|
|
||||||
|
// "This change will only be enabled if the go command is run with
|
||||||
|
// GO15VENDOREXPERIMENT=1 in its environment."
|
||||||
|
// c.f. the vendor-experiment proposal https://goo.gl/2ucMeC
|
||||||
|
vendorExperiment := os.Getenv("GO15VENDOREXPERIMENT")
|
||||||
|
if (vendorExperiment == "1") && path.Base(dir) == "vendor" {
|
||||||
|
return suites
|
||||||
|
}
|
||||||
|
|
||||||
files, _ := ioutil.ReadDir(dir)
|
files, _ := ioutil.ReadDir(dir)
|
||||||
re := regexp.MustCompile(`_test\.go$`)
|
re := regexp.MustCompile(`_test\.go$`)
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
|
2
Godeps/_workspace/src/github.com/onsi/ginkgo/ginkgo/unfocus_command.go
generated
vendored
2
Godeps/_workspace/src/github.com/onsi/ginkgo/ginkgo/unfocus_command.go
generated
vendored
@@ -24,6 +24,8 @@ func unfocusSpecs([]string, []string) {
|
|||||||
unfocus("Context")
|
unfocus("Context")
|
||||||
unfocus("It")
|
unfocus("It")
|
||||||
unfocus("Measure")
|
unfocus("Measure")
|
||||||
|
unfocus("DescribeTable")
|
||||||
|
unfocus("Entry")
|
||||||
}
|
}
|
||||||
|
|
||||||
func unfocus(component string) {
|
func unfocus(component string) {
|
||||||
|
8
Godeps/_workspace/src/github.com/onsi/ginkgo/internal/leafnodes/runner.go
generated
vendored
8
Godeps/_workspace/src/github.com/onsi/ginkgo/internal/leafnodes/runner.go
generated
vendored
@@ -68,7 +68,7 @@ func (r *runner) runAsync() (outcome types.SpecState, failure types.SpecFailure)
|
|||||||
done := make(chan interface{}, 1)
|
done := make(chan interface{}, 1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
finished := false
|
finished := false
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil || !finished {
|
if e := recover(); e != nil || !finished {
|
||||||
@@ -83,7 +83,7 @@ func (r *runner) runAsync() (outcome types.SpecState, failure types.SpecFailure)
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
r.asyncFunc(done)
|
r.asyncFunc(done)
|
||||||
finished = true
|
finished = true
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -96,7 +96,7 @@ func (r *runner) runAsync() (outcome types.SpecState, failure types.SpecFailure)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (r *runner) runSync() (outcome types.SpecState, failure types.SpecFailure) {
|
func (r *runner) runSync() (outcome types.SpecState, failure types.SpecFailure) {
|
||||||
finished := false
|
finished := false
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil || !finished {
|
if e := recover(); e != nil || !finished {
|
||||||
@@ -107,7 +107,7 @@ func (r *runner) runSync() (outcome types.SpecState, failure types.SpecFailure)
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
r.syncFunc()
|
r.syncFunc()
|
||||||
finished = true
|
finished = true
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
19
Godeps/_workspace/src/github.com/onsi/ginkgo/reporters/stenographer/stenographer.go
generated
vendored
19
Godeps/_workspace/src/github.com/onsi/ginkgo/reporters/stenographer/stenographer.go
generated
vendored
@@ -8,6 +8,7 @@ package stenographer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/onsi/ginkgo/types"
|
"github.com/onsi/ginkgo/types"
|
||||||
@@ -59,14 +60,20 @@ type Stenographer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func New(color bool) Stenographer {
|
func New(color bool) Stenographer {
|
||||||
|
denoter := "•"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
denoter = "+"
|
||||||
|
}
|
||||||
return &consoleStenographer{
|
return &consoleStenographer{
|
||||||
color: color,
|
color: color,
|
||||||
|
denoter: denoter,
|
||||||
cursorState: cursorStateTop,
|
cursorState: cursorStateTop,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type consoleStenographer struct {
|
type consoleStenographer struct {
|
||||||
color bool
|
color bool
|
||||||
|
denoter string
|
||||||
cursorState cursorStateType
|
cursorState cursorStateType
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,13 +223,13 @@ func (s *consoleStenographer) AnnounceCapturedOutput(output string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *consoleStenographer) AnnounceSuccesfulSpec(spec *types.SpecSummary) {
|
func (s *consoleStenographer) AnnounceSuccesfulSpec(spec *types.SpecSummary) {
|
||||||
s.print(0, s.colorize(greenColor, "•"))
|
s.print(0, s.colorize(greenColor, s.denoter))
|
||||||
s.stream()
|
s.stream()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consoleStenographer) AnnounceSuccesfulSlowSpec(spec *types.SpecSummary, succinct bool) {
|
func (s *consoleStenographer) AnnounceSuccesfulSlowSpec(spec *types.SpecSummary, succinct bool) {
|
||||||
s.printBlockWithMessage(
|
s.printBlockWithMessage(
|
||||||
s.colorize(greenColor, "• [SLOW TEST:%.3f seconds]", spec.RunTime.Seconds()),
|
s.colorize(greenColor, "%s [SLOW TEST:%.3f seconds]", s.denoter, spec.RunTime.Seconds()),
|
||||||
"",
|
"",
|
||||||
spec,
|
spec,
|
||||||
succinct,
|
succinct,
|
||||||
@@ -231,7 +238,7 @@ func (s *consoleStenographer) AnnounceSuccesfulSlowSpec(spec *types.SpecSummary,
|
|||||||
|
|
||||||
func (s *consoleStenographer) AnnounceSuccesfulMeasurement(spec *types.SpecSummary, succinct bool) {
|
func (s *consoleStenographer) AnnounceSuccesfulMeasurement(spec *types.SpecSummary, succinct bool) {
|
||||||
s.printBlockWithMessage(
|
s.printBlockWithMessage(
|
||||||
s.colorize(greenColor, "• [MEASUREMENT]"),
|
s.colorize(greenColor, "%s [MEASUREMENT]", s.denoter),
|
||||||
s.measurementReport(spec, succinct),
|
s.measurementReport(spec, succinct),
|
||||||
spec,
|
spec,
|
||||||
succinct,
|
succinct,
|
||||||
@@ -270,15 +277,15 @@ func (s *consoleStenographer) AnnounceSkippedSpec(spec *types.SpecSummary, succi
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *consoleStenographer) AnnounceSpecTimedOut(spec *types.SpecSummary, succinct bool, fullTrace bool) {
|
func (s *consoleStenographer) AnnounceSpecTimedOut(spec *types.SpecSummary, succinct bool, fullTrace bool) {
|
||||||
s.printSpecFailure("•... Timeout", spec, succinct, fullTrace)
|
s.printSpecFailure(fmt.Sprintf("%s... Timeout", s.denoter), spec, succinct, fullTrace)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consoleStenographer) AnnounceSpecPanicked(spec *types.SpecSummary, succinct bool, fullTrace bool) {
|
func (s *consoleStenographer) AnnounceSpecPanicked(spec *types.SpecSummary, succinct bool, fullTrace bool) {
|
||||||
s.printSpecFailure("•! Panic", spec, succinct, fullTrace)
|
s.printSpecFailure(fmt.Sprintf("%s! Panic", s.denoter), spec, succinct, fullTrace)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consoleStenographer) AnnounceSpecFailed(spec *types.SpecSummary, succinct bool, fullTrace bool) {
|
func (s *consoleStenographer) AnnounceSpecFailed(spec *types.SpecSummary, succinct bool, fullTrace bool) {
|
||||||
s.printSpecFailure("• Failure", spec, succinct, fullTrace)
|
s.printSpecFailure(fmt.Sprintf("%s Failure", s.denoter), spec, succinct, fullTrace)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consoleStenographer) SummarizeFailures(summaries []*types.SpecSummary) {
|
func (s *consoleStenographer) SummarizeFailures(summaries []*types.SpecSummary) {
|
||||||
|
2
Godeps/_workspace/src/github.com/onsi/gomega/.gitignore
generated
vendored
2
Godeps/_workspace/src/github.com/onsi/gomega/.gitignore
generated
vendored
@@ -1,3 +1,5 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
*.test
|
*.test
|
||||||
.
|
.
|
||||||
|
.idea
|
||||||
|
gomega.iml
|
||||||
|
11
Godeps/_workspace/src/github.com/onsi/gomega/matchers/have_occurred_matcher.go
generated
vendored
11
Godeps/_workspace/src/github.com/onsi/gomega/matchers/have_occurred_matcher.go
generated
vendored
@@ -10,15 +10,18 @@ type HaveOccurredMatcher struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (matcher *HaveOccurredMatcher) Match(actual interface{}) (success bool, err error) {
|
func (matcher *HaveOccurredMatcher) Match(actual interface{}) (success bool, err error) {
|
||||||
if isNil(actual) {
|
// is purely nil?
|
||||||
|
if actual == nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if isError(actual) {
|
// must be an 'error' type
|
||||||
return true, nil
|
if !isError(actual) {
|
||||||
|
return false, fmt.Errorf("Expected an error-type. Got:\n%s", format.Object(actual, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, fmt.Errorf("Expected an error. Got:\n%s", format.Object(actual, 1))
|
// must be non-nil (or a pointer to a non-nil)
|
||||||
|
return !isNil(actual), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (matcher *HaveOccurredMatcher) FailureMessage(actual interface{}) (message string) {
|
func (matcher *HaveOccurredMatcher) FailureMessage(actual interface{}) (message string) {
|
||||||
|
2
Godeps/_workspace/src/github.com/onsi/gomega/matchers/have_suffix_matcher.go
generated
vendored
2
Godeps/_workspace/src/github.com/onsi/gomega/matchers/have_suffix_matcher.go
generated
vendored
@@ -16,7 +16,7 @@ func (matcher *HaveSuffixMatcher) Match(actual interface{}) (success bool, err e
|
|||||||
return false, fmt.Errorf("HaveSuffix matcher requires a string or stringer. Got:\n%s", format.Object(actual, 1))
|
return false, fmt.Errorf("HaveSuffix matcher requires a string or stringer. Got:\n%s", format.Object(actual, 1))
|
||||||
}
|
}
|
||||||
suffix := matcher.suffix()
|
suffix := matcher.suffix()
|
||||||
return len(actualString) >= len(suffix) && actualString[len(actualString) - len(suffix):] == suffix, nil
|
return len(actualString) >= len(suffix) && actualString[len(actualString)-len(suffix):] == suffix, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (matcher *HaveSuffixMatcher) suffix() string {
|
func (matcher *HaveSuffixMatcher) suffix() string {
|
||||||
|
9
Godeps/_workspace/src/github.com/onsi/gomega/matchers/succeed_matcher.go
generated
vendored
9
Godeps/_workspace/src/github.com/onsi/gomega/matchers/succeed_matcher.go
generated
vendored
@@ -10,15 +10,18 @@ type SucceedMatcher struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (matcher *SucceedMatcher) Match(actual interface{}) (success bool, err error) {
|
func (matcher *SucceedMatcher) Match(actual interface{}) (success bool, err error) {
|
||||||
|
// is purely nil?
|
||||||
if actual == nil {
|
if actual == nil {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if isError(actual) {
|
// must be an 'error' type
|
||||||
return false, nil
|
if !isError(actual) {
|
||||||
|
return false, fmt.Errorf("Expected an error-type. Got:\n%s", format.Object(actual, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, fmt.Errorf("Expected an error-type. Got:\n%s", format.Object(actual, 1))
|
// must be nil (or a pointer to a nil)
|
||||||
|
return isNil(actual), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (matcher *SucceedMatcher) FailureMessage(actual interface{}) (message string) {
|
func (matcher *SucceedMatcher) FailureMessage(actual interface{}) (message string) {
|
||||||
|
4
Godeps/_workspace/src/github.com/onsi/gomega/matchers/support/goraph/util/util.go
generated
vendored
4
Godeps/_workspace/src/github.com/onsi/gomega/matchers/support/goraph/util/util.go
generated
vendored
@@ -3,5 +3,5 @@ package util
|
|||||||
import "math"
|
import "math"
|
||||||
|
|
||||||
func Odd(n int) bool {
|
func Odd(n int) bool {
|
||||||
return math.Mod(float64(n), 2.0) == 1.0
|
return math.Mod(float64(n), 2.0) == 1.0
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2009 The goauth2 Authors. All rights reserved.
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
@@ -1,7 +1,7 @@
|
|||||||
Additional IP Rights Grant (Patents)
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
"This implementation" means the copyrightable works distributed by
|
||||||
Google as part of the goauth2 project.
|
Google as part of the Go project.
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
447
Godeps/_workspace/src/golang.org/x/net/context/context.go
generated
vendored
Normal file
447
Godeps/_workspace/src/golang.org/x/net/context/context.go
generated
vendored
Normal file
@@ -0,0 +1,447 @@
|
|||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package context defines the Context type, which carries deadlines,
|
||||||
|
// cancelation signals, and other request-scoped values across API boundaries
|
||||||
|
// and between processes.
|
||||||
|
//
|
||||||
|
// Incoming requests to a server should create a Context, and outgoing calls to
|
||||||
|
// servers should accept a Context. The chain of function calls between must
|
||||||
|
// propagate the Context, optionally replacing it with a modified copy created
|
||||||
|
// using WithDeadline, WithTimeout, WithCancel, or WithValue.
|
||||||
|
//
|
||||||
|
// Programs that use Contexts should follow these rules to keep interfaces
|
||||||
|
// consistent across packages and enable static analysis tools to check context
|
||||||
|
// propagation:
|
||||||
|
//
|
||||||
|
// Do not store Contexts inside a struct type; instead, pass a Context
|
||||||
|
// explicitly to each function that needs it. The Context should be the first
|
||||||
|
// parameter, typically named ctx:
|
||||||
|
//
|
||||||
|
// func DoSomething(ctx context.Context, arg Arg) error {
|
||||||
|
// // ... use ctx ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
||||||
|
// if you are unsure about which Context to use.
|
||||||
|
//
|
||||||
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
// APIs, not for passing optional parameters to functions.
|
||||||
|
//
|
||||||
|
// The same Context may be passed to functions running in different goroutines;
|
||||||
|
// Contexts are safe for simultaneous use by multiple goroutines.
|
||||||
|
//
|
||||||
|
// See http://blog.golang.org/context for example code for a server that uses
|
||||||
|
// Contexts.
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Context carries a deadline, a cancelation signal, and other values across
|
||||||
|
// API boundaries.
|
||||||
|
//
|
||||||
|
// Context's methods may be called by multiple goroutines simultaneously.
|
||||||
|
type Context interface {
|
||||||
|
// Deadline returns the time when work done on behalf of this context
|
||||||
|
// should be canceled. Deadline returns ok==false when no deadline is
|
||||||
|
// set. Successive calls to Deadline return the same results.
|
||||||
|
Deadline() (deadline time.Time, ok bool)
|
||||||
|
|
||||||
|
// Done returns a channel that's closed when work done on behalf of this
|
||||||
|
// context should be canceled. Done may return nil if this context can
|
||||||
|
// never be canceled. Successive calls to Done return the same value.
|
||||||
|
//
|
||||||
|
// WithCancel arranges for Done to be closed when cancel is called;
|
||||||
|
// WithDeadline arranges for Done to be closed when the deadline
|
||||||
|
// expires; WithTimeout arranges for Done to be closed when the timeout
|
||||||
|
// elapses.
|
||||||
|
//
|
||||||
|
// Done is provided for use in select statements:
|
||||||
|
//
|
||||||
|
// // Stream generates values with DoSomething and sends them to out
|
||||||
|
// // until DoSomething returns an error or ctx.Done is closed.
|
||||||
|
// func Stream(ctx context.Context, out <-chan Value) error {
|
||||||
|
// for {
|
||||||
|
// v, err := DoSomething(ctx)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// select {
|
||||||
|
// case <-ctx.Done():
|
||||||
|
// return ctx.Err()
|
||||||
|
// case out <- v:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// See http://blog.golang.org/pipelines for more examples of how to use
|
||||||
|
// a Done channel for cancelation.
|
||||||
|
Done() <-chan struct{}
|
||||||
|
|
||||||
|
// Err returns a non-nil error value after Done is closed. Err returns
|
||||||
|
// Canceled if the context was canceled or DeadlineExceeded if the
|
||||||
|
// context's deadline passed. No other values for Err are defined.
|
||||||
|
// After Done is closed, successive calls to Err return the same value.
|
||||||
|
Err() error
|
||||||
|
|
||||||
|
// Value returns the value associated with this context for key, or nil
|
||||||
|
// if no value is associated with key. Successive calls to Value with
|
||||||
|
// the same key returns the same result.
|
||||||
|
//
|
||||||
|
// Use context values only for request-scoped data that transits
|
||||||
|
// processes and API boundaries, not for passing optional parameters to
|
||||||
|
// functions.
|
||||||
|
//
|
||||||
|
// A key identifies a specific value in a Context. Functions that wish
|
||||||
|
// to store values in Context typically allocate a key in a global
|
||||||
|
// variable then use that key as the argument to context.WithValue and
|
||||||
|
// Context.Value. A key can be any type that supports equality;
|
||||||
|
// packages should define keys as an unexported type to avoid
|
||||||
|
// collisions.
|
||||||
|
//
|
||||||
|
// Packages that define a Context key should provide type-safe accessors
|
||||||
|
// for the values stores using that key:
|
||||||
|
//
|
||||||
|
// // Package user defines a User type that's stored in Contexts.
|
||||||
|
// package user
|
||||||
|
//
|
||||||
|
// import "golang.org/x/net/context"
|
||||||
|
//
|
||||||
|
// // User is the type of value stored in the Contexts.
|
||||||
|
// type User struct {...}
|
||||||
|
//
|
||||||
|
// // key is an unexported type for keys defined in this package.
|
||||||
|
// // This prevents collisions with keys defined in other packages.
|
||||||
|
// type key int
|
||||||
|
//
|
||||||
|
// // userKey is the key for user.User values in Contexts. It is
|
||||||
|
// // unexported; clients use user.NewContext and user.FromContext
|
||||||
|
// // instead of using this key directly.
|
||||||
|
// var userKey key = 0
|
||||||
|
//
|
||||||
|
// // NewContext returns a new Context that carries value u.
|
||||||
|
// func NewContext(ctx context.Context, u *User) context.Context {
|
||||||
|
// return context.WithValue(ctx, userKey, u)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // FromContext returns the User value stored in ctx, if any.
|
||||||
|
// func FromContext(ctx context.Context) (*User, bool) {
|
||||||
|
// u, ok := ctx.Value(userKey).(*User)
|
||||||
|
// return u, ok
|
||||||
|
// }
|
||||||
|
Value(key interface{}) interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Canceled is the error returned by Context.Err when the context is canceled.
|
||||||
|
var Canceled = errors.New("context canceled")
|
||||||
|
|
||||||
|
// DeadlineExceeded is the error returned by Context.Err when the context's
|
||||||
|
// deadline passes.
|
||||||
|
var DeadlineExceeded = errors.New("context deadline exceeded")
|
||||||
|
|
||||||
|
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||||
|
// struct{}, since vars of this type must have distinct addresses.
|
||||||
|
type emptyCtx int
|
||||||
|
|
||||||
|
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Done() <-chan struct{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Err() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Value(key interface{}) interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *emptyCtx) String() string {
|
||||||
|
switch e {
|
||||||
|
case background:
|
||||||
|
return "context.Background"
|
||||||
|
case todo:
|
||||||
|
return "context.TODO"
|
||||||
|
}
|
||||||
|
return "unknown empty Context"
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
background = new(emptyCtx)
|
||||||
|
todo = new(emptyCtx)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Background returns a non-nil, empty Context. It is never canceled, has no
|
||||||
|
// values, and has no deadline. It is typically used by the main function,
|
||||||
|
// initialization, and tests, and as the top-level Context for incoming
|
||||||
|
// requests.
|
||||||
|
func Background() Context {
|
||||||
|
return background
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
||||||
|
// it's unclear which Context to use or it is not yet available (because the
|
||||||
|
// surrounding function has not yet been extended to accept a Context
|
||||||
|
// parameter). TODO is recognized by static analysis tools that determine
|
||||||
|
// whether Contexts are propagated correctly in a program.
|
||||||
|
func TODO() Context {
|
||||||
|
return todo
|
||||||
|
}
|
||||||
|
|
||||||
|
// A CancelFunc tells an operation to abandon its work.
|
||||||
|
// A CancelFunc does not wait for the work to stop.
|
||||||
|
// After the first call, subsequent calls to a CancelFunc do nothing.
|
||||||
|
type CancelFunc func()
|
||||||
|
|
||||||
|
// WithCancel returns a copy of parent with a new Done channel. The returned
|
||||||
|
// context's Done channel is closed when the returned cancel function is called
|
||||||
|
// or when the parent context's Done channel is closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
||||||
|
c := newCancelCtx(parent)
|
||||||
|
propagateCancel(parent, &c)
|
||||||
|
return &c, func() { c.cancel(true, Canceled) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// newCancelCtx returns an initialized cancelCtx.
|
||||||
|
func newCancelCtx(parent Context) cancelCtx {
|
||||||
|
return cancelCtx{
|
||||||
|
Context: parent,
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// propagateCancel arranges for child to be canceled when parent is.
|
||||||
|
func propagateCancel(parent Context, child canceler) {
|
||||||
|
if parent.Done() == nil {
|
||||||
|
return // parent is never canceled
|
||||||
|
}
|
||||||
|
if p, ok := parentCancelCtx(parent); ok {
|
||||||
|
p.mu.Lock()
|
||||||
|
if p.err != nil {
|
||||||
|
// parent has already been canceled
|
||||||
|
child.cancel(false, p.err)
|
||||||
|
} else {
|
||||||
|
if p.children == nil {
|
||||||
|
p.children = make(map[canceler]bool)
|
||||||
|
}
|
||||||
|
p.children[child] = true
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
} else {
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-parent.Done():
|
||||||
|
child.cancel(false, parent.Err())
|
||||||
|
case <-child.Done():
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parentCancelCtx follows a chain of parent references until it finds a
|
||||||
|
// *cancelCtx. This function understands how each of the concrete types in this
|
||||||
|
// package represents its parent.
|
||||||
|
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
||||||
|
for {
|
||||||
|
switch c := parent.(type) {
|
||||||
|
case *cancelCtx:
|
||||||
|
return c, true
|
||||||
|
case *timerCtx:
|
||||||
|
return &c.cancelCtx, true
|
||||||
|
case *valueCtx:
|
||||||
|
parent = c.Context
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeChild removes a context from its parent.
|
||||||
|
func removeChild(parent Context, child canceler) {
|
||||||
|
p, ok := parentCancelCtx(parent)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.mu.Lock()
|
||||||
|
if p.children != nil {
|
||||||
|
delete(p.children, child)
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A canceler is a context type that can be canceled directly. The
|
||||||
|
// implementations are *cancelCtx and *timerCtx.
|
||||||
|
type canceler interface {
|
||||||
|
cancel(removeFromParent bool, err error)
|
||||||
|
Done() <-chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
||||||
|
// that implement canceler.
|
||||||
|
type cancelCtx struct {
|
||||||
|
Context
|
||||||
|
|
||||||
|
done chan struct{} // closed by the first cancel call.
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
children map[canceler]bool // set to nil by the first cancel call
|
||||||
|
err error // set to non-nil by the first cancel call
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cancelCtx) Done() <-chan struct{} {
|
||||||
|
return c.done
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cancelCtx) Err() error {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
return c.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cancelCtx) String() string {
|
||||||
|
return fmt.Sprintf("%v.WithCancel", c.Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancel closes c.done, cancels each of c's children, and, if
|
||||||
|
// removeFromParent is true, removes c from its parent's children.
|
||||||
|
func (c *cancelCtx) cancel(removeFromParent bool, err error) {
|
||||||
|
if err == nil {
|
||||||
|
panic("context: internal error: missing cancel error")
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.err != nil {
|
||||||
|
c.mu.Unlock()
|
||||||
|
return // already canceled
|
||||||
|
}
|
||||||
|
c.err = err
|
||||||
|
close(c.done)
|
||||||
|
for child := range c.children {
|
||||||
|
// NOTE: acquiring the child's lock while holding parent's lock.
|
||||||
|
child.cancel(false, err)
|
||||||
|
}
|
||||||
|
c.children = nil
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
if removeFromParent {
|
||||||
|
removeChild(c.Context, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||||
|
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||||
|
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||||
|
// context's Done channel is closed when the deadline expires, when the returned
|
||||||
|
// cancel function is called, or when the parent context's Done channel is
|
||||||
|
// closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||||
|
if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
|
||||||
|
// The current deadline is already sooner than the new one.
|
||||||
|
return WithCancel(parent)
|
||||||
|
}
|
||||||
|
c := &timerCtx{
|
||||||
|
cancelCtx: newCancelCtx(parent),
|
||||||
|
deadline: deadline,
|
||||||
|
}
|
||||||
|
propagateCancel(parent, c)
|
||||||
|
d := deadline.Sub(time.Now())
|
||||||
|
if d <= 0 {
|
||||||
|
c.cancel(true, DeadlineExceeded) // deadline has already passed
|
||||||
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
if c.err == nil {
|
||||||
|
c.timer = time.AfterFunc(d, func() {
|
||||||
|
c.cancel(true, DeadlineExceeded)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
||||||
|
// implement Done and Err. It implements cancel by stopping its timer then
|
||||||
|
// delegating to cancelCtx.cancel.
|
||||||
|
type timerCtx struct {
|
||||||
|
cancelCtx
|
||||||
|
timer *time.Timer // Under cancelCtx.mu.
|
||||||
|
|
||||||
|
deadline time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
|
||||||
|
return c.deadline, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timerCtx) String() string {
|
||||||
|
return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timerCtx) cancel(removeFromParent bool, err error) {
|
||||||
|
c.cancelCtx.cancel(false, err)
|
||||||
|
if removeFromParent {
|
||||||
|
// Remove this timerCtx from its parent cancelCtx's children.
|
||||||
|
removeChild(c.cancelCtx.Context, c)
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.timer != nil {
|
||||||
|
c.timer.Stop()
|
||||||
|
c.timer = nil
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete:
|
||||||
|
//
|
||||||
|
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
|
||||||
|
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||||
|
// defer cancel() // releases resources if slowOperation completes before timeout elapses
|
||||||
|
// return slowOperation(ctx)
|
||||||
|
// }
|
||||||
|
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
|
||||||
|
return WithDeadline(parent, time.Now().Add(timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValue returns a copy of parent in which the value associated with key is
|
||||||
|
// val.
|
||||||
|
//
|
||||||
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
// APIs, not for passing optional parameters to functions.
|
||||||
|
func WithValue(parent Context, key interface{}, val interface{}) Context {
|
||||||
|
return &valueCtx{parent, key, val}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A valueCtx carries a key-value pair. It implements Value for that key and
|
||||||
|
// delegates all other calls to the embedded Context.
|
||||||
|
type valueCtx struct {
|
||||||
|
Context
|
||||||
|
key, val interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *valueCtx) String() string {
|
||||||
|
return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *valueCtx) Value(key interface{}) interface{} {
|
||||||
|
if c.key == key {
|
||||||
|
return c.val
|
||||||
|
}
|
||||||
|
return c.Context.Value(key)
|
||||||
|
}
|
19
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq.go
generated
vendored
Normal file
19
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
|
package ctxhttp
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func canceler(client *http.Client, req *http.Request) func() {
|
||||||
|
// TODO(djd): Respect any existing value of req.Cancel.
|
||||||
|
ch := make(chan struct{})
|
||||||
|
req.Cancel = ch
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
close(ch)
|
||||||
|
}
|
||||||
|
}
|
23
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq_go14.go
generated
vendored
Normal file
23
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq_go14.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
package ctxhttp
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
type requestCanceler interface {
|
||||||
|
CancelRequest(*http.Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func canceler(client *http.Client, req *http.Request) func() {
|
||||||
|
rc, ok := client.Transport.(requestCanceler)
|
||||||
|
if !ok {
|
||||||
|
return func() {}
|
||||||
|
}
|
||||||
|
return func() {
|
||||||
|
rc.CancelRequest(req)
|
||||||
|
}
|
||||||
|
}
|
140
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp.go
generated
vendored
Normal file
140
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp.go
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
|
||||||
|
package ctxhttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func nop() {}
|
||||||
|
|
||||||
|
var (
|
||||||
|
testHookContextDoneBeforeHeaders = nop
|
||||||
|
testHookDoReturned = nop
|
||||||
|
testHookDidBodyClose = nop
|
||||||
|
)
|
||||||
|
|
||||||
|
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
|
||||||
|
// If the client is nil, http.DefaultClient is used.
|
||||||
|
// If the context is canceled or times out, ctx.Err() will be returned.
|
||||||
|
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
||||||
|
if client == nil {
|
||||||
|
client = http.DefaultClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request cancelation changed in Go 1.5, see cancelreq.go and cancelreq_go14.go.
|
||||||
|
cancel := canceler(client, req)
|
||||||
|
|
||||||
|
type responseAndError struct {
|
||||||
|
resp *http.Response
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
result := make(chan responseAndError, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
testHookDoReturned()
|
||||||
|
result <- responseAndError{resp, err}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var resp *http.Response
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
testHookContextDoneBeforeHeaders()
|
||||||
|
cancel()
|
||||||
|
// Clean up after the goroutine calling client.Do:
|
||||||
|
go func() {
|
||||||
|
if r := <-result; r.resp != nil {
|
||||||
|
testHookDidBodyClose()
|
||||||
|
r.resp.Body.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case r := <-result:
|
||||||
|
var err error
|
||||||
|
resp, err = r.resp, r.err
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
cancel()
|
||||||
|
case <-c:
|
||||||
|
// The response's Body is closed.
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resp.Body = ¬ifyingReader{resp.Body, c}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get issues a GET request via the Do function.
|
||||||
|
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head issues a HEAD request via the Do function.
|
||||||
|
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("HEAD", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post issues a POST request via the Do function.
|
||||||
|
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("POST", url, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", bodyType)
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostForm issues a POST request via the Do function.
|
||||||
|
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
|
||||||
|
return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// notifyingReader is an io.ReadCloser that closes the notify channel after
|
||||||
|
// Close is called or a Read fails on the underlying ReadCloser.
|
||||||
|
type notifyingReader struct {
|
||||||
|
io.ReadCloser
|
||||||
|
notify chan<- struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *notifyingReader) Read(p []byte) (int, error) {
|
||||||
|
n, err := r.ReadCloser.Read(p)
|
||||||
|
if err != nil && r.notify != nil {
|
||||||
|
close(r.notify)
|
||||||
|
r.notify = nil
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *notifyingReader) Close() error {
|
||||||
|
err := r.ReadCloser.Close()
|
||||||
|
if r.notify != nil {
|
||||||
|
close(r.notify)
|
||||||
|
r.notify = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
14
Godeps/_workspace/src/golang.org/x/oauth2/.travis.yml
generated
vendored
Normal file
14
Godeps/_workspace/src/golang.org/x/oauth2/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
|
||||||
|
install:
|
||||||
|
- export GOPATH="$HOME/gopath"
|
||||||
|
- mkdir -p "$GOPATH/src/golang.org/x"
|
||||||
|
- mv "$TRAVIS_BUILD_DIR" "$GOPATH/src/golang.org/x/oauth2"
|
||||||
|
- go get -v -t -d golang.org/x/oauth2/...
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test -v golang.org/x/oauth2/...
|
3
Godeps/_workspace/src/golang.org/x/oauth2/AUTHORS
generated
vendored
Normal file
3
Godeps/_workspace/src/golang.org/x/oauth2/AUTHORS
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# This source code refers to The Go Authors for copyright purposes.
|
||||||
|
# The master list of authors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/AUTHORS.
|
31
Godeps/_workspace/src/golang.org/x/oauth2/CONTRIBUTING.md
generated
vendored
Normal file
31
Godeps/_workspace/src/golang.org/x/oauth2/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Contributing to Go
|
||||||
|
|
||||||
|
Go is an open source project.
|
||||||
|
|
||||||
|
It is the work of hundreds of contributors. We appreciate your help!
|
||||||
|
|
||||||
|
|
||||||
|
## Filing issues
|
||||||
|
|
||||||
|
When [filing an issue](https://github.com/golang/oauth2/issues), make sure to answer these five questions:
|
||||||
|
|
||||||
|
1. What version of Go are you using (`go version`)?
|
||||||
|
2. What operating system and processor architecture are you using?
|
||||||
|
3. What did you do?
|
||||||
|
4. What did you expect to see?
|
||||||
|
5. What did you see instead?
|
||||||
|
|
||||||
|
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
|
||||||
|
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
|
||||||
|
|
||||||
|
## Contributing code
|
||||||
|
|
||||||
|
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
|
||||||
|
before sending patches.
|
||||||
|
|
||||||
|
**We do not accept GitHub pull requests**
|
||||||
|
(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
|
||||||
|
|
||||||
|
Unless otherwise noted, the Go source files are distributed under
|
||||||
|
the BSD-style license found in the LICENSE file.
|
||||||
|
|
3
Godeps/_workspace/src/golang.org/x/oauth2/CONTRIBUTORS
generated
vendored
Normal file
3
Godeps/_workspace/src/golang.org/x/oauth2/CONTRIBUTORS
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# This source code was written by the Go contributors.
|
||||||
|
# The master list of contributors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/CONTRIBUTORS.
|
27
Godeps/_workspace/src/golang.org/x/oauth2/LICENSE
generated
vendored
Normal file
27
Godeps/_workspace/src/golang.org/x/oauth2/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2009 The oauth2 Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
64
Godeps/_workspace/src/golang.org/x/oauth2/README.md
generated
vendored
Normal file
64
Godeps/_workspace/src/golang.org/x/oauth2/README.md
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# OAuth2 for Go
|
||||||
|
|
||||||
|
[](https://travis-ci.org/golang/oauth2)
|
||||||
|
|
||||||
|
oauth2 package contains a client implementation for OAuth 2.0 spec.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
~~~~
|
||||||
|
go get golang.org/x/oauth2
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
See godoc for further documentation and examples.
|
||||||
|
|
||||||
|
* [godoc.org/golang.org/x/oauth2](http://godoc.org/golang.org/x/oauth2)
|
||||||
|
* [godoc.org/golang.org/x/oauth2/google](http://godoc.org/golang.org/x/oauth2/google)
|
||||||
|
|
||||||
|
|
||||||
|
## App Engine
|
||||||
|
|
||||||
|
In change 96e89be (March 2015) we removed the `oauth2.Context2` type in favor
|
||||||
|
of the [`context.Context`](https://golang.org/x/net/context#Context) type from
|
||||||
|
the `golang.org/x/net/context` package
|
||||||
|
|
||||||
|
This means its no longer possible to use the "Classic App Engine"
|
||||||
|
`appengine.Context` type with the `oauth2` package. (You're using
|
||||||
|
Classic App Engine if you import the package `"appengine"`.)
|
||||||
|
|
||||||
|
To work around this, you may use the new `"google.golang.org/appengine"`
|
||||||
|
package. This package has almost the same API as the `"appengine"` package,
|
||||||
|
but it can be fetched with `go get` and used on "Managed VMs" and well as
|
||||||
|
Classic App Engine.
|
||||||
|
|
||||||
|
See the [new `appengine` package's readme](https://github.com/golang/appengine#updating-a-go-app-engine-app)
|
||||||
|
for information on updating your app.
|
||||||
|
|
||||||
|
If you don't want to update your entire app to use the new App Engine packages,
|
||||||
|
you may use both sets of packages in parallel, using only the new packages
|
||||||
|
with the `oauth2` package.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"golang.org/x/oauth2/google"
|
||||||
|
newappengine "google.golang.org/appengine"
|
||||||
|
newurlfetch "google.golang.org/appengine/urlfetch"
|
||||||
|
|
||||||
|
"appengine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var c appengine.Context = appengine.NewContext(r)
|
||||||
|
c.Infof("Logging a message with the old package")
|
||||||
|
|
||||||
|
var ctx context.Context = newappengine.NewContext(r)
|
||||||
|
client := &http.Client{
|
||||||
|
Transport: &oauth2.Transport{
|
||||||
|
Source: google.AppEngineTokenSource(ctx, "scope"),
|
||||||
|
Base: &newurlfetch.Transport{Context: ctx},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client.Get("...")
|
||||||
|
}
|
||||||
|
|
16
Godeps/_workspace/src/golang.org/x/oauth2/bitbucket/bitbucket.go
generated
vendored
Normal file
16
Godeps/_workspace/src/golang.org/x/oauth2/bitbucket/bitbucket.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2015 The oauth2 Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package bitbucket provides constants for using OAuth2 to access Bitbucket.
|
||||||
|
package bitbucket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Endpoint is Bitbucket's OAuth 2.0 endpoint.
|
||||||
|
var Endpoint = oauth2.Endpoint{
|
||||||
|
AuthURL: "https://bitbucket.org/site/oauth2/authorize",
|
||||||
|
TokenURL: "https://bitbucket.org/site/oauth2/access_token",
|
||||||
|
}
|
25
Godeps/_workspace/src/golang.org/x/oauth2/client_appengine.go
generated
vendored
Normal file
25
Godeps/_workspace/src/golang.org/x/oauth2/client_appengine.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build appengine
|
||||||
|
|
||||||
|
// App Engine hooks.
|
||||||
|
|
||||||
|
package oauth2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/oauth2/internal"
|
||||||
|
"google.golang.org/appengine/urlfetch"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
internal.RegisterContextClientFunc(contextClientAppEngine)
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextClientAppEngine(ctx context.Context) (*http.Client, error) {
|
||||||
|
return urlfetch.Client(ctx), nil
|
||||||
|
}
|
112
Godeps/_workspace/src/golang.org/x/oauth2/clientcredentials/clientcredentials.go
generated
vendored
Normal file
112
Godeps/_workspace/src/golang.org/x/oauth2/clientcredentials/clientcredentials.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package clientcredentials implements the OAuth2.0 "client credentials" token flow,
|
||||||
|
// also known as the "two-legged OAuth 2.0".
|
||||||
|
//
|
||||||
|
// This should be used when the client is acting on its own behalf or when the client
|
||||||
|
// is the resource owner. It may also be used when requesting access to protected
|
||||||
|
// resources based on an authorization previously arranged with the authorization
|
||||||
|
// server.
|
||||||
|
//
|
||||||
|
// See http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.4
|
||||||
|
package clientcredentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"golang.org/x/oauth2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// tokenFromInternal maps an *internal.Token struct into
|
||||||
|
// an *oauth2.Token struct.
|
||||||
|
func tokenFromInternal(t *internal.Token) *oauth2.Token {
|
||||||
|
if t == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
tk := &oauth2.Token{
|
||||||
|
AccessToken: t.AccessToken,
|
||||||
|
TokenType: t.TokenType,
|
||||||
|
RefreshToken: t.RefreshToken,
|
||||||
|
Expiry: t.Expiry,
|
||||||
|
}
|
||||||
|
return tk.WithExtra(t.Raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieveToken takes a *Config and uses that to retrieve an *internal.Token.
|
||||||
|
// This token is then mapped from *internal.Token into an *oauth2.Token which is
|
||||||
|
// returned along with an error.
|
||||||
|
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*oauth2.Token, error) {
|
||||||
|
tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.TokenURL, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tokenFromInternal(tk), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client Credentials Config describes a 2-legged OAuth2 flow, with both the
|
||||||
|
// client application information and the server's endpoint URLs.
|
||||||
|
type Config struct {
|
||||||
|
// ClientID is the application's ID.
|
||||||
|
ClientID string
|
||||||
|
|
||||||
|
// ClientSecret is the application's secret.
|
||||||
|
ClientSecret string
|
||||||
|
|
||||||
|
// TokenURL is the resource server's token endpoint
|
||||||
|
// URL. This is a constant specific to each server.
|
||||||
|
TokenURL string
|
||||||
|
|
||||||
|
// Scope specifies optional requested permissions.
|
||||||
|
Scopes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token uses client credentials to retrieve a token.
|
||||||
|
// The HTTP client to use is derived from the context.
|
||||||
|
// If nil, http.DefaultClient is used.
|
||||||
|
func (c *Config) Token(ctx context.Context) (*oauth2.Token, error) {
|
||||||
|
return retrieveToken(ctx, c, url.Values{
|
||||||
|
"grant_type": {"client_credentials"},
|
||||||
|
"scope": internal.CondVal(strings.Join(c.Scopes, " ")),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client returns an HTTP client using the provided token.
|
||||||
|
// The token will auto-refresh as necessary. The underlying
|
||||||
|
// HTTP transport will be obtained using the provided context.
|
||||||
|
// The returned client and its Transport should not be modified.
|
||||||
|
func (c *Config) Client(ctx context.Context) *http.Client {
|
||||||
|
return oauth2.NewClient(ctx, c.TokenSource(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenSource returns a TokenSource that returns t until t expires,
|
||||||
|
// automatically refreshing it as necessary using the provided context and the
|
||||||
|
// client ID and client secret.
|
||||||
|
//
|
||||||
|
// Most users will use Config.Client instead.
|
||||||
|
func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSource {
|
||||||
|
source := &tokenSource{
|
||||||
|
ctx: ctx,
|
||||||
|
conf: c,
|
||||||
|
}
|
||||||
|
return oauth2.ReuseTokenSource(nil, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenSource struct {
|
||||||
|
ctx context.Context
|
||||||
|
conf *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token refreshes the token by using a new client credentials request.
|
||||||
|
// tokens received this way do not include a refresh token
|
||||||
|
func (c *tokenSource) Token() (*oauth2.Token, error) {
|
||||||
|
return retrieveToken(c.ctx, c.conf, url.Values{
|
||||||
|
"grant_type": {"client_credentials"},
|
||||||
|
"scope": internal.CondVal(strings.Join(c.conf.Scopes, " ")),
|
||||||
|
})
|
||||||
|
}
|
16
Godeps/_workspace/src/golang.org/x/oauth2/facebook/facebook.go
generated
vendored
Normal file
16
Godeps/_workspace/src/golang.org/x/oauth2/facebook/facebook.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package facebook provides constants for using OAuth2 to access Facebook.
|
||||||
|
package facebook
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Endpoint is Facebook's OAuth 2.0 endpoint.
|
||||||
|
var Endpoint = oauth2.Endpoint{
|
||||||
|
AuthURL: "https://www.facebook.com/dialog/oauth",
|
||||||
|
TokenURL: "https://graph.facebook.com/oauth/access_token",
|
||||||
|
}
|
16
Godeps/_workspace/src/golang.org/x/oauth2/github/github.go
generated
vendored
Normal file
16
Godeps/_workspace/src/golang.org/x/oauth2/github/github.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package github provides constants for using OAuth2 to access Github.
|
||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Endpoint is Github's OAuth 2.0 endpoint.
|
||||||
|
var Endpoint = oauth2.Endpoint{
|
||||||
|
AuthURL: "https://github.com/login/oauth/authorize",
|
||||||
|
TokenURL: "https://github.com/login/oauth/access_token",
|
||||||
|
}
|
86
Godeps/_workspace/src/golang.org/x/oauth2/google/appengine.go
generated
vendored
Normal file
86
Godeps/_workspace/src/golang.org/x/oauth2/google/appengine.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set at init time by appenginevm_hook.go. If true, we are on App Engine Managed VMs.
|
||||||
|
var appengineVM bool
|
||||||
|
|
||||||
|
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
|
||||||
|
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
|
||||||
|
|
||||||
|
// AppEngineTokenSource returns a token source that fetches tokens
|
||||||
|
// issued to the current App Engine application's service account.
|
||||||
|
// If you are implementing a 3-legged OAuth 2.0 flow on App Engine
|
||||||
|
// that involves user accounts, see oauth2.Config instead.
|
||||||
|
//
|
||||||
|
// The provided context must have come from appengine.NewContext.
|
||||||
|
func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
|
||||||
|
if appengineTokenFunc == nil {
|
||||||
|
panic("google: AppEngineTokenSource can only be used on App Engine.")
|
||||||
|
}
|
||||||
|
scopes := append([]string{}, scope...)
|
||||||
|
sort.Strings(scopes)
|
||||||
|
return &appEngineTokenSource{
|
||||||
|
ctx: ctx,
|
||||||
|
scopes: scopes,
|
||||||
|
key: strings.Join(scopes, " "),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// aeTokens helps the fetched tokens to be reused until their expiration.
|
||||||
|
var (
|
||||||
|
aeTokensMu sync.Mutex
|
||||||
|
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes
|
||||||
|
)
|
||||||
|
|
||||||
|
type tokenLock struct {
|
||||||
|
mu sync.Mutex // guards t; held while fetching or updating t
|
||||||
|
t *oauth2.Token
|
||||||
|
}
|
||||||
|
|
||||||
|
type appEngineTokenSource struct {
|
||||||
|
ctx context.Context
|
||||||
|
scopes []string
|
||||||
|
key string // to aeTokens map; space-separated scopes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *appEngineTokenSource) Token() (*oauth2.Token, error) {
|
||||||
|
if appengineTokenFunc == nil {
|
||||||
|
panic("google: AppEngineTokenSource can only be used on App Engine.")
|
||||||
|
}
|
||||||
|
|
||||||
|
aeTokensMu.Lock()
|
||||||
|
tok, ok := aeTokens[ts.key]
|
||||||
|
if !ok {
|
||||||
|
tok = &tokenLock{}
|
||||||
|
aeTokens[ts.key] = tok
|
||||||
|
}
|
||||||
|
aeTokensMu.Unlock()
|
||||||
|
|
||||||
|
tok.mu.Lock()
|
||||||
|
defer tok.mu.Unlock()
|
||||||
|
if tok.t.Valid() {
|
||||||
|
return tok.t, nil
|
||||||
|
}
|
||||||
|
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tok.t = &oauth2.Token{
|
||||||
|
AccessToken: access,
|
||||||
|
Expiry: exp,
|
||||||
|
}
|
||||||
|
return tok.t, nil
|
||||||
|
}
|
13
Godeps/_workspace/src/golang.org/x/oauth2/google/appengine_hook.go
generated
vendored
Normal file
13
Godeps/_workspace/src/golang.org/x/oauth2/google/appengine_hook.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build appengine
|
||||||
|
|
||||||
|
package google
|
||||||
|
|
||||||
|
import "google.golang.org/appengine"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
appengineTokenFunc = appengine.AccessToken
|
||||||
|
}
|
14
Godeps/_workspace/src/golang.org/x/oauth2/google/appenginevm_hook.go
generated
vendored
Normal file
14
Godeps/_workspace/src/golang.org/x/oauth2/google/appenginevm_hook.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2015 The oauth2 Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build appenginevm
|
||||||
|
|
||||||
|
package google
|
||||||
|
|
||||||
|
import "google.golang.org/appengine"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
appengineVM = true
|
||||||
|
appengineTokenFunc = appengine.AccessToken
|
||||||
|
}
|
155
Godeps/_workspace/src/golang.org/x/oauth2/google/default.go
generated
vendored
Normal file
155
Godeps/_workspace/src/golang.org/x/oauth2/google/default.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"golang.org/x/oauth2/jwt"
|
||||||
|
"google.golang.org/cloud/compute/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultClient returns an HTTP Client that uses the
|
||||||
|
// DefaultTokenSource to obtain authentication credentials.
|
||||||
|
//
|
||||||
|
// This client should be used when developing services
|
||||||
|
// that run on Google App Engine or Google Compute Engine
|
||||||
|
// and use "Application Default Credentials."
|
||||||
|
//
|
||||||
|
// For more details, see:
|
||||||
|
// https://developers.google.com/accounts/docs/application-default-credentials
|
||||||
|
//
|
||||||
|
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
|
||||||
|
ts, err := DefaultTokenSource(ctx, scope...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return oauth2.NewClient(ctx, ts), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultTokenSource is a token source that uses
|
||||||
|
// "Application Default Credentials".
|
||||||
|
//
|
||||||
|
// It looks for credentials in the following places,
|
||||||
|
// preferring the first location found:
|
||||||
|
//
|
||||||
|
// 1. A JSON file whose path is specified by the
|
||||||
|
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
|
||||||
|
// 2. A JSON file in a location known to the gcloud command-line tool.
|
||||||
|
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
|
||||||
|
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
|
||||||
|
// 3. On Google App Engine it uses the appengine.AccessToken function.
|
||||||
|
// 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
|
||||||
|
// credentials from the metadata server.
|
||||||
|
// (In this final case any provided scopes are ignored.)
|
||||||
|
//
|
||||||
|
// For more details, see:
|
||||||
|
// https://developers.google.com/accounts/docs/application-default-credentials
|
||||||
|
//
|
||||||
|
func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
|
||||||
|
// First, try the environment variable.
|
||||||
|
const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
|
||||||
|
if filename := os.Getenv(envVar); filename != "" {
|
||||||
|
ts, err := tokenSourceFromFile(ctx, filename, scope)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err)
|
||||||
|
}
|
||||||
|
return ts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second, try a well-known file.
|
||||||
|
filename := wellKnownFile()
|
||||||
|
_, err := os.Stat(filename)
|
||||||
|
if err == nil {
|
||||||
|
ts, err2 := tokenSourceFromFile(ctx, filename, scope)
|
||||||
|
if err2 == nil {
|
||||||
|
return ts, nil
|
||||||
|
}
|
||||||
|
err = err2
|
||||||
|
} else if os.IsNotExist(err) {
|
||||||
|
err = nil // ignore this error
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Third, if we're on Google App Engine use those credentials.
|
||||||
|
if appengineTokenFunc != nil && !appengineVM {
|
||||||
|
return AppEngineTokenSource(ctx, scope...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fourth, if we're on Google Compute Engine use the metadata server.
|
||||||
|
if metadata.OnGCE() {
|
||||||
|
return ComputeTokenSource(""), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// None are found; return helpful error.
|
||||||
|
const url = "https://developers.google.com/accounts/docs/application-default-credentials"
|
||||||
|
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func wellKnownFile() string {
|
||||||
|
const f = "application_default_credentials.json"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
return filepath.Join(os.Getenv("APPDATA"), "gcloud", f)
|
||||||
|
}
|
||||||
|
return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tokenSourceFromFile(ctx context.Context, filename string, scopes []string) (oauth2.TokenSource, error) {
|
||||||
|
b, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var d struct {
|
||||||
|
// Common fields
|
||||||
|
Type string
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
|
||||||
|
// User Credential fields
|
||||||
|
ClientSecret string `json:"client_secret"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
|
||||||
|
// Service Account fields
|
||||||
|
ClientEmail string `json:"client_email"`
|
||||||
|
PrivateKeyID string `json:"private_key_id"`
|
||||||
|
PrivateKey string `json:"private_key"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(b, &d); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch d.Type {
|
||||||
|
case "authorized_user":
|
||||||
|
cfg := &oauth2.Config{
|
||||||
|
ClientID: d.ClientID,
|
||||||
|
ClientSecret: d.ClientSecret,
|
||||||
|
Scopes: append([]string{}, scopes...), // copy
|
||||||
|
Endpoint: Endpoint,
|
||||||
|
}
|
||||||
|
tok := &oauth2.Token{RefreshToken: d.RefreshToken}
|
||||||
|
return cfg.TokenSource(ctx, tok), nil
|
||||||
|
case "service_account":
|
||||||
|
cfg := &jwt.Config{
|
||||||
|
Email: d.ClientEmail,
|
||||||
|
PrivateKey: []byte(d.PrivateKey),
|
||||||
|
Scopes: append([]string{}, scopes...), // copy
|
||||||
|
TokenURL: JWTTokenURL,
|
||||||
|
}
|
||||||
|
return cfg.TokenSource(ctx), nil
|
||||||
|
case "":
|
||||||
|
return nil, errors.New("missing 'type' field in credentials")
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown credential type: %q", d.Type)
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user