Bump deps
This commit is contained in:
parent
fe52ce1115
commit
07dfc1da27
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Annotate prepends msg to the error message in err, attempting
|
||||
// to preserve other information in err, like an error code.
|
||||
//
|
||||
// Annotate panics if err is nil.
|
||||
//
|
||||
// Annotate knows about these error types:
|
||||
// - "google.golang.org/grpc/status".Status
|
||||
// - "google.golang.org/api/googleapi".Error
|
||||
// If the error is not one of these types, Annotate behaves
|
||||
// like
|
||||
// fmt.Errorf("%s: %v", msg, err)
|
||||
func Annotate(err error, msg string) error {
|
||||
if err == nil {
|
||||
panic("Annotate called with nil")
|
||||
}
|
||||
if s, ok := status.FromError(err); ok {
|
||||
p := s.Proto()
|
||||
p.Message = msg + ": " + p.Message
|
||||
return status.ErrorProto(p)
|
||||
}
|
||||
if g, ok := err.(*googleapi.Error); ok {
|
||||
g.Message = msg + ": " + g.Message
|
||||
return g
|
||||
}
|
||||
return fmt.Errorf("%s: %v", msg, err)
|
||||
}
|
||||
|
||||
// Annotatef uses format and args to format a string, then calls Annotate.
|
||||
func Annotatef(err error, format string, args ...interface{}) error {
|
||||
return Annotate(err, fmt.Sprintf(format, args...))
|
||||
}
|
|
@ -15,7 +15,6 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
gax "github.com/googleapis/gax-go"
|
||||
|
@ -48,7 +47,7 @@ func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error),
|
|||
p := bo.Pause()
|
||||
if cerr := sleep(ctx, p); cerr != nil {
|
||||
if lastErr != nil {
|
||||
return fmt.Errorf("%v; last function err: %v", cerr, lastErr)
|
||||
return Annotatef(lastErr, "retry failed with %v; last error", cerr)
|
||||
}
|
||||
return cerr
|
||||
}
|
||||
|
|
|
@ -258,14 +258,15 @@ func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) {
|
|||
// ObjectHandle provides operations on an object in a Google Cloud Storage bucket.
|
||||
// Use BucketHandle.Object to get a handle.
|
||||
type ObjectHandle struct {
|
||||
c *Client
|
||||
bucket string
|
||||
object string
|
||||
acl ACLHandle
|
||||
gen int64 // a negative value indicates latest
|
||||
conds *Conditions
|
||||
encryptionKey []byte // AES-256 key
|
||||
userProject string // for requester-pays buckets
|
||||
c *Client
|
||||
bucket string
|
||||
object string
|
||||
acl ACLHandle
|
||||
gen int64 // a negative value indicates latest
|
||||
conds *Conditions
|
||||
encryptionKey []byte // AES-256 key
|
||||
userProject string // for requester-pays buckets
|
||||
readCompressed bool // Accept-Encoding: gzip
|
||||
}
|
||||
|
||||
// ACL provides access to the object's access control list.
|
||||
|
@ -467,6 +468,13 @@ func (o *ObjectHandle) Delete(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// ReadCompressed when true causes the read to happen without decompressing.
|
||||
func (o *ObjectHandle) ReadCompressed(compressed bool) *ObjectHandle {
|
||||
o2 := *o
|
||||
o2.readCompressed = compressed
|
||||
return &o2
|
||||
}
|
||||
|
||||
// NewReader creates a new Reader to read the contents of the
|
||||
// object.
|
||||
// ErrObjectNotExist will be returned if the object is not found.
|
||||
|
@ -514,6 +522,9 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
|||
if o.userProject != "" {
|
||||
req.Header.Set("X-Goog-User-Project", o.userProject)
|
||||
}
|
||||
if o.readCompressed {
|
||||
req.Header.Set("Accept-Encoding", "gzip")
|
||||
}
|
||||
if err := setEncryptionHeaders(req.Header, o.encryptionKey, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -549,27 +549,7 @@ func (b *Blob) GetMetadata(options *GetBlobMetadataOptions) error {
|
|||
}
|
||||
|
||||
func (b *Blob) writeMetadata(h http.Header) {
|
||||
metadata := make(map[string]string)
|
||||
for k, v := range h {
|
||||
// Can't trust CanonicalHeaderKey() to munge case
|
||||
// reliably. "_" is allowed in identifiers:
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
|
||||
// https://msdn.microsoft.com/library/aa664670(VS.71).aspx
|
||||
// http://tools.ietf.org/html/rfc7230#section-3.2
|
||||
// ...but "_" is considered invalid by
|
||||
// CanonicalMIMEHeaderKey in
|
||||
// https://golang.org/src/net/textproto/reader.go?s=14615:14659#L542
|
||||
// so k can be "X-Ms-Meta-Lol" or "x-ms-meta-lol_rofl".
|
||||
k = strings.ToLower(k)
|
||||
if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) {
|
||||
continue
|
||||
}
|
||||
// metadata["lol"] = content of the last X-Ms-Meta-Lol header
|
||||
k = k[len(userDefinedMetadataHeaderPrefix):]
|
||||
metadata[k] = v[len(v)-1]
|
||||
}
|
||||
|
||||
b.Metadata = BlobMetadata(metadata)
|
||||
b.Metadata = BlobMetadata(writeMetadata(h))
|
||||
}
|
||||
|
||||
// DeleteBlobOptions includes the options for a delete blob operation
|
||||
|
|
|
@ -15,6 +15,7 @@ package storage
|
|||
// limitations under the License.
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -85,21 +86,53 @@ func (b BlobStorageClient) ListContainers(params ListContainersParameters) (*Con
|
|||
uri := b.client.getEndpoint(blobServiceName, "", q)
|
||||
headers := b.client.getStandardHeaders()
|
||||
|
||||
var out ContainerListResponse
|
||||
type ContainerAlias struct {
|
||||
bsc *BlobStorageClient
|
||||
Name string `xml:"Name"`
|
||||
Properties ContainerProperties `xml:"Properties"`
|
||||
Metadata BlobMetadata
|
||||
sasuri url.URL
|
||||
}
|
||||
type ContainerListResponseAlias struct {
|
||||
XMLName xml.Name `xml:"EnumerationResults"`
|
||||
Xmlns string `xml:"xmlns,attr"`
|
||||
Prefix string `xml:"Prefix"`
|
||||
Marker string `xml:"Marker"`
|
||||
NextMarker string `xml:"NextMarker"`
|
||||
MaxResults int64 `xml:"MaxResults"`
|
||||
Containers []ContainerAlias `xml:"Containers>Container"`
|
||||
}
|
||||
|
||||
var outAlias ContainerListResponseAlias
|
||||
resp, err := b.client.exec(http.MethodGet, uri, headers, nil, b.auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.body.Close()
|
||||
err = xmlUnmarshal(resp.body, &out)
|
||||
err = xmlUnmarshal(resp.body, &outAlias)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// assign our client to the newly created Container objects
|
||||
for i := range out.Containers {
|
||||
out.Containers[i].bsc = &b
|
||||
out := ContainerListResponse{
|
||||
XMLName: outAlias.XMLName,
|
||||
Xmlns: outAlias.Xmlns,
|
||||
Prefix: outAlias.Prefix,
|
||||
Marker: outAlias.Marker,
|
||||
NextMarker: outAlias.NextMarker,
|
||||
MaxResults: outAlias.MaxResults,
|
||||
Containers: make([]Container, len(outAlias.Containers)),
|
||||
}
|
||||
for i, cnt := range outAlias.Containers {
|
||||
out.Containers[i] = Container{
|
||||
bsc: &b,
|
||||
Name: cnt.Name,
|
||||
Properties: cnt.Properties,
|
||||
Metadata: map[string]string(cnt.Metadata),
|
||||
sasuri: cnt.sasuri,
|
||||
}
|
||||
}
|
||||
|
||||
return &out, err
|
||||
}
|
||||
|
||||
|
@ -124,3 +157,26 @@ func (p ListContainersParameters) getParameters() url.Values {
|
|||
|
||||
return out
|
||||
}
|
||||
|
||||
func writeMetadata(h http.Header) map[string]string {
|
||||
metadata := make(map[string]string)
|
||||
for k, v := range h {
|
||||
// Can't trust CanonicalHeaderKey() to munge case
|
||||
// reliably. "_" is allowed in identifiers:
|
||||
// https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
|
||||
// https://msdn.microsoft.com/library/aa664670(VS.71).aspx
|
||||
// http://tools.ietf.org/html/rfc7230#section-3.2
|
||||
// ...but "_" is considered invalid by
|
||||
// CanonicalMIMEHeaderKey in
|
||||
// https://golang.org/src/net/textproto/reader.go?s=14615:14659#L542
|
||||
// so k can be "X-Ms-Meta-Lol" or "x-ms-meta-lol_rofl".
|
||||
k = strings.ToLower(k)
|
||||
if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) {
|
||||
continue
|
||||
}
|
||||
// metadata["lol"] = content of the last X-Ms-Meta-Lol header
|
||||
k = k[len(userDefinedMetadataHeaderPrefix):]
|
||||
metadata[k] = v[len(v)-1]
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import (
|
|||
"net/url"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -69,6 +70,11 @@ const (
|
|||
userAgentHeader = "User-Agent"
|
||||
|
||||
userDefinedMetadataHeaderPrefix = "x-ms-meta-"
|
||||
|
||||
connectionStringAccountName = "accountname"
|
||||
connectionStringAccountKey = "accountkey"
|
||||
connectionStringEndpointSuffix = "endpointsuffix"
|
||||
connectionStringEndpointProtocol = "defaultendpointsprotocol"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -204,6 +210,45 @@ func (e UnexpectedStatusCodeError) Got() int {
|
|||
return e.got
|
||||
}
|
||||
|
||||
// NewClientFromConnectionString creates a Client from the connection string.
|
||||
func NewClientFromConnectionString(input string) (Client, error) {
|
||||
var (
|
||||
accountName, accountKey, endpointSuffix string
|
||||
useHTTPS = defaultUseHTTPS
|
||||
)
|
||||
|
||||
for _, pair := range strings.Split(input, ";") {
|
||||
if pair == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
equalDex := strings.IndexByte(pair, '=')
|
||||
if equalDex <= 0 {
|
||||
return Client{}, fmt.Errorf("Invalid connection segment %q", pair)
|
||||
}
|
||||
|
||||
value := pair[equalDex+1:]
|
||||
key := strings.ToLower(pair[:equalDex])
|
||||
switch key {
|
||||
case connectionStringAccountName:
|
||||
accountName = value
|
||||
case connectionStringAccountKey:
|
||||
accountKey = value
|
||||
case connectionStringEndpointSuffix:
|
||||
endpointSuffix = value
|
||||
case connectionStringEndpointProtocol:
|
||||
useHTTPS = value == "https"
|
||||
default:
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
if accountName == StorageEmulatorAccountName {
|
||||
return NewEmulatorClient()
|
||||
}
|
||||
return NewClient(accountName, accountKey, endpointSuffix, DefaultAPIVersion, useHTTPS)
|
||||
}
|
||||
|
||||
// NewBasicClient constructs a Client with given storage service name and
|
||||
// key.
|
||||
func NewBasicClient(accountName, accountKey string) (Client, error) {
|
||||
|
@ -613,12 +658,13 @@ func (c Client) exec(verb, url string, headers map[string]string, body io.Reader
|
|||
return nil, errors.New("azure/storage: error creating request: " + err.Error())
|
||||
}
|
||||
|
||||
// if a body was provided ensure that the content length was set.
|
||||
// http.NewRequest() will automatically do this for a handful of types
|
||||
// and for those that it doesn't we will handle here.
|
||||
if body != nil && req.ContentLength < 1 {
|
||||
if lr, ok := body.(*io.LimitedReader); ok {
|
||||
setContentLengthFromLimitedReader(req, lr)
|
||||
// http.NewRequest() will automatically set req.ContentLength for a handful of types
|
||||
// otherwise we will handle here.
|
||||
if req.ContentLength < 1 {
|
||||
if clstr, ok := headers["Content-Length"]; ok {
|
||||
if cl, err := strconv.ParseInt(clstr, 10, 64); err == nil {
|
||||
req.ContentLength = cl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -512,6 +512,81 @@ func (c *Container) ListBlobs(params ListBlobsParameters) (BlobListResponse, err
|
|||
return out, err
|
||||
}
|
||||
|
||||
// ContainerMetadataOptions includes options for container metadata operations
|
||||
type ContainerMetadataOptions struct {
|
||||
Timeout uint
|
||||
LeaseID string `header:"x-ms-lease-id"`
|
||||
RequestID string `header:"x-ms-client-request-id"`
|
||||
}
|
||||
|
||||
// SetMetadata replaces the metadata for the specified container.
|
||||
//
|
||||
// Some keys may be converted to Camel-Case before sending. All keys
|
||||
// are returned in lower case by GetBlobMetadata. HTTP header names
|
||||
// are case-insensitive so case munging should not matter to other
|
||||
// applications either.
|
||||
//
|
||||
// See https://docs.microsoft.com/en-us/rest/api/storageservices/set-container-metadata
|
||||
func (c *Container) SetMetadata(options *ContainerMetadataOptions) error {
|
||||
params := url.Values{
|
||||
"comp": {"metadata"},
|
||||
"restype": {"container"},
|
||||
}
|
||||
headers := c.bsc.client.getStandardHeaders()
|
||||
headers = c.bsc.client.addMetadataToHeaders(headers, c.Metadata)
|
||||
|
||||
if options != nil {
|
||||
params = addTimeout(params, options.Timeout)
|
||||
headers = mergeHeaders(headers, headersFromStruct(*options))
|
||||
}
|
||||
|
||||
uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), params)
|
||||
|
||||
resp, err := c.bsc.client.exec(http.MethodPut, uri, headers, nil, c.bsc.auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
readAndCloseBody(resp.body)
|
||||
return checkRespCode(resp.statusCode, []int{http.StatusOK})
|
||||
}
|
||||
|
||||
// GetMetadata returns all user-defined metadata for the specified container.
|
||||
//
|
||||
// All metadata keys will be returned in lower case. (HTTP header
|
||||
// names are case-insensitive.)
|
||||
//
|
||||
// See https://docs.microsoft.com/en-us/rest/api/storageservices/get-container-metadata
|
||||
func (c *Container) GetMetadata(options *ContainerMetadataOptions) error {
|
||||
params := url.Values{
|
||||
"comp": {"metadata"},
|
||||
"restype": {"container"},
|
||||
}
|
||||
headers := c.bsc.client.getStandardHeaders()
|
||||
|
||||
if options != nil {
|
||||
params = addTimeout(params, options.Timeout)
|
||||
headers = mergeHeaders(headers, headersFromStruct(*options))
|
||||
}
|
||||
|
||||
uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), params)
|
||||
|
||||
resp, err := c.bsc.client.exec(http.MethodGet, uri, headers, nil, c.bsc.auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
readAndCloseBody(resp.body)
|
||||
if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.writeMetadata(resp.headers)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Container) writeMetadata(h http.Header) {
|
||||
c.Metadata = writeMetadata(h)
|
||||
}
|
||||
|
||||
func generateContainerACLpayload(policies []ContainerAccessPolicy) (io.Reader, int, error) {
|
||||
sil := SignedIdentifiers{
|
||||
SignedIdentifiers: []SignedIdentifier{},
|
||||
|
|
|
@ -87,10 +87,10 @@ func (b *Blob) modifyRange(blobRange BlobRange, bytes io.Reader, options *PutPag
|
|||
return errors.New("the value for rangeEnd must be greater than or equal to rangeStart")
|
||||
}
|
||||
if blobRange.Start%512 != 0 {
|
||||
return errors.New("the value for rangeStart must be a modulus of 512")
|
||||
return errors.New("the value for rangeStart must be a multiple of 512")
|
||||
}
|
||||
if blobRange.End%512 != 511 {
|
||||
return errors.New("the value for rangeEnd must be a modulus of 511")
|
||||
return errors.New("the value for rangeEnd must be a multiple of 512 - 1")
|
||||
}
|
||||
|
||||
params := url.Values{"comp": {"page"}}
|
||||
|
@ -147,7 +147,7 @@ func (b *Blob) GetPageRanges(options *GetPageRangesOptions) (GetPageRangesRespon
|
|||
params = addTimeout(params, options.Timeout)
|
||||
params = addSnapshot(params, options.Snapshot)
|
||||
if options.PreviousSnapshot != nil {
|
||||
params.Add("prevsnapshot", timeRfc1123Formatted(*options.PreviousSnapshot))
|
||||
params.Add("prevsnapshot", timeRFC3339Formatted(*options.PreviousSnapshot))
|
||||
}
|
||||
if options.Range != nil {
|
||||
headers["Range"] = options.Range.String()
|
||||
|
|
|
@ -71,6 +71,10 @@ func timeRfc1123Formatted(t time.Time) string {
|
|||
return t.Format(http.TimeFormat)
|
||||
}
|
||||
|
||||
func timeRFC3339Formatted(t time.Time) string {
|
||||
return t.Format("2006-01-02T15:04:05.0000000Z")
|
||||
}
|
||||
|
||||
func mergeParams(v1, v2 url.Values) url.Values {
|
||||
out := url.Values{}
|
||||
for k, v := range v1 {
|
||||
|
@ -172,7 +176,7 @@ func addTimeout(params url.Values, timeout uint) url.Values {
|
|||
|
||||
func addSnapshot(params url.Values, snapshot *time.Time) url.Values {
|
||||
if snapshot != nil {
|
||||
params.Add("snapshot", snapshot.Format("2006-01-02T15:04:05.0000000Z"))
|
||||
params.Add("snapshot", timeRFC3339Formatted(*snapshot))
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
// +build !go1.8
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func setContentLengthFromLimitedReader(req *http.Request, lr *io.LimitedReader) {
|
||||
req.ContentLength = lr.N
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// +build go1.8
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func setContentLengthFromLimitedReader(req *http.Request, lr *io.LimitedReader) {
|
||||
req.ContentLength = lr.N
|
||||
snapshot := *lr
|
||||
req.GetBody = func() (io.ReadCloser, error) {
|
||||
r := snapshot
|
||||
return ioutil.NopCloser(&r), nil
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ package azure
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -37,6 +38,109 @@ const (
|
|||
operationSucceeded string = "Succeeded"
|
||||
)
|
||||
|
||||
// Future provides a mechanism to access the status and results of an asynchronous request.
|
||||
// Since futures are stateful they should be passed by value to avoid race conditions.
|
||||
type Future struct {
|
||||
req *http.Request
|
||||
resp *http.Response
|
||||
ps pollingState
|
||||
}
|
||||
|
||||
// NewFuture returns a new Future object initialized with the specified request.
|
||||
func NewFuture(req *http.Request) Future {
|
||||
return Future{req: req}
|
||||
}
|
||||
|
||||
// Response returns the last HTTP response or nil if there isn't one.
|
||||
func (f Future) Response() *http.Response {
|
||||
return f.resp
|
||||
}
|
||||
|
||||
// Status returns the last status message of the operation.
|
||||
func (f Future) Status() string {
|
||||
if f.ps.State == "" {
|
||||
return "Unknown"
|
||||
}
|
||||
return f.ps.State
|
||||
}
|
||||
|
||||
// PollingMethod returns the method used to monitor the status of the asynchronous operation.
|
||||
func (f Future) PollingMethod() PollingMethodType {
|
||||
return f.ps.PollingMethod
|
||||
}
|
||||
|
||||
// Done queries the service to see if the operation has completed.
|
||||
func (f *Future) Done(sender autorest.Sender) (bool, error) {
|
||||
// exit early if this future has terminated
|
||||
if f.ps.hasTerminated() {
|
||||
return true, f.errorInfo()
|
||||
}
|
||||
|
||||
resp, err := sender.Do(f.req)
|
||||
f.resp = resp
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = updatePollingState(resp, &f.ps)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if f.ps.hasTerminated() {
|
||||
return true, f.errorInfo()
|
||||
}
|
||||
|
||||
f.req, err = newPollingRequest(f.ps)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// GetPollingDelay returns a duration the application should wait before checking
|
||||
// the status of the asynchronous request and true; this value is returned from
|
||||
// the service via the Retry-After response header. If the header wasn't returned
|
||||
// then the function returns the zero-value time.Duration and false.
|
||||
func (f Future) GetPollingDelay() (time.Duration, bool) {
|
||||
if f.resp == nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
retry := f.resp.Header.Get(autorest.HeaderRetryAfter)
|
||||
if retry == "" {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
d, err := time.ParseDuration(retry + "s")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return d, true
|
||||
}
|
||||
|
||||
// if the operation failed the polling state will contain
|
||||
// error information and implements the error interface
|
||||
func (f *Future) errorInfo() error {
|
||||
if !f.ps.hasSucceeded() {
|
||||
return f.ps
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (f Future) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(&f.ps)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (f *Future) UnmarshalJSON(data []byte) error {
|
||||
err := json.Unmarshal(data, &f.ps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.req, err = newPollingRequest(f.ps)
|
||||
return err
|
||||
}
|
||||
|
||||
// DoPollForAsynchronous returns a SendDecorator that polls if the http.Response is for an Azure
|
||||
// long-running operation. It will delay between requests for the duration specified in the
|
||||
// RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled by
|
||||
|
@ -66,10 +170,11 @@ func DoPollForAsynchronous(delay time.Duration) autorest.SendDecorator {
|
|||
break
|
||||
}
|
||||
|
||||
r, err = newPollingRequest(resp, ps)
|
||||
r, err = newPollingRequest(ps)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
r.Cancel = resp.Request.Cancel
|
||||
|
||||
delay = autorest.GetRetryAfter(resp, delay)
|
||||
resp, err = autorest.SendWithSender(s, r,
|
||||
|
@ -160,36 +265,42 @@ func (ps provisioningStatus) hasProvisioningError() bool {
|
|||
return ps.ProvisioningError != ServiceError{}
|
||||
}
|
||||
|
||||
type pollingResponseFormat string
|
||||
// PollingMethodType defines a type used for enumerating polling mechanisms.
|
||||
type PollingMethodType string
|
||||
|
||||
const (
|
||||
usesOperationResponse pollingResponseFormat = "OperationResponse"
|
||||
usesProvisioningStatus pollingResponseFormat = "ProvisioningStatus"
|
||||
formatIsUnknown pollingResponseFormat = ""
|
||||
// PollingAsyncOperation indicates the polling method uses the Azure-AsyncOperation header.
|
||||
PollingAsyncOperation PollingMethodType = "AsyncOperation"
|
||||
|
||||
// PollingLocation indicates the polling method uses the Location header.
|
||||
PollingLocation PollingMethodType = "Location"
|
||||
|
||||
// PollingUnknown indicates an unknown polling method and is the default value.
|
||||
PollingUnknown PollingMethodType = ""
|
||||
)
|
||||
|
||||
type pollingState struct {
|
||||
responseFormat pollingResponseFormat
|
||||
uri string
|
||||
state string
|
||||
code string
|
||||
message string
|
||||
PollingMethod PollingMethodType `json:"pollingMethod"`
|
||||
URI string `json:"uri"`
|
||||
State string `json:"state"`
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (ps pollingState) hasSucceeded() bool {
|
||||
return hasSucceeded(ps.state)
|
||||
return hasSucceeded(ps.State)
|
||||
}
|
||||
|
||||
func (ps pollingState) hasTerminated() bool {
|
||||
return hasTerminated(ps.state)
|
||||
return hasTerminated(ps.State)
|
||||
}
|
||||
|
||||
func (ps pollingState) hasFailed() bool {
|
||||
return hasFailed(ps.state)
|
||||
return hasFailed(ps.State)
|
||||
}
|
||||
|
||||
func (ps pollingState) Error() string {
|
||||
return fmt.Sprintf("Long running operation terminated with status '%s': Code=%q Message=%q", ps.state, ps.code, ps.message)
|
||||
return fmt.Sprintf("Long running operation terminated with status '%s': Code=%q Message=%q", ps.State, ps.Code, ps.Message)
|
||||
}
|
||||
|
||||
// updatePollingState maps the operation status -- retrieved from either a provisioningState
|
||||
|
@ -204,7 +315,7 @@ func updatePollingState(resp *http.Response, ps *pollingState) error {
|
|||
// -- The first response will always be a provisioningStatus response; only the polling requests,
|
||||
// depending on the header returned, may be something otherwise.
|
||||
var pt provisioningTracker
|
||||
if ps.responseFormat == usesOperationResponse {
|
||||
if ps.PollingMethod == PollingAsyncOperation {
|
||||
pt = &operationResource{}
|
||||
} else {
|
||||
pt = &provisioningStatus{}
|
||||
|
@ -212,30 +323,30 @@ func updatePollingState(resp *http.Response, ps *pollingState) error {
|
|||
|
||||
// If this is the first request (that is, the polling response shape is unknown), determine how
|
||||
// to poll and what to expect
|
||||
if ps.responseFormat == formatIsUnknown {
|
||||
if ps.PollingMethod == PollingUnknown {
|
||||
req := resp.Request
|
||||
if req == nil {
|
||||
return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Original HTTP request is missing")
|
||||
}
|
||||
|
||||
// Prefer the Azure-AsyncOperation header
|
||||
ps.uri = getAsyncOperation(resp)
|
||||
if ps.uri != "" {
|
||||
ps.responseFormat = usesOperationResponse
|
||||
ps.URI = getAsyncOperation(resp)
|
||||
if ps.URI != "" {
|
||||
ps.PollingMethod = PollingAsyncOperation
|
||||
} else {
|
||||
ps.responseFormat = usesProvisioningStatus
|
||||
ps.PollingMethod = PollingLocation
|
||||
}
|
||||
|
||||
// Else, use the Location header
|
||||
if ps.uri == "" {
|
||||
ps.uri = autorest.GetLocation(resp)
|
||||
if ps.URI == "" {
|
||||
ps.URI = autorest.GetLocation(resp)
|
||||
}
|
||||
|
||||
// Lastly, requests against an existing resource, use the last request URI
|
||||
if ps.uri == "" {
|
||||
if ps.URI == "" {
|
||||
m := strings.ToUpper(req.Method)
|
||||
if m == http.MethodPatch || m == http.MethodPut || m == http.MethodGet {
|
||||
ps.uri = req.URL.String()
|
||||
ps.URI = req.URL.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -256,23 +367,23 @@ func updatePollingState(resp *http.Response, ps *pollingState) error {
|
|||
// -- Unknown states are per-service inprogress states
|
||||
// -- Otherwise, infer state from HTTP status code
|
||||
if pt.hasTerminated() {
|
||||
ps.state = pt.state()
|
||||
ps.State = pt.state()
|
||||
} else if pt.state() != "" {
|
||||
ps.state = operationInProgress
|
||||
ps.State = operationInProgress
|
||||
} else {
|
||||
switch resp.StatusCode {
|
||||
case http.StatusAccepted:
|
||||
ps.state = operationInProgress
|
||||
ps.State = operationInProgress
|
||||
|
||||
case http.StatusNoContent, http.StatusCreated, http.StatusOK:
|
||||
ps.state = operationSucceeded
|
||||
ps.State = operationSucceeded
|
||||
|
||||
default:
|
||||
ps.state = operationFailed
|
||||
ps.State = operationFailed
|
||||
}
|
||||
}
|
||||
|
||||
if ps.state == operationInProgress && ps.uri == "" {
|
||||
if ps.State == operationInProgress && ps.URI == "" {
|
||||
return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Unable to obtain polling URI for %s %s", resp.Request.Method, resp.Request.URL)
|
||||
}
|
||||
|
||||
|
@ -281,35 +392,30 @@ func updatePollingState(resp *http.Response, ps *pollingState) error {
|
|||
// -- Response
|
||||
// -- Otherwise, Unknown
|
||||
if ps.hasFailed() {
|
||||
if ps.responseFormat == usesOperationResponse {
|
||||
if ps.PollingMethod == PollingAsyncOperation {
|
||||
or := pt.(*operationResource)
|
||||
ps.code = or.OperationError.Code
|
||||
ps.message = or.OperationError.Message
|
||||
ps.Code = or.OperationError.Code
|
||||
ps.Message = or.OperationError.Message
|
||||
} else {
|
||||
p := pt.(*provisioningStatus)
|
||||
if p.hasProvisioningError() {
|
||||
ps.code = p.ProvisioningError.Code
|
||||
ps.message = p.ProvisioningError.Message
|
||||
ps.Code = p.ProvisioningError.Code
|
||||
ps.Message = p.ProvisioningError.Message
|
||||
} else {
|
||||
ps.code = "Unknown"
|
||||
ps.message = "None"
|
||||
ps.Code = "Unknown"
|
||||
ps.Message = "None"
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newPollingRequest(resp *http.Response, ps pollingState) (*http.Request, error) {
|
||||
req := resp.Request
|
||||
if req == nil {
|
||||
return nil, autorest.NewError("azure", "newPollingRequest", "Azure Polling Error - Original HTTP request is missing")
|
||||
}
|
||||
|
||||
reqPoll, err := autorest.Prepare(&http.Request{Cancel: req.Cancel},
|
||||
func newPollingRequest(ps pollingState) (*http.Request, error) {
|
||||
reqPoll, err := autorest.Prepare(&http.Request{},
|
||||
autorest.AsGet(),
|
||||
autorest.WithBaseURL(ps.uri))
|
||||
autorest.WithBaseURL(ps.URI))
|
||||
if err != nil {
|
||||
return nil, autorest.NewErrorWithError(err, "azure", "newPollingRequest", nil, "Failure creating poll request to %s", ps.uri)
|
||||
return nil, autorest.NewErrorWithError(err, "azure", "newPollingRequest", nil, "Failure creating poll request to %s", ps.URI)
|
||||
}
|
||||
|
||||
return reqPoll, nil
|
||||
|
|
|
@ -15,10 +15,17 @@ package azure
|
|||
// limitations under the License.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// EnvironmentFilepathName captures the name of the environment variable containing the path to the file
|
||||
// to be used while populating the Azure Environment.
|
||||
const EnvironmentFilepathName = "AZURE_ENVIRONMENT_FILEPATH"
|
||||
|
||||
var environments = map[string]Environment{
|
||||
"AZURECHINACLOUD": ChinaCloud,
|
||||
"AZUREGERMANCLOUD": GermanCloud,
|
||||
|
@ -133,12 +140,37 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
// EnvironmentFromName returns an Environment based on the common name specified
|
||||
// EnvironmentFromName returns an Environment based on the common name specified.
|
||||
func EnvironmentFromName(name string) (Environment, error) {
|
||||
// IMPORTANT
|
||||
// As per @radhikagupta5:
|
||||
// This is technical debt, fundamentally here because Kubernetes is not currently accepting
|
||||
// contributions to the providers. Once that is an option, the provider should be updated to
|
||||
// directly call `EnvironmentFromFile`. Until then, we rely on dispatching Azure Stack environment creation
|
||||
// from this method based on the name that is provided to us.
|
||||
if strings.EqualFold(name, "AZURESTACKCLOUD") {
|
||||
return EnvironmentFromFile(os.Getenv(EnvironmentFilepathName))
|
||||
}
|
||||
|
||||
name = strings.ToUpper(name)
|
||||
env, ok := environments[name]
|
||||
if !ok {
|
||||
return env, fmt.Errorf("autorest/azure: There is no cloud environment matching the name %q", name)
|
||||
}
|
||||
|
||||
return env, nil
|
||||
}
|
||||
|
||||
// EnvironmentFromFile loads an Environment from a configuration file available on disk.
|
||||
// This function is particularly useful in the Hybrid Cloud model, where one must define their own
|
||||
// endpoints.
|
||||
func EnvironmentFromFile(location string) (unmarshaled Environment, err error) {
|
||||
fileContents, err := ioutil.ReadFile(location)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(fileContents, &unmarshaled)
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -55,15 +55,16 @@ func DoRetryWithRegistration(client autorest.Client) autorest.SendDecorator {
|
|||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
err = re
|
||||
|
||||
if re.ServiceError != nil && re.ServiceError.Code == "MissingSubscriptionRegistration" {
|
||||
err = register(client, r, re)
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("failed auto registering Resource Provider: %s", err)
|
||||
regErr := register(client, r, re)
|
||||
if regErr != nil {
|
||||
return resp, fmt.Errorf("failed auto registering Resource Provider: %s. Original error: %s", regErr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return resp, errors.New("failed request and resource provider registration")
|
||||
return resp, fmt.Errorf("failed request: %s", err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -221,7 +221,8 @@ func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) Se
|
|||
return resp, err
|
||||
}
|
||||
resp, err = s.Do(rr.Request())
|
||||
if err != nil || !ResponseHasStatusCode(resp, codes...) {
|
||||
// we want to retry if err is not nil (e.g. transient network failure)
|
||||
if err == nil && !ResponseHasStatusCode(resp, codes...) {
|
||||
return resp, err
|
||||
}
|
||||
delayed := DelayWithRetryAfter(resp, r.Cancel)
|
||||
|
@ -237,6 +238,9 @@ func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) Se
|
|||
// DelayWithRetryAfter invokes time.After for the duration specified in the "Retry-After" header in
|
||||
// responses with status code 429
|
||||
func DelayWithRetryAfter(resp *http.Response, cancel <-chan struct{}) bool {
|
||||
if resp == nil {
|
||||
return false
|
||||
}
|
||||
retryAfter, _ := strconv.Atoi(resp.Header.Get("Retry-After"))
|
||||
if resp.StatusCode == http.StatusTooManyRequests && retryAfter > 0 {
|
||||
select {
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
@ -190,3 +191,14 @@ func createQuery(v url.Values) string {
|
|||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ChangeToGet turns the specified http.Request into a GET (it assumes it wasn't).
|
||||
// This is mainly useful for long-running operations that use the Azure-AsyncOperation
|
||||
// header, so we change the initial PUT into a GET to retrieve the final result.
|
||||
func ChangeToGet(req *http.Request) *http.Request {
|
||||
req.Method = "GET"
|
||||
req.Body = nil
|
||||
req.ContentLength = 0
|
||||
req.Header.Del("Content-Length")
|
||||
return req
|
||||
}
|
||||
|
|
|
@ -156,6 +156,7 @@ func IsPort(str string) bool
|
|||
func IsPositive(value float64) bool
|
||||
func IsPrintableASCII(str string) bool
|
||||
func IsRFC3339(str string) bool
|
||||
func IsRFC3339WithoutZone(str string) bool
|
||||
func IsRGBcolor(str string) bool
|
||||
func IsRequestURI(rawurl string) bool
|
||||
func IsRequestURL(rawurl string) bool
|
||||
|
@ -269,56 +270,57 @@ For completely custom validators (interface-based), see below.
|
|||
|
||||
Here is a list of available validators for struct fields (validator - used function):
|
||||
```go
|
||||
"email": IsEmail,
|
||||
"url": IsURL,
|
||||
"dialstring": IsDialString,
|
||||
"requrl": IsRequestURL,
|
||||
"requri": IsRequestURI,
|
||||
"alpha": IsAlpha,
|
||||
"utfletter": IsUTFLetter,
|
||||
"alphanum": IsAlphanumeric,
|
||||
"utfletternum": IsUTFLetterNumeric,
|
||||
"numeric": IsNumeric,
|
||||
"utfnumeric": IsUTFNumeric,
|
||||
"utfdigit": IsUTFDigit,
|
||||
"hexadecimal": IsHexadecimal,
|
||||
"hexcolor": IsHexcolor,
|
||||
"rgbcolor": IsRGBcolor,
|
||||
"lowercase": IsLowerCase,
|
||||
"uppercase": IsUpperCase,
|
||||
"int": IsInt,
|
||||
"float": IsFloat,
|
||||
"null": IsNull,
|
||||
"uuid": IsUUID,
|
||||
"uuidv3": IsUUIDv3,
|
||||
"uuidv4": IsUUIDv4,
|
||||
"uuidv5": IsUUIDv5,
|
||||
"creditcard": IsCreditCard,
|
||||
"isbn10": IsISBN10,
|
||||
"isbn13": IsISBN13,
|
||||
"json": IsJSON,
|
||||
"multibyte": IsMultibyte,
|
||||
"ascii": IsASCII,
|
||||
"printableascii": IsPrintableASCII,
|
||||
"fullwidth": IsFullWidth,
|
||||
"halfwidth": IsHalfWidth,
|
||||
"variablewidth": IsVariableWidth,
|
||||
"base64": IsBase64,
|
||||
"datauri": IsDataURI,
|
||||
"ip": IsIP,
|
||||
"port": IsPort,
|
||||
"ipv4": IsIPv4,
|
||||
"ipv6": IsIPv6,
|
||||
"dns": IsDNSName,
|
||||
"host": IsHost,
|
||||
"mac": IsMAC,
|
||||
"latitude": IsLatitude,
|
||||
"longitude": IsLongitude,
|
||||
"ssn": IsSSN,
|
||||
"semver": IsSemver,
|
||||
"rfc3339": IsRFC3339,
|
||||
"ISO3166Alpha2": IsISO3166Alpha2,
|
||||
"ISO3166Alpha3": IsISO3166Alpha3,
|
||||
"email": IsEmail,
|
||||
"url": IsURL,
|
||||
"dialstring": IsDialString,
|
||||
"requrl": IsRequestURL,
|
||||
"requri": IsRequestURI,
|
||||
"alpha": IsAlpha,
|
||||
"utfletter": IsUTFLetter,
|
||||
"alphanum": IsAlphanumeric,
|
||||
"utfletternum": IsUTFLetterNumeric,
|
||||
"numeric": IsNumeric,
|
||||
"utfnumeric": IsUTFNumeric,
|
||||
"utfdigit": IsUTFDigit,
|
||||
"hexadecimal": IsHexadecimal,
|
||||
"hexcolor": IsHexcolor,
|
||||
"rgbcolor": IsRGBcolor,
|
||||
"lowercase": IsLowerCase,
|
||||
"uppercase": IsUpperCase,
|
||||
"int": IsInt,
|
||||
"float": IsFloat,
|
||||
"null": IsNull,
|
||||
"uuid": IsUUID,
|
||||
"uuidv3": IsUUIDv3,
|
||||
"uuidv4": IsUUIDv4,
|
||||
"uuidv5": IsUUIDv5,
|
||||
"creditcard": IsCreditCard,
|
||||
"isbn10": IsISBN10,
|
||||
"isbn13": IsISBN13,
|
||||
"json": IsJSON,
|
||||
"multibyte": IsMultibyte,
|
||||
"ascii": IsASCII,
|
||||
"printableascii": IsPrintableASCII,
|
||||
"fullwidth": IsFullWidth,
|
||||
"halfwidth": IsHalfWidth,
|
||||
"variablewidth": IsVariableWidth,
|
||||
"base64": IsBase64,
|
||||
"datauri": IsDataURI,
|
||||
"ip": IsIP,
|
||||
"port": IsPort,
|
||||
"ipv4": IsIPv4,
|
||||
"ipv6": IsIPv6,
|
||||
"dns": IsDNSName,
|
||||
"host": IsHost,
|
||||
"mac": IsMAC,
|
||||
"latitude": IsLatitude,
|
||||
"longitude": IsLongitude,
|
||||
"ssn": IsSSN,
|
||||
"semver": IsSemver,
|
||||
"rfc3339": IsRFC3339,
|
||||
"rfc3339WithoutZone": IsRFC3339WithoutZone,
|
||||
"ISO3166Alpha2": IsISO3166Alpha2,
|
||||
"ISO3166Alpha3": IsISO3166Alpha3,
|
||||
```
|
||||
Validators with parameters
|
||||
|
||||
|
@ -409,7 +411,7 @@ Documentation is available here: [godoc.org](https://godoc.org/github.com/asaske
|
|||
Full information about code coverage is also available here: [govalidator on gocover.io](http://gocover.io/github.com/asaskevich/govalidator).
|
||||
|
||||
#### Support
|
||||
If you do have a contribution for the package feel free to put up a Pull Request or open Issue.
|
||||
If you do have a contribution for the package, feel free to create a Pull Request or an Issue.
|
||||
|
||||
#### Special thanks to [contributors](https://github.com/asaskevich/govalidator/graphs/contributors)
|
||||
* [Daniel Lohse](https://github.com/annismckenzie)
|
||||
|
|
|
@ -72,57 +72,58 @@ var CustomTypeTagMap = &customTypeTagMap{validators: make(map[string]CustomTypeV
|
|||
|
||||
// TagMap is a map of functions, that can be used as tags for ValidateStruct function.
|
||||
var TagMap = map[string]Validator{
|
||||
"email": IsEmail,
|
||||
"url": IsURL,
|
||||
"dialstring": IsDialString,
|
||||
"requrl": IsRequestURL,
|
||||
"requri": IsRequestURI,
|
||||
"alpha": IsAlpha,
|
||||
"utfletter": IsUTFLetter,
|
||||
"alphanum": IsAlphanumeric,
|
||||
"utfletternum": IsUTFLetterNumeric,
|
||||
"numeric": IsNumeric,
|
||||
"utfnumeric": IsUTFNumeric,
|
||||
"utfdigit": IsUTFDigit,
|
||||
"hexadecimal": IsHexadecimal,
|
||||
"hexcolor": IsHexcolor,
|
||||
"rgbcolor": IsRGBcolor,
|
||||
"lowercase": IsLowerCase,
|
||||
"uppercase": IsUpperCase,
|
||||
"int": IsInt,
|
||||
"float": IsFloat,
|
||||
"null": IsNull,
|
||||
"uuid": IsUUID,
|
||||
"uuidv3": IsUUIDv3,
|
||||
"uuidv4": IsUUIDv4,
|
||||
"uuidv5": IsUUIDv5,
|
||||
"creditcard": IsCreditCard,
|
||||
"isbn10": IsISBN10,
|
||||
"isbn13": IsISBN13,
|
||||
"json": IsJSON,
|
||||
"multibyte": IsMultibyte,
|
||||
"ascii": IsASCII,
|
||||
"printableascii": IsPrintableASCII,
|
||||
"fullwidth": IsFullWidth,
|
||||
"halfwidth": IsHalfWidth,
|
||||
"variablewidth": IsVariableWidth,
|
||||
"base64": IsBase64,
|
||||
"datauri": IsDataURI,
|
||||
"ip": IsIP,
|
||||
"port": IsPort,
|
||||
"ipv4": IsIPv4,
|
||||
"ipv6": IsIPv6,
|
||||
"dns": IsDNSName,
|
||||
"host": IsHost,
|
||||
"mac": IsMAC,
|
||||
"latitude": IsLatitude,
|
||||
"longitude": IsLongitude,
|
||||
"ssn": IsSSN,
|
||||
"semver": IsSemver,
|
||||
"rfc3339": IsRFC3339,
|
||||
"ISO3166Alpha2": IsISO3166Alpha2,
|
||||
"ISO3166Alpha3": IsISO3166Alpha3,
|
||||
"ISO4217": IsISO4217,
|
||||
"email": IsEmail,
|
||||
"url": IsURL,
|
||||
"dialstring": IsDialString,
|
||||
"requrl": IsRequestURL,
|
||||
"requri": IsRequestURI,
|
||||
"alpha": IsAlpha,
|
||||
"utfletter": IsUTFLetter,
|
||||
"alphanum": IsAlphanumeric,
|
||||
"utfletternum": IsUTFLetterNumeric,
|
||||
"numeric": IsNumeric,
|
||||
"utfnumeric": IsUTFNumeric,
|
||||
"utfdigit": IsUTFDigit,
|
||||
"hexadecimal": IsHexadecimal,
|
||||
"hexcolor": IsHexcolor,
|
||||
"rgbcolor": IsRGBcolor,
|
||||
"lowercase": IsLowerCase,
|
||||
"uppercase": IsUpperCase,
|
||||
"int": IsInt,
|
||||
"float": IsFloat,
|
||||
"null": IsNull,
|
||||
"uuid": IsUUID,
|
||||
"uuidv3": IsUUIDv3,
|
||||
"uuidv4": IsUUIDv4,
|
||||
"uuidv5": IsUUIDv5,
|
||||
"creditcard": IsCreditCard,
|
||||
"isbn10": IsISBN10,
|
||||
"isbn13": IsISBN13,
|
||||
"json": IsJSON,
|
||||
"multibyte": IsMultibyte,
|
||||
"ascii": IsASCII,
|
||||
"printableascii": IsPrintableASCII,
|
||||
"fullwidth": IsFullWidth,
|
||||
"halfwidth": IsHalfWidth,
|
||||
"variablewidth": IsVariableWidth,
|
||||
"base64": IsBase64,
|
||||
"datauri": IsDataURI,
|
||||
"ip": IsIP,
|
||||
"port": IsPort,
|
||||
"ipv4": IsIPv4,
|
||||
"ipv6": IsIPv6,
|
||||
"dns": IsDNSName,
|
||||
"host": IsHost,
|
||||
"mac": IsMAC,
|
||||
"latitude": IsLatitude,
|
||||
"longitude": IsLongitude,
|
||||
"ssn": IsSSN,
|
||||
"semver": IsSemver,
|
||||
"rfc3339": IsRFC3339,
|
||||
"rfc3339WithoutZone": IsRFC3339WithoutZone,
|
||||
"ISO3166Alpha2": IsISO3166Alpha2,
|
||||
"ISO3166Alpha3": IsISO3166Alpha3,
|
||||
"ISO4217": IsISO4217,
|
||||
}
|
||||
|
||||
// ISO3166Entry stores country codes
|
||||
|
|
|
@ -108,7 +108,7 @@ func CamelCaseToUnderscore(str string) string {
|
|||
var output []rune
|
||||
var segment []rune
|
||||
for _, r := range str {
|
||||
if !unicode.IsLower(r) {
|
||||
if !unicode.IsLower(r) && string(r) != "_" {
|
||||
output = addSegment(output, segment)
|
||||
segment = nil
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ var (
|
|||
|
||||
const maxURLRuneCount = 2083
|
||||
const minURLRuneCount = 3
|
||||
const RF3339WithoutZone = "2006-01-02T15:04:05"
|
||||
|
||||
// SetFieldsRequiredByDefault causes validation to fail when struct fields
|
||||
// do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`).
|
||||
|
@ -569,7 +570,16 @@ func toJSONName(tag string) string {
|
|||
// JSON name always comes first. If there's no options then split[0] is
|
||||
// JSON name, if JSON name is not set, then split[0] is an empty string.
|
||||
split := strings.SplitN(tag, ",", 2)
|
||||
return split[0]
|
||||
|
||||
name := split[0]
|
||||
|
||||
// However it is possible that the field is skipped when
|
||||
// (de-)serializing from/to JSON, in which case assume that there is no
|
||||
// tag name to use
|
||||
if name == "-" {
|
||||
return ""
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// ValidateStruct use tags for fields.
|
||||
|
@ -614,6 +624,14 @@ func ValidateStruct(s interface{}) (bool, error) {
|
|||
jsonError.Name = jsonTag
|
||||
err2 = jsonError
|
||||
case Errors:
|
||||
for i2, err3 := range jsonError {
|
||||
switch customErr := err3.(type) {
|
||||
case Error:
|
||||
customErr.Name = jsonTag
|
||||
jsonError[i2] = customErr
|
||||
}
|
||||
}
|
||||
|
||||
err2 = jsonError
|
||||
}
|
||||
}
|
||||
|
@ -692,6 +710,11 @@ func IsRFC3339(str string) bool {
|
|||
return IsTime(str, time.RFC3339)
|
||||
}
|
||||
|
||||
// IsRFC3339WithoutZone check if string is valid timestamp value according to RFC3339 which excludes the timezone.
|
||||
func IsRFC3339WithoutZone(str string) bool {
|
||||
return IsTime(str, RF3339WithoutZone)
|
||||
}
|
||||
|
||||
// IsISO4217 check if string is valid ISO currency code
|
||||
func IsISO4217(str string) bool {
|
||||
for _, currency := range ISO4217List {
|
||||
|
|
|
@ -2,6 +2,7 @@ package client
|
|||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -38,6 +39,10 @@ func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
|
|||
minTime := 30
|
||||
throttle := d.shouldThrottle(r)
|
||||
if throttle {
|
||||
if delay, ok := getRetryDelay(r); ok {
|
||||
return delay
|
||||
}
|
||||
|
||||
minTime = 500
|
||||
}
|
||||
|
||||
|
@ -68,12 +73,49 @@ func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
|
|||
|
||||
// ShouldThrottle returns true if the request should be throttled.
|
||||
func (d DefaultRetryer) shouldThrottle(r *request.Request) bool {
|
||||
if r.HTTPResponse.StatusCode == 502 ||
|
||||
r.HTTPResponse.StatusCode == 503 ||
|
||||
r.HTTPResponse.StatusCode == 504 {
|
||||
return true
|
||||
switch r.HTTPResponse.StatusCode {
|
||||
case 429:
|
||||
case 502:
|
||||
case 503:
|
||||
case 504:
|
||||
default:
|
||||
return r.IsErrorThrottle()
|
||||
}
|
||||
return r.IsErrorThrottle()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// This will look in the Retry-After header, RFC 7231, for how long
|
||||
// it will wait before attempting another request
|
||||
func getRetryDelay(r *request.Request) (time.Duration, bool) {
|
||||
if !canUseRetryAfterHeader(r) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
delayStr := r.HTTPResponse.Header.Get("Retry-After")
|
||||
if len(delayStr) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
delay, err := strconv.Atoi(delayStr)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return time.Duration(delay) * time.Second, true
|
||||
}
|
||||
|
||||
// Will look at the status code to see if the retry header pertains to
|
||||
// the status code.
|
||||
func canUseRetryAfterHeader(r *request.Request) bool {
|
||||
switch r.HTTPResponse.StatusCode {
|
||||
case 429:
|
||||
case 503:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// lockedSource is a thread-safe implementation of rand.Source
|
||||
|
|
|
@ -44,6 +44,7 @@ const (
|
|||
// Service identifiers
|
||||
const (
|
||||
AcmServiceID = "acm" // Acm.
|
||||
ApiPricingServiceID = "api.pricing" // ApiPricing.
|
||||
ApigatewayServiceID = "apigateway" // Apigateway.
|
||||
ApplicationAutoscalingServiceID = "application-autoscaling" // ApplicationAutoscaling.
|
||||
Appstream2ServiceID = "appstream2" // Appstream2.
|
||||
|
@ -256,6 +257,16 @@ var awsPartition = partition{
|
|||
"us-west-2": endpoint{},
|
||||
},
|
||||
},
|
||||
"api.pricing": service{
|
||||
Defaults: endpoint{
|
||||
CredentialScope: credentialScope{
|
||||
Service: "pricing",
|
||||
},
|
||||
},
|
||||
Endpoints: endpoints{
|
||||
"us-east-1": endpoint{},
|
||||
},
|
||||
},
|
||||
"apigateway": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
|
@ -1933,6 +1944,12 @@ var awscnPartition = partition{
|
|||
"cn-north-1": endpoint{},
|
||||
},
|
||||
},
|
||||
"cognito-identity": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
"cn-north-1": endpoint{},
|
||||
},
|
||||
},
|
||||
"config": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
|
|
|
@ -28,6 +28,10 @@ const (
|
|||
// during body reads.
|
||||
ErrCodeResponseTimeout = "ResponseTimeout"
|
||||
|
||||
// ErrCodeInvalidPresignExpire is returned when the expire time provided to
|
||||
// presign is invalid
|
||||
ErrCodeInvalidPresignExpire = "InvalidPresignExpireError"
|
||||
|
||||
// CanceledErrorCode is the error code that will be returned by an
|
||||
// API request that was canceled. Requests given a aws.Context may
|
||||
// return this error when canceled.
|
||||
|
@ -42,7 +46,6 @@ type Request struct {
|
|||
|
||||
Retryer
|
||||
Time time.Time
|
||||
ExpireTime time.Duration
|
||||
Operation *Operation
|
||||
HTTPRequest *http.Request
|
||||
HTTPResponse *http.Response
|
||||
|
@ -60,6 +63,11 @@ type Request struct {
|
|||
LastSignedAt time.Time
|
||||
DisableFollowRedirects bool
|
||||
|
||||
// A value greater than 0 instructs the request to be signed as Presigned URL
|
||||
// You should not set this field directly. Instead use Request's
|
||||
// Presign or PresignRequest methods.
|
||||
ExpireTime time.Duration
|
||||
|
||||
context aws.Context
|
||||
|
||||
built bool
|
||||
|
@ -250,40 +258,59 @@ func (r *Request) SetReaderBody(reader io.ReadSeeker) {
|
|||
|
||||
// Presign returns the request's signed URL. Error will be returned
|
||||
// if the signing fails.
|
||||
func (r *Request) Presign(expireTime time.Duration) (string, error) {
|
||||
r.ExpireTime = expireTime
|
||||
//
|
||||
// It is invalid to create a presigned URL with a expire duration 0 or less. An
|
||||
// error is returned if expire duration is 0 or less.
|
||||
func (r *Request) Presign(expire time.Duration) (string, error) {
|
||||
r = r.copy()
|
||||
|
||||
// Presign requires all headers be hoisted. There is no way to retrieve
|
||||
// the signed headers not hoisted without this. Making the presigned URL
|
||||
// useless.
|
||||
r.NotHoist = false
|
||||
|
||||
if r.Operation.BeforePresignFn != nil {
|
||||
r = r.copy()
|
||||
err := r.Operation.BeforePresignFn(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
r.Sign()
|
||||
if r.Error != nil {
|
||||
return "", r.Error
|
||||
}
|
||||
return r.HTTPRequest.URL.String(), nil
|
||||
u, _, err := getPresignedURL(r, expire)
|
||||
return u, err
|
||||
}
|
||||
|
||||
// PresignRequest behaves just like presign, with the addition of returning a
|
||||
// set of headers that were signed.
|
||||
//
|
||||
// It is invalid to create a presigned URL with a expire duration 0 or less. An
|
||||
// error is returned if expire duration is 0 or less.
|
||||
//
|
||||
// Returns the URL string for the API operation with signature in the query string,
|
||||
// and the HTTP headers that were included in the signature. These headers must
|
||||
// be included in any HTTP request made with the presigned URL.
|
||||
//
|
||||
// To prevent hoisting any headers to the query string set NotHoist to true on
|
||||
// this Request value prior to calling PresignRequest.
|
||||
func (r *Request) PresignRequest(expireTime time.Duration) (string, http.Header, error) {
|
||||
r.ExpireTime = expireTime
|
||||
r.Sign()
|
||||
if r.Error != nil {
|
||||
return "", nil, r.Error
|
||||
func (r *Request) PresignRequest(expire time.Duration) (string, http.Header, error) {
|
||||
r = r.copy()
|
||||
return getPresignedURL(r, expire)
|
||||
}
|
||||
|
||||
func getPresignedURL(r *Request, expire time.Duration) (string, http.Header, error) {
|
||||
if expire <= 0 {
|
||||
return "", nil, awserr.New(
|
||||
ErrCodeInvalidPresignExpire,
|
||||
"presigned URL requires an expire duration greater than 0",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
r.ExpireTime = expire
|
||||
|
||||
if r.Operation.BeforePresignFn != nil {
|
||||
if err := r.Operation.BeforePresignFn(r); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.Sign(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return r.HTTPRequest.URL.String(), r.SignedHeaderVals, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ type signingCtx struct {
|
|||
// "X-Amz-Content-Sha256" header with a precomputed value. The signer will
|
||||
// only compute the hash if the request header value is empty.
|
||||
func (v4 Signer) Sign(r *http.Request, body io.ReadSeeker, service, region string, signTime time.Time) (http.Header, error) {
|
||||
return v4.signWithBody(r, body, service, region, 0, signTime)
|
||||
return v4.signWithBody(r, body, service, region, 0, false, signTime)
|
||||
}
|
||||
|
||||
// Presign signs AWS v4 requests with the provided body, service name, region
|
||||
|
@ -302,10 +302,10 @@ func (v4 Signer) Sign(r *http.Request, body io.ReadSeeker, service, region strin
|
|||
// presigned request's signature you can set the "X-Amz-Content-Sha256"
|
||||
// HTTP header and that will be included in the request's signature.
|
||||
func (v4 Signer) Presign(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) {
|
||||
return v4.signWithBody(r, body, service, region, exp, signTime)
|
||||
return v4.signWithBody(r, body, service, region, exp, true, signTime)
|
||||
}
|
||||
|
||||
func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) {
|
||||
func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, isPresign bool, signTime time.Time) (http.Header, error) {
|
||||
currentTimeFn := v4.currentTimeFn
|
||||
if currentTimeFn == nil {
|
||||
currentTimeFn = time.Now
|
||||
|
@ -317,7 +317,7 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
|
|||
Query: r.URL.Query(),
|
||||
Time: signTime,
|
||||
ExpireTime: exp,
|
||||
isPresign: exp != 0,
|
||||
isPresign: isPresign,
|
||||
ServiceName: service,
|
||||
Region: region,
|
||||
DisableURIPathEscaping: v4.DisableURIPathEscaping,
|
||||
|
@ -467,7 +467,7 @@ func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time
|
|||
}
|
||||
|
||||
signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.GetBody(),
|
||||
name, region, req.ExpireTime, signingTime,
|
||||
name, region, req.ExpireTime, req.ExpireTime > 0, signingTime,
|
||||
)
|
||||
if err != nil {
|
||||
req.Error = err
|
||||
|
|
|
@ -5,4 +5,4 @@ package aws
|
|||
const SDKName = "aws-sdk-go"
|
||||
|
||||
// SDKVersion is the version of this SDK
|
||||
const SDKVersion = "1.12.19"
|
||||
const SDKVersion = "1.12.23"
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
//
|
||||
// Using the Client
|
||||
//
|
||||
// To Amazon DynamoDB with the SDK use the New function to create
|
||||
// To contact Amazon DynamoDB with the SDK use the New function to create
|
||||
// a new service client. With that client you can make API requests to the service.
|
||||
// These clients are safe to use concurrently.
|
||||
//
|
||||
|
|
|
@ -60892,6 +60892,24 @@ const (
|
|||
// InstanceTypeC48xlarge is a InstanceType enum value
|
||||
InstanceTypeC48xlarge = "c4.8xlarge"
|
||||
|
||||
// InstanceTypeC5Large is a InstanceType enum value
|
||||
InstanceTypeC5Large = "c5.large"
|
||||
|
||||
// InstanceTypeC5Xlarge is a InstanceType enum value
|
||||
InstanceTypeC5Xlarge = "c5.xlarge"
|
||||
|
||||
// InstanceTypeC52xlarge is a InstanceType enum value
|
||||
InstanceTypeC52xlarge = "c5.2xlarge"
|
||||
|
||||
// InstanceTypeC54xlarge is a InstanceType enum value
|
||||
InstanceTypeC54xlarge = "c5.4xlarge"
|
||||
|
||||
// InstanceTypeC59xlarge is a InstanceType enum value
|
||||
InstanceTypeC59xlarge = "c5.9xlarge"
|
||||
|
||||
// InstanceTypeC518xlarge is a InstanceType enum value
|
||||
InstanceTypeC518xlarge = "c5.18xlarge"
|
||||
|
||||
// InstanceTypeCc14xlarge is a InstanceType enum value
|
||||
InstanceTypeCc14xlarge = "cc1.4xlarge"
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
//
|
||||
// Using the Client
|
||||
//
|
||||
// To Amazon Elastic Compute Cloud with the SDK use the New function to create
|
||||
// To contact Amazon Elastic Compute Cloud with the SDK use the New function to create
|
||||
// a new service client. With that client you can make API requests to the service.
|
||||
// These clients are safe to use concurrently.
|
||||
//
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
//
|
||||
// Using the Client
|
||||
//
|
||||
// To AWS Identity and Access Management with the SDK use the New function to create
|
||||
// To contact AWS Identity and Access Management with the SDK use the New function to create
|
||||
// a new service client. With that client you can make API requests to the service.
|
||||
// These clients are safe to use concurrently.
|
||||
//
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
// Using the Client
|
||||
//
|
||||
// To Amazon Simple Storage Service with the SDK use the New function to create
|
||||
// To contact Amazon Simple Storage Service with the SDK use the New function to create
|
||||
// a new service client. With that client you can make API requests to the service.
|
||||
// These clients are safe to use concurrently.
|
||||
//
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
//
|
||||
// Using the Client
|
||||
//
|
||||
// To AWS Security Token Service with the SDK use the New function to create
|
||||
// To contact AWS Security Token Service with the SDK use the New function to create
|
||||
// a new service client. With that client you can make API requests to the service.
|
||||
// These clients are safe to use concurrently.
|
||||
//
|
||||
|
|
|
@ -22,12 +22,13 @@ import (
|
|||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// ErrNoAddrAvilable is returned by Get() when the balancer does not have
|
||||
// any active connection to endpoints at the time.
|
||||
// This error is returned only when opts.BlockingWait is true.
|
||||
var ErrNoAddrAvilable = grpc.Errorf(codes.Unavailable, "there is no address available")
|
||||
var ErrNoAddrAvilable = status.Error(codes.Unavailable, "there is no address available")
|
||||
|
||||
type notifyMsg int
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -91,7 +92,7 @@ func (wr *WatchResponse) Err() error {
|
|||
return v3rpc.ErrCompacted
|
||||
case wr.Canceled:
|
||||
if len(wr.cancelReason) != 0 {
|
||||
return v3rpc.Error(grpc.Errorf(codes.FailedPrecondition, "%s", wr.cancelReason))
|
||||
return v3rpc.Error(status.Error(codes.FailedPrecondition, wr.cancelReason))
|
||||
}
|
||||
return v3rpc.ErrFutureRev
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ type ContainerLogsOptions struct {
|
|||
ShowStdout bool
|
||||
ShowStderr bool
|
||||
Since string
|
||||
Until string
|
||||
Timestamps bool
|
||||
Follow bool
|
||||
Tail string
|
||||
|
|
|
@ -7,10 +7,22 @@ package container
|
|||
// See hack/generate-swagger-api.sh
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// ContainerWaitOKBodyError container waiting error, if any
|
||||
// swagger:model ContainerWaitOKBodyError
|
||||
type ContainerWaitOKBodyError struct {
|
||||
|
||||
// Details of an error
|
||||
Message string `json:"Message,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerWaitOKBody container wait o k body
|
||||
// swagger:model ContainerWaitOKBody
|
||||
type ContainerWaitOKBody struct {
|
||||
|
||||
// error
|
||||
// Required: true
|
||||
Error *ContainerWaitOKBodyError `json:"Error"`
|
||||
|
||||
// Exit code of the container
|
||||
// Required: true
|
||||
StatusCode int64 `json:"StatusCode"`
|
||||
|
|
|
@ -20,6 +20,27 @@ func (i Isolation) IsDefault() bool {
|
|||
return strings.ToLower(string(i)) == "default" || string(i) == ""
|
||||
}
|
||||
|
||||
// IsHyperV indicates the use of a Hyper-V partition for isolation
|
||||
func (i Isolation) IsHyperV() bool {
|
||||
return strings.ToLower(string(i)) == "hyperv"
|
||||
}
|
||||
|
||||
// IsProcess indicates the use of process isolation
|
||||
func (i Isolation) IsProcess() bool {
|
||||
return strings.ToLower(string(i)) == "process"
|
||||
}
|
||||
|
||||
const (
|
||||
// IsolationEmpty is unspecified (same behavior as default)
|
||||
IsolationEmpty = Isolation("")
|
||||
// IsolationDefault is the default isolation mode on current daemon
|
||||
IsolationDefault = Isolation("default")
|
||||
// IsolationProcess is process isolation mode
|
||||
IsolationProcess = Isolation("process")
|
||||
// IsolationHyperV is HyperV isolation mode
|
||||
IsolationHyperV = Isolation("hyperv")
|
||||
)
|
||||
|
||||
// IpcMode represents the container ipc stack.
|
||||
type IpcMode string
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IsBridge indicates whether container uses the bridge network stack
|
||||
// in windows it is given the name NAT
|
||||
func (n NetworkMode) IsBridge() bool {
|
||||
|
@ -21,16 +17,6 @@ func (n NetworkMode) IsUserDefined() bool {
|
|||
return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer()
|
||||
}
|
||||
|
||||
// IsHyperV indicates the use of a Hyper-V partition for isolation
|
||||
func (i Isolation) IsHyperV() bool {
|
||||
return strings.ToLower(string(i)) == "hyperv"
|
||||
}
|
||||
|
||||
// IsProcess indicates the use of process isolation
|
||||
func (i Isolation) IsProcess() bool {
|
||||
return strings.ToLower(string(i)) == "process"
|
||||
}
|
||||
|
||||
// IsValid indicates if an isolation technology is valid
|
||||
func (i Isolation) IsValid() bool {
|
||||
return i.IsDefault() || i.IsHyperV() || i.IsProcess()
|
||||
|
|
|
@ -65,8 +65,9 @@ type ContainerSpec struct {
|
|||
// The format of extra hosts on swarmkit is specified in:
|
||||
// http://man7.org/linux/man-pages/man5/hosts.5.html
|
||||
// IP_address canonical_hostname [aliases...]
|
||||
Hosts []string `json:",omitempty"`
|
||||
DNSConfig *DNSConfig `json:",omitempty"`
|
||||
Secrets []*SecretReference `json:",omitempty"`
|
||||
Configs []*ConfigReference `json:",omitempty"`
|
||||
Hosts []string `json:",omitempty"`
|
||||
DNSConfig *DNSConfig `json:",omitempty"`
|
||||
Secrets []*SecretReference `json:",omitempty"`
|
||||
Configs []*ConfigReference `json:",omitempty"`
|
||||
Isolation container.Isolation `json:",omitempty"`
|
||||
}
|
||||
|
|
|
@ -263,6 +263,16 @@ func ValidateLabel(val string) (string, error) {
|
|||
return val, nil
|
||||
}
|
||||
|
||||
// ValidateSingleGenericResource validates that a single entry in the
|
||||
// generic resource list is valid.
|
||||
// i.e 'GPU=UID1' is valid however 'GPU:UID1' or 'UID1' isn't
|
||||
func ValidateSingleGenericResource(val string) (string, error) {
|
||||
if strings.Count(val, "=") < 1 {
|
||||
return "", fmt.Errorf("invalid node-generic-resource format `%s` expected `name=value`", val)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// ParseLink parses and validates the specified string as a link format (name:alias)
|
||||
func ParseLink(val string) (string, string, error) {
|
||||
if val == "" {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !linux,!freebsd freebsd,!cgo solaris,!cgo
|
||||
// +build !linux,!freebsd freebsd,!cgo
|
||||
|
||||
package mount
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ func GetMounts() ([]*Info, error) {
|
|||
}
|
||||
|
||||
// Mounted determines if a specified mountpoint has been mounted.
|
||||
// On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab.
|
||||
// On Linux it looks at /proc/self/mountinfo.
|
||||
func Mounted(mountpoint string) (bool, error) {
|
||||
entries, err := parseMountTable()
|
||||
if err != nil {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo
|
||||
// +build !linux,!freebsd freebsd,!cgo
|
||||
|
||||
package mount
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !windows,!linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo
|
||||
// +build !windows,!linux,!freebsd freebsd,!cgo
|
||||
|
||||
package mount
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !linux,!windows,!solaris
|
||||
// +build !linux,!windows
|
||||
|
||||
package system
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build linux freebsd solaris darwin
|
||||
// +build linux freebsd darwin
|
||||
|
||||
package system
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// +build !windows
|
||||
// +build !solaris !cgo
|
||||
|
||||
package term
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !solaris,!windows
|
||||
// +build !windows
|
||||
|
||||
package term
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
Abhishek Chanda
|
||||
Adam Bell-Hanssen
|
||||
Adnan Khan
|
||||
Adrien Kohlbecker
|
||||
Aldrin Leal
|
||||
Alex Dadgar
|
||||
|
@ -114,6 +115,7 @@ Lucas Clemente
|
|||
Lucas Weiblen
|
||||
Lyon Hill
|
||||
Mantas Matelis
|
||||
Manuel Vogel
|
||||
Marguerite des Trois Maisons
|
||||
Mariusz Borsa
|
||||
Martin Sweeney
|
||||
|
|
|
@ -5,8 +5,8 @@ clone_folder: c:\gopath\src\github.com\fsouza\go-dockerclient
|
|||
environment:
|
||||
GOPATH: c:\gopath
|
||||
matrix:
|
||||
- GOVERSION: 1.8.4
|
||||
- GOVERSION: 1.9.1
|
||||
- GOVERSION: 1.8.5
|
||||
- GOVERSION: 1.9.2
|
||||
install:
|
||||
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
|
||||
- rmdir c:\go /s /q
|
||||
|
|
|
@ -426,8 +426,9 @@ type HealthConfig struct {
|
|||
Test []string `json:"Test,omitempty" yaml:"Test,omitempty" toml:"Test,omitempty"`
|
||||
|
||||
// Zero means to inherit. Durations are expressed as integer nanoseconds.
|
||||
Interval time.Duration `json:"Interval,omitempty" yaml:"Interval,omitempty" toml:"Interval,omitempty"` // Interval is the time to wait between checks.
|
||||
Timeout time.Duration `json:"Timeout,omitempty" yaml:"Timeout,omitempty" toml:"Timeout,omitempty"` // Timeout is the time to wait before considering the check to have hung.
|
||||
Interval time.Duration `json:"Interval,omitempty" yaml:"Interval,omitempty" toml:"Interval,omitempty"` // Interval is the time to wait between checks.
|
||||
Timeout time.Duration `json:"Timeout,omitempty" yaml:"Timeout,omitempty" toml:"Timeout,omitempty"` // Timeout is the time to wait before considering the check to have hung.
|
||||
StartPeriod time.Duration `json:"StartPeriod,omitempty" yaml:"StartPeriod,omitempty" toml:"StartPeriod,omitempty"` // The start period for the container to initialize before the retries starts to count down.
|
||||
|
||||
// Retries is the number of consecutive failures needed to consider a container as unhealthy.
|
||||
// Zero means inherit.
|
||||
|
@ -742,6 +743,7 @@ type HostConfig struct {
|
|||
UTSMode string `json:"UTSMode,omitempty" yaml:"UTSMode,omitempty" toml:"UTSMode,omitempty"`
|
||||
RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty" yaml:"RestartPolicy,omitempty" toml:"RestartPolicy,omitempty"`
|
||||
Devices []Device `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"`
|
||||
DeviceCgroupRules []string `json:"DeviceCgroupRules,omitempty" yaml:"DeviceCgroupRules,omitempty" toml:"DeviceCgroupRules,omitempty"`
|
||||
LogConfig LogConfig `json:"LogConfig,omitempty" yaml:"LogConfig,omitempty" toml:"LogConfig,omitempty"`
|
||||
SecurityOpt []string `json:"SecurityOpt,omitempty" yaml:"SecurityOpt,omitempty" toml:"SecurityOpt,omitempty"`
|
||||
Cgroup string `json:"Cgroup,omitempty" yaml:"Cgroup,omitempty" toml:"Cgroup,omitempty"`
|
||||
|
|
|
@ -473,6 +473,7 @@ type BuildImageOptions struct {
|
|||
NetworkMode string `qs:"networkmode"`
|
||||
InactivityTimeout time.Duration `qs:"-"`
|
||||
CgroupParent string `qs:"cgroupparent"`
|
||||
SecurityOpt []string `qs:"securityopt"`
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright 2017 go-dockerclient 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 docker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// NoSuchConfig is the error returned when a given config does not exist.
|
||||
type NoSuchConfig struct {
|
||||
ID string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (err *NoSuchConfig) Error() string {
|
||||
if err.Err != nil {
|
||||
return err.Err.Error()
|
||||
}
|
||||
return "No such config: " + err.ID
|
||||
}
|
||||
|
||||
// CreateConfigOptions specify parameters to the CreateConfig function.
|
||||
//
|
||||
// See https://goo.gl/KrVjHz for more details.
|
||||
type CreateConfigOptions struct {
|
||||
Auth AuthConfiguration `qs:"-"`
|
||||
swarm.ConfigSpec
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// CreateConfig creates a new config, returning the config instance
|
||||
// or an error in case of failure.
|
||||
//
|
||||
// See https://goo.gl/KrVjHz for more details.
|
||||
func (c *Client) CreateConfig(opts CreateConfigOptions) (*swarm.Config, error) {
|
||||
headers, err := headersWithAuth(opts.Auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := "/configs/create?" + queryString(opts)
|
||||
resp, err := c.do("POST", path, doOptions{
|
||||
headers: headers,
|
||||
data: opts.ConfigSpec,
|
||||
forceJSON: true,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var config swarm.Config
|
||||
if err := json.NewDecoder(resp.Body).Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// RemoveConfigOptions encapsulates options to remove a config.
|
||||
//
|
||||
// See https://goo.gl/Tqrtya for more details.
|
||||
type RemoveConfigOptions struct {
|
||||
ID string `qs:"-"`
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// RemoveConfig removes a config, returning an error in case of failure.
|
||||
//
|
||||
// See https://goo.gl/Tqrtya for more details.
|
||||
func (c *Client) RemoveConfig(opts RemoveConfigOptions) error {
|
||||
path := "/configs/" + opts.ID
|
||||
resp, err := c.do("DELETE", path, doOptions{context: opts.Context})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return &NoSuchConfig{ID: opts.ID}
|
||||
}
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateConfigOptions specify parameters to the UpdateConfig function.
|
||||
//
|
||||
// See https://goo.gl/wu3MmS for more details.
|
||||
type UpdateConfigOptions struct {
|
||||
Auth AuthConfiguration `qs:"-"`
|
||||
swarm.ConfigSpec
|
||||
Context context.Context
|
||||
Version uint64
|
||||
}
|
||||
|
||||
// UpdateConfig updates the config at ID with the options
|
||||
//
|
||||
// Only label can be updated
|
||||
// https://docs.docker.com/engine/api/v1.33/#operation/ConfigUpdate
|
||||
// See https://goo.gl/wu3MmS for more details.
|
||||
func (c *Client) UpdateConfig(id string, opts UpdateConfigOptions) error {
|
||||
headers, err := headersWithAuth(opts.Auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := make(url.Values)
|
||||
params.Set("version", strconv.FormatUint(opts.Version, 10))
|
||||
resp, err := c.do("POST", "/configs/"+id+"/update?"+params.Encode(), doOptions{
|
||||
headers: headers,
|
||||
data: opts.ConfigSpec,
|
||||
forceJSON: true,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return &NoSuchConfig{ID: id}
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// InspectConfig returns information about a config by its ID.
|
||||
//
|
||||
// See https://goo.gl/dHmr75 for more details.
|
||||
func (c *Client) InspectConfig(id string) (*swarm.Config, error) {
|
||||
path := "/configs/" + id
|
||||
resp, err := c.do("GET", path, doOptions{})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return nil, &NoSuchConfig{ID: id}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var config swarm.Config
|
||||
if err := json.NewDecoder(resp.Body).Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// ListConfigsOptions specify parameters to the ListConfigs function.
|
||||
//
|
||||
// See https://goo.gl/DwvNMd for more details.
|
||||
type ListConfigsOptions struct {
|
||||
Filters map[string][]string
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// ListConfigs returns a slice of configs matching the given criteria.
|
||||
//
|
||||
// See https://goo.gl/DwvNMd for more details.
|
||||
func (c *Client) ListConfigs(opts ListConfigsOptions) ([]swarm.Config, error) {
|
||||
path := "/configs?" + queryString(opts)
|
||||
resp, err := c.do("GET", path, doOptions{context: opts.Context})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var configs []swarm.Config
|
||||
if err := json.NewDecoder(resp.Body).Decode(&configs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return configs, nil
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright 2016 go-dockerclient 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 docker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// NoSuchSecret is the error returned when a given secret does not exist.
|
||||
type NoSuchSecret struct {
|
||||
ID string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (err *NoSuchSecret) Error() string {
|
||||
if err.Err != nil {
|
||||
return err.Err.Error()
|
||||
}
|
||||
return "No such secret: " + err.ID
|
||||
}
|
||||
|
||||
// CreateSecretOptions specify parameters to the CreateSecret function.
|
||||
//
|
||||
// See https://goo.gl/KrVjHz for more details.
|
||||
type CreateSecretOptions struct {
|
||||
Auth AuthConfiguration `qs:"-"`
|
||||
swarm.SecretSpec
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// CreateSecret creates a new secret, returning the secret instance
|
||||
// or an error in case of failure.
|
||||
//
|
||||
// See https://goo.gl/KrVjHz for more details.
|
||||
func (c *Client) CreateSecret(opts CreateSecretOptions) (*swarm.Secret, error) {
|
||||
headers, err := headersWithAuth(opts.Auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := "/secrets/create?" + queryString(opts)
|
||||
resp, err := c.do("POST", path, doOptions{
|
||||
headers: headers,
|
||||
data: opts.SecretSpec,
|
||||
forceJSON: true,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var secret swarm.Secret
|
||||
if err := json.NewDecoder(resp.Body).Decode(&secret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &secret, nil
|
||||
}
|
||||
|
||||
// RemoveSecretOptions encapsulates options to remove a secret.
|
||||
//
|
||||
// See https://goo.gl/Tqrtya for more details.
|
||||
type RemoveSecretOptions struct {
|
||||
ID string `qs:"-"`
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// RemoveSecret removes a secret, returning an error in case of failure.
|
||||
//
|
||||
// See https://goo.gl/Tqrtya for more details.
|
||||
func (c *Client) RemoveSecret(opts RemoveSecretOptions) error {
|
||||
path := "/secrets/" + opts.ID
|
||||
resp, err := c.do("DELETE", path, doOptions{context: opts.Context})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return &NoSuchSecret{ID: opts.ID}
|
||||
}
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateSecretOptions specify parameters to the UpdateSecret function.
|
||||
//
|
||||
// Only label can be updated
|
||||
// See https://docs.docker.com/engine/api/v1.33/#operation/SecretUpdate
|
||||
// See https://goo.gl/wu3MmS for more details.
|
||||
type UpdateSecretOptions struct {
|
||||
Auth AuthConfiguration `qs:"-"`
|
||||
swarm.SecretSpec
|
||||
Context context.Context
|
||||
Version uint64
|
||||
}
|
||||
|
||||
// UpdateSecret updates the secret at ID with the options
|
||||
//
|
||||
// See https://goo.gl/wu3MmS for more details.
|
||||
func (c *Client) UpdateSecret(id string, opts UpdateSecretOptions) error {
|
||||
headers, err := headersWithAuth(opts.Auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := make(url.Values)
|
||||
params.Set("version", strconv.FormatUint(opts.Version, 10))
|
||||
resp, err := c.do("POST", "/secrets/"+id+"/update?"+params.Encode(), doOptions{
|
||||
headers: headers,
|
||||
data: opts.SecretSpec,
|
||||
forceJSON: true,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return &NoSuchSecret{ID: id}
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// InspectSecret returns information about a secret by its ID.
|
||||
//
|
||||
// See https://goo.gl/dHmr75 for more details.
|
||||
func (c *Client) InspectSecret(id string) (*swarm.Secret, error) {
|
||||
path := "/secrets/" + id
|
||||
resp, err := c.do("GET", path, doOptions{})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return nil, &NoSuchSecret{ID: id}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var secret swarm.Secret
|
||||
if err := json.NewDecoder(resp.Body).Decode(&secret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &secret, nil
|
||||
}
|
||||
|
||||
// ListSecretsOptions specify parameters to the ListSecrets function.
|
||||
//
|
||||
// See https://goo.gl/DwvNMd for more details.
|
||||
type ListSecretsOptions struct {
|
||||
Filters map[string][]string
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// ListSecrets returns a slice of secrets matching the given criteria.
|
||||
//
|
||||
// See https://goo.gl/DwvNMd for more details.
|
||||
func (c *Client) ListSecrets(opts ListSecretsOptions) ([]swarm.Secret, error) {
|
||||
path := "/secrets?" + queryString(opts)
|
||||
resp, err := c.do("GET", path, doOptions{context: opts.Context})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var secrets []swarm.Secret
|
||||
if err := json.NewDecoder(resp.Body).Decode(&secrets); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return secrets, nil
|
||||
}
|
|
@ -118,15 +118,17 @@ func Wrap(e interface{}, skip int) *Error {
|
|||
// 1 from its caller, etc.
|
||||
func WrapPrefix(e interface{}, prefix string, skip int) *Error {
|
||||
|
||||
err := Wrap(e, skip)
|
||||
err := Wrap(e, 1+skip)
|
||||
|
||||
if err.prefix != "" {
|
||||
err.prefix = fmt.Sprintf("%s: %s", prefix, err.prefix)
|
||||
} else {
|
||||
err.prefix = prefix
|
||||
prefix = fmt.Sprintf("%s: %s", prefix, err.prefix)
|
||||
}
|
||||
|
||||
return err
|
||||
return &Error{
|
||||
Err: err.Err,
|
||||
stack: err.stack,
|
||||
prefix: prefix,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ type SimpleSchema struct {
|
|||
Items *Items `json:"items,omitempty"`
|
||||
CollectionFormat string `json:"collectionFormat,omitempty"`
|
||||
Default interface{} `json:"default,omitempty"`
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
}
|
||||
|
||||
func (s *SimpleSchema) TypeName() string {
|
||||
|
|
|
@ -381,7 +381,7 @@ func (c *controlConn) HandleError(conn *Conn, err error, closed bool) {
|
|||
return
|
||||
}
|
||||
|
||||
c.reconnect(true)
|
||||
c.reconnect(false)
|
||||
}
|
||||
|
||||
func (c *controlConn) getConn() *connHost {
|
||||
|
|
|
@ -876,7 +876,7 @@ func (f *framer) parsePreparedMetadata() preparedMetadata {
|
|||
}
|
||||
|
||||
if meta.flags&flagHasMorePages == flagHasMorePages {
|
||||
meta.pagingState = f.readBytes()
|
||||
meta.pagingState = copyBytes(f.readBytes())
|
||||
}
|
||||
|
||||
if meta.flags&flagNoMetaData == flagNoMetaData {
|
||||
|
@ -961,7 +961,7 @@ func (f *framer) parseResultMetadata() resultMetadata {
|
|||
meta.actualColCount = meta.colCount
|
||||
|
||||
if meta.flags&flagHasMorePages == flagHasMorePages {
|
||||
meta.pagingState = f.readBytes()
|
||||
meta.pagingState = copyBytes(f.readBytes())
|
||||
}
|
||||
|
||||
if meta.flags&flagNoMetaData == flagNoMetaData {
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright 2017 The go-github 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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// AdminStats represents a variety of stats of a Github Enterprise
|
||||
// installation.
|
||||
type AdminStats struct {
|
||||
Issues *IssueStats `json:"issues,omitempty"`
|
||||
Hooks *HookStats `json:"hooks,omitempty"`
|
||||
Milestones *MilestoneStats `json:"milestones,omitempty"`
|
||||
Orgs *OrgStats `json:"orgs,omitempty"`
|
||||
Comments *CommentStats `json:"comments,omitempty"`
|
||||
Pages *PageStats `json:"pages,omitempty"`
|
||||
Users *UserStats `json:"users,omitempty"`
|
||||
Gists *GistStats `json:"gists,omitempty"`
|
||||
Pulls *PullStats `json:"pulls,omitempty"`
|
||||
Repos *RepoStats `json:"repos,omitempty"`
|
||||
}
|
||||
|
||||
func (s AdminStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// IssueStats represents the number of total, open and closed issues.
|
||||
type IssueStats struct {
|
||||
TotalIssues *int `json:"total_issues,omitempty"`
|
||||
OpenIssues *int `json:"open_issues,omitempty"`
|
||||
ClosedIssues *int `json:"closed_issues,omitempty"`
|
||||
}
|
||||
|
||||
func (s IssueStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// HookStats represents the number of total, active and inactive hooks.
|
||||
type HookStats struct {
|
||||
TotalHooks *int `json:"total_hooks,omitempty"`
|
||||
ActiveHooks *int `json:"active_hooks,omitempty"`
|
||||
InactiveHooks *int `json:"inactive_hooks,omitempty"`
|
||||
}
|
||||
|
||||
func (s HookStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// MilestoneStats represents the number of total, open and close milestones.
|
||||
type MilestoneStats struct {
|
||||
TotalMilestones *int `json:"total_milestones,omitempty"`
|
||||
OpenMilestones *int `json:"open_milestones,omitempty"`
|
||||
ClosedMilestones *int `json:"closed_milestones,omitempty"`
|
||||
}
|
||||
|
||||
func (s MilestoneStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// OrgStats represents the number of total, disabled organizations and the team
|
||||
// and team member count.
|
||||
type OrgStats struct {
|
||||
TotalOrgs *int `json:"total_orgs,omitempty"`
|
||||
DisabledOrgs *int `json:"disabled_orgs,omitempty"`
|
||||
TotalTeams *int `json:"total_teams,omitempty"`
|
||||
TotalTeamMembers *int `json:"total_team_members,omitempty"`
|
||||
}
|
||||
|
||||
func (s OrgStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// CommentStats represents the number of total comments on commits, gists, issues
|
||||
// and pull requests.
|
||||
type CommentStats struct {
|
||||
TotalCommitComments *int `json:"total_commit_comments,omitempty"`
|
||||
TotalGistComments *int `json:"total_gist_comments,omitempty"`
|
||||
TotalIssueComments *int `json:"total_issue_comments,omitempty"`
|
||||
TotalPullRequestComments *int `json:"total_pull_request_comments,omitempty"`
|
||||
}
|
||||
|
||||
func (s CommentStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// PageStats represents the total number of github pages.
|
||||
type PageStats struct {
|
||||
TotalPages *int `json:"total_pages,omitempty"`
|
||||
}
|
||||
|
||||
func (s PageStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// UserStats represents the number of total, admin and suspended users.
|
||||
type UserStats struct {
|
||||
TotalUsers *int `json:"total_users,omitempty"`
|
||||
AdminUsers *int `json:"admin_users,omitempty"`
|
||||
SuspendedUsers *int `json:"suspended_users,omitempty"`
|
||||
}
|
||||
|
||||
func (s UserStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
//GistStats represents the number of total, private and public gists.
|
||||
type GistStats struct {
|
||||
TotalGists *int `json:"total_gists,omitempty"`
|
||||
PrivateGists *int `json:"private_gists,omitempty"`
|
||||
PublicGists *int `json:"public_gists,omitempty"`
|
||||
}
|
||||
|
||||
func (s GistStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// PullStats represents the number of total, merged, mergable and unmergeable
|
||||
// pull-requests.
|
||||
type PullStats struct {
|
||||
TotalPulls *int `json:"total_pulls,omitempty"`
|
||||
MergedPulls *int `json:"merged_pulls,omitempty"`
|
||||
MergablePulls *int `json:"mergeable_pulls,omitempty"`
|
||||
UnmergablePulls *int `json:"unmergeable_pulls,omitempty"`
|
||||
}
|
||||
|
||||
func (s PullStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// RepoStats represents the number of total, root, fork, organization repositories
|
||||
// together with the total number of pushes and wikis.
|
||||
type RepoStats struct {
|
||||
TotalRepos *int `json:"total_repos,omitempty"`
|
||||
RootRepos *int `json:"root_repos,omitempty"`
|
||||
ForkRepos *int `json:"fork_repos,omitempty"`
|
||||
OrgRepos *int `json:"org_repos,omitempty"`
|
||||
TotalPushes *int `json:"total_pushes,omitempty"`
|
||||
TotalWikis *int `json:"total_wikis,omitempty"`
|
||||
}
|
||||
|
||||
func (s RepoStats) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// GetAdminStats returns a variety of metrics about a Github Enterprise
|
||||
// installation.
|
||||
//
|
||||
// Please note that this is only available to site administrators,
|
||||
// otherwise it will error with a 404 not found (instead of 401 or 403).
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/enterprise-admin/admin_stats/
|
||||
func (s *AdminService) GetAdminStats(ctx context.Context) (*AdminStats, *Response, error) {
|
||||
u := fmt.Sprintf("enterprise/stats/all")
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
m := new(AdminStats)
|
||||
resp, err := s.client.Do(ctx, req, m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, nil
|
||||
}
|
|
@ -5,7 +5,11 @@
|
|||
|
||||
package github
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AppsService provides access to the installation related functions
|
||||
// in the GitHub API.
|
||||
|
@ -13,6 +17,57 @@ import "context"
|
|||
// GitHub API docs: https://developer.github.com/v3/apps/
|
||||
type AppsService service
|
||||
|
||||
// App represents a GitHub App.
|
||||
type App struct {
|
||||
ID *int `json:"id,omitempty"`
|
||||
Owner *User `json:"owner,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
ExternalURL *string `json:"external_url,omitempty"`
|
||||
HTMLURL *string `json:"html_url,omitempty"`
|
||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
||||
// InstallationToken represents an installation token.
|
||||
type InstallationToken struct {
|
||||
Token *string `json:"token,omitempty"`
|
||||
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
||||
}
|
||||
|
||||
// Get a single GitHub App. Passing the empty string will get
|
||||
// the authenticated GitHub App.
|
||||
//
|
||||
// Note: appSlug is just the URL-friendly name of your GitHub App.
|
||||
// You can find this on the settings page for your GitHub App
|
||||
// (e.g., https://github.com/settings/apps/:app_slug).
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-github-app
|
||||
func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response, error) {
|
||||
var u string
|
||||
if appSlug != "" {
|
||||
u = fmt.Sprintf("apps/%v", appSlug)
|
||||
} else {
|
||||
u = "app"
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview)
|
||||
|
||||
app := new(App)
|
||||
resp, err := s.client.Do(ctx, req, app)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return app, resp, nil
|
||||
}
|
||||
|
||||
// ListInstallations lists the installations that the current GitHub App has.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#find-installations
|
||||
|
@ -38,3 +93,77 @@ func (s *AppsService) ListInstallations(ctx context.Context, opt *ListOptions) (
|
|||
|
||||
return i, resp, nil
|
||||
}
|
||||
|
||||
// GetInstallation returns the specified installation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-installation
|
||||
func (s *AppsService) GetInstallation(ctx context.Context, id int) (*Installation, *Response, error) {
|
||||
u := fmt.Sprintf("app/installations/%v", id)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview)
|
||||
|
||||
i := new(Installation)
|
||||
resp, err := s.client.Do(ctx, req, i)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return i, resp, nil
|
||||
}
|
||||
|
||||
// ListUserInstallations lists installations that are accessible to the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#list-installations-for-user
|
||||
func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) {
|
||||
u, err := addOptions("user/installations", opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview)
|
||||
|
||||
var i struct {
|
||||
Installations []*Installation `json:"installations"`
|
||||
}
|
||||
resp, err := s.client.Do(ctx, req, &i)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return i.Installations, resp, nil
|
||||
}
|
||||
|
||||
// CreateInstallationToken creates a new installation token.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token
|
||||
func (s *AppsService) CreateInstallationToken(ctx context.Context, id int) (*InstallationToken, *Response, error) {
|
||||
u := fmt.Sprintf("installations/%v/access_tokens", id)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview)
|
||||
|
||||
t := new(InstallationToken)
|
||||
resp, err := s.client.Do(ctx, req, t)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return t, resp, nil
|
||||
}
|
||||
|
|
|
@ -51,6 +51,33 @@ func (s *AppsService) ListRepos(ctx context.Context, opt *ListOptions) ([]*Repos
|
|||
return r.Repositories, resp, nil
|
||||
}
|
||||
|
||||
// ListUserRepos lists repositories that are accessible
|
||||
// to the authenticated user for an installation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories-accessible-to-the-user-for-an-installation
|
||||
func (s *AppsService) ListUserRepos(ctx context.Context, id int, opt *ListOptions) ([]*Repository, *Response, error) {
|
||||
u := fmt.Sprintf("user/installations/%v/repositories", id)
|
||||
u, err := addOptions(u, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var r struct {
|
||||
Repositories []*Repository `json:"repositories"`
|
||||
}
|
||||
resp, err := s.client.Do(ctx, req, &r)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return r.Repositories, resp, nil
|
||||
}
|
||||
|
||||
// AddRepository adds a single repository to an installation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/installations/#add-repository-to-installation
|
||||
|
|
|
@ -36,6 +36,62 @@ func (a *APIMeta) GetVerifiablePasswordAuthentication() bool {
|
|||
return *a.VerifiablePasswordAuthentication
|
||||
}
|
||||
|
||||
// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
|
||||
func (a *App) GetCreatedAt() time.Time {
|
||||
if a == nil || a.CreatedAt == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return *a.CreatedAt
|
||||
}
|
||||
|
||||
// GetDescription returns the Description field if it's non-nil, zero value otherwise.
|
||||
func (a *App) GetDescription() string {
|
||||
if a == nil || a.Description == nil {
|
||||
return ""
|
||||
}
|
||||
return *a.Description
|
||||
}
|
||||
|
||||
// GetExternalURL returns the ExternalURL field if it's non-nil, zero value otherwise.
|
||||
func (a *App) GetExternalURL() string {
|
||||
if a == nil || a.ExternalURL == nil {
|
||||
return ""
|
||||
}
|
||||
return *a.ExternalURL
|
||||
}
|
||||
|
||||
// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise.
|
||||
func (a *App) GetHTMLURL() string {
|
||||
if a == nil || a.HTMLURL == nil {
|
||||
return ""
|
||||
}
|
||||
return *a.HTMLURL
|
||||
}
|
||||
|
||||
// GetID returns the ID field if it's non-nil, zero value otherwise.
|
||||
func (a *App) GetID() int {
|
||||
if a == nil || a.ID == nil {
|
||||
return 0
|
||||
}
|
||||
return *a.ID
|
||||
}
|
||||
|
||||
// GetName returns the Name field if it's non-nil, zero value otherwise.
|
||||
func (a *App) GetName() string {
|
||||
if a == nil || a.Name == nil {
|
||||
return ""
|
||||
}
|
||||
return *a.Name
|
||||
}
|
||||
|
||||
// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
|
||||
func (a *App) GetUpdatedAt() time.Time {
|
||||
if a == nil || a.UpdatedAt == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return *a.UpdatedAt
|
||||
}
|
||||
|
||||
// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
|
||||
func (a *Authorization) GetCreatedAt() Timestamp {
|
||||
if a == nil || a.CreatedAt == nil {
|
||||
|
@ -388,6 +444,38 @@ func (c *CombinedStatus) GetTotalCount() int {
|
|||
return *c.TotalCount
|
||||
}
|
||||
|
||||
// GetTotalCommitComments returns the TotalCommitComments field if it's non-nil, zero value otherwise.
|
||||
func (c *CommentStats) GetTotalCommitComments() int {
|
||||
if c == nil || c.TotalCommitComments == nil {
|
||||
return 0
|
||||
}
|
||||
return *c.TotalCommitComments
|
||||
}
|
||||
|
||||
// GetTotalGistComments returns the TotalGistComments field if it's non-nil, zero value otherwise.
|
||||
func (c *CommentStats) GetTotalGistComments() int {
|
||||
if c == nil || c.TotalGistComments == nil {
|
||||
return 0
|
||||
}
|
||||
return *c.TotalGistComments
|
||||
}
|
||||
|
||||
// GetTotalIssueComments returns the TotalIssueComments field if it's non-nil, zero value otherwise.
|
||||
func (c *CommentStats) GetTotalIssueComments() int {
|
||||
if c == nil || c.TotalIssueComments == nil {
|
||||
return 0
|
||||
}
|
||||
return *c.TotalIssueComments
|
||||
}
|
||||
|
||||
// GetTotalPullRequestComments returns the TotalPullRequestComments field if it's non-nil, zero value otherwise.
|
||||
func (c *CommentStats) GetTotalPullRequestComments() int {
|
||||
if c == nil || c.TotalPullRequestComments == nil {
|
||||
return 0
|
||||
}
|
||||
return *c.TotalPullRequestComments
|
||||
}
|
||||
|
||||
// GetCommentCount returns the CommentCount field if it's non-nil, zero value otherwise.
|
||||
func (c *Commit) GetCommentCount() int {
|
||||
if c == nil || c.CommentCount == nil {
|
||||
|
@ -1588,6 +1676,30 @@ func (g *GistFork) GetURL() string {
|
|||
return *g.URL
|
||||
}
|
||||
|
||||
// GetPrivateGists returns the PrivateGists field if it's non-nil, zero value otherwise.
|
||||
func (g *GistStats) GetPrivateGists() int {
|
||||
if g == nil || g.PrivateGists == nil {
|
||||
return 0
|
||||
}
|
||||
return *g.PrivateGists
|
||||
}
|
||||
|
||||
// GetPublicGists returns the PublicGists field if it's non-nil, zero value otherwise.
|
||||
func (g *GistStats) GetPublicGists() int {
|
||||
if g == nil || g.PublicGists == nil {
|
||||
return 0
|
||||
}
|
||||
return *g.PublicGists
|
||||
}
|
||||
|
||||
// GetTotalGists returns the TotalGists field if it's non-nil, zero value otherwise.
|
||||
func (g *GistStats) GetTotalGists() int {
|
||||
if g == nil || g.TotalGists == nil {
|
||||
return 0
|
||||
}
|
||||
return *g.TotalGists
|
||||
}
|
||||
|
||||
// GetName returns the Name field if it's non-nil, zero value otherwise.
|
||||
func (g *Gitignore) GetName() string {
|
||||
if g == nil || g.Name == nil {
|
||||
|
@ -1804,6 +1916,30 @@ func (h *Hook) GetURL() string {
|
|||
return *h.URL
|
||||
}
|
||||
|
||||
// GetActiveHooks returns the ActiveHooks field if it's non-nil, zero value otherwise.
|
||||
func (h *HookStats) GetActiveHooks() int {
|
||||
if h == nil || h.ActiveHooks == nil {
|
||||
return 0
|
||||
}
|
||||
return *h.ActiveHooks
|
||||
}
|
||||
|
||||
// GetInactiveHooks returns the InactiveHooks field if it's non-nil, zero value otherwise.
|
||||
func (h *HookStats) GetInactiveHooks() int {
|
||||
if h == nil || h.InactiveHooks == nil {
|
||||
return 0
|
||||
}
|
||||
return *h.InactiveHooks
|
||||
}
|
||||
|
||||
// GetTotalHooks returns the TotalHooks field if it's non-nil, zero value otherwise.
|
||||
func (h *HookStats) GetTotalHooks() int {
|
||||
if h == nil || h.TotalHooks == nil {
|
||||
return 0
|
||||
}
|
||||
return *h.TotalHooks
|
||||
}
|
||||
|
||||
// GetAuthorsCount returns the AuthorsCount field if it's non-nil, zero value otherwise.
|
||||
func (i *Import) GetAuthorsCount() int {
|
||||
if i == nil || i.AuthorsCount == nil {
|
||||
|
@ -2036,6 +2172,22 @@ func (i *InstallationRepositoriesEvent) GetRepositorySelection() string {
|
|||
return *i.RepositorySelection
|
||||
}
|
||||
|
||||
// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise.
|
||||
func (i *InstallationToken) GetExpiresAt() time.Time {
|
||||
if i == nil || i.ExpiresAt == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return *i.ExpiresAt
|
||||
}
|
||||
|
||||
// GetToken returns the Token field if it's non-nil, zero value otherwise.
|
||||
func (i *InstallationToken) GetToken() string {
|
||||
if i == nil || i.Token == nil {
|
||||
return ""
|
||||
}
|
||||
return *i.Token
|
||||
}
|
||||
|
||||
// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
|
||||
func (i *Invitation) GetCreatedAt() time.Time {
|
||||
if i == nil || i.CreatedAt == nil {
|
||||
|
@ -2388,6 +2540,30 @@ func (i *IssuesSearchResult) GetTotal() int {
|
|||
return *i.Total
|
||||
}
|
||||
|
||||
// GetClosedIssues returns the ClosedIssues field if it's non-nil, zero value otherwise.
|
||||
func (i *IssueStats) GetClosedIssues() int {
|
||||
if i == nil || i.ClosedIssues == nil {
|
||||
return 0
|
||||
}
|
||||
return *i.ClosedIssues
|
||||
}
|
||||
|
||||
// GetOpenIssues returns the OpenIssues field if it's non-nil, zero value otherwise.
|
||||
func (i *IssueStats) GetOpenIssues() int {
|
||||
if i == nil || i.OpenIssues == nil {
|
||||
return 0
|
||||
}
|
||||
return *i.OpenIssues
|
||||
}
|
||||
|
||||
// GetTotalIssues returns the TotalIssues field if it's non-nil, zero value otherwise.
|
||||
func (i *IssueStats) GetTotalIssues() int {
|
||||
if i == nil || i.TotalIssues == nil {
|
||||
return 0
|
||||
}
|
||||
return *i.TotalIssues
|
||||
}
|
||||
|
||||
// GetID returns the ID field if it's non-nil, zero value otherwise.
|
||||
func (k *Key) GetID() int {
|
||||
if k == nil || k.ID == nil {
|
||||
|
@ -2900,6 +3076,30 @@ func (m *MilestoneEvent) GetAction() string {
|
|||
return *m.Action
|
||||
}
|
||||
|
||||
// GetClosedMilestones returns the ClosedMilestones field if it's non-nil, zero value otherwise.
|
||||
func (m *MilestoneStats) GetClosedMilestones() int {
|
||||
if m == nil || m.ClosedMilestones == nil {
|
||||
return 0
|
||||
}
|
||||
return *m.ClosedMilestones
|
||||
}
|
||||
|
||||
// GetOpenMilestones returns the OpenMilestones field if it's non-nil, zero value otherwise.
|
||||
func (m *MilestoneStats) GetOpenMilestones() int {
|
||||
if m == nil || m.OpenMilestones == nil {
|
||||
return 0
|
||||
}
|
||||
return *m.OpenMilestones
|
||||
}
|
||||
|
||||
// GetTotalMilestones returns the TotalMilestones field if it's non-nil, zero value otherwise.
|
||||
func (m *MilestoneStats) GetTotalMilestones() int {
|
||||
if m == nil || m.TotalMilestones == nil {
|
||||
return 0
|
||||
}
|
||||
return *m.TotalMilestones
|
||||
}
|
||||
|
||||
// GetBase returns the Base field if it's non-nil, zero value otherwise.
|
||||
func (n *NewPullRequest) GetBase() string {
|
||||
if n == nil || n.Base == nil {
|
||||
|
@ -2948,6 +3148,46 @@ func (n *NewPullRequest) GetTitle() string {
|
|||
return *n.Title
|
||||
}
|
||||
|
||||
// GetDescription returns the Description field if it's non-nil, zero value otherwise.
|
||||
func (n *NewTeam) GetDescription() string {
|
||||
if n == nil || n.Description == nil {
|
||||
return ""
|
||||
}
|
||||
return *n.Description
|
||||
}
|
||||
|
||||
// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise.
|
||||
func (n *NewTeam) GetLDAPDN() string {
|
||||
if n == nil || n.LDAPDN == nil {
|
||||
return ""
|
||||
}
|
||||
return *n.LDAPDN
|
||||
}
|
||||
|
||||
// GetParentTeamID returns the ParentTeamID field if it's non-nil, zero value otherwise.
|
||||
func (n *NewTeam) GetParentTeamID() int {
|
||||
if n == nil || n.ParentTeamID == nil {
|
||||
return 0
|
||||
}
|
||||
return *n.ParentTeamID
|
||||
}
|
||||
|
||||
// GetPermission returns the Permission field if it's non-nil, zero value otherwise.
|
||||
func (n *NewTeam) GetPermission() string {
|
||||
if n == nil || n.Permission == nil {
|
||||
return ""
|
||||
}
|
||||
return *n.Permission
|
||||
}
|
||||
|
||||
// GetPrivacy returns the Privacy field if it's non-nil, zero value otherwise.
|
||||
func (n *NewTeam) GetPrivacy() string {
|
||||
if n == nil || n.Privacy == nil {
|
||||
return ""
|
||||
}
|
||||
return *n.Privacy
|
||||
}
|
||||
|
||||
// GetID returns the ID field if it's non-nil, zero value otherwise.
|
||||
func (n *Notification) GetID() string {
|
||||
if n == nil || n.ID == nil {
|
||||
|
@ -3284,6 +3524,38 @@ func (o *OrgBlockEvent) GetAction() string {
|
|||
return *o.Action
|
||||
}
|
||||
|
||||
// GetDisabledOrgs returns the DisabledOrgs field if it's non-nil, zero value otherwise.
|
||||
func (o *OrgStats) GetDisabledOrgs() int {
|
||||
if o == nil || o.DisabledOrgs == nil {
|
||||
return 0
|
||||
}
|
||||
return *o.DisabledOrgs
|
||||
}
|
||||
|
||||
// GetTotalOrgs returns the TotalOrgs field if it's non-nil, zero value otherwise.
|
||||
func (o *OrgStats) GetTotalOrgs() int {
|
||||
if o == nil || o.TotalOrgs == nil {
|
||||
return 0
|
||||
}
|
||||
return *o.TotalOrgs
|
||||
}
|
||||
|
||||
// GetTotalTeamMembers returns the TotalTeamMembers field if it's non-nil, zero value otherwise.
|
||||
func (o *OrgStats) GetTotalTeamMembers() int {
|
||||
if o == nil || o.TotalTeamMembers == nil {
|
||||
return 0
|
||||
}
|
||||
return *o.TotalTeamMembers
|
||||
}
|
||||
|
||||
// GetTotalTeams returns the TotalTeams field if it's non-nil, zero value otherwise.
|
||||
func (o *OrgStats) GetTotalTeams() int {
|
||||
if o == nil || o.TotalTeams == nil {
|
||||
return 0
|
||||
}
|
||||
return *o.TotalTeams
|
||||
}
|
||||
|
||||
// GetAction returns the Action field if it's non-nil, zero value otherwise.
|
||||
func (p *Page) GetAction() string {
|
||||
if p == nil || p.Action == nil {
|
||||
|
@ -3436,6 +3708,14 @@ func (p *PagesError) GetMessage() string {
|
|||
return *p.Message
|
||||
}
|
||||
|
||||
// GetTotalPages returns the TotalPages field if it's non-nil, zero value otherwise.
|
||||
func (p *PageStats) GetTotalPages() int {
|
||||
if p == nil || p.TotalPages == nil {
|
||||
return 0
|
||||
}
|
||||
return *p.TotalPages
|
||||
}
|
||||
|
||||
// GetHookID returns the HookID field if it's non-nil, zero value otherwise.
|
||||
func (p *PingEvent) GetHookID() int {
|
||||
if p == nil || p.HookID == nil {
|
||||
|
@ -4260,6 +4540,38 @@ func (p *pullRequestUpdate) GetTitle() string {
|
|||
return *p.Title
|
||||
}
|
||||
|
||||
// GetMergablePulls returns the MergablePulls field if it's non-nil, zero value otherwise.
|
||||
func (p *PullStats) GetMergablePulls() int {
|
||||
if p == nil || p.MergablePulls == nil {
|
||||
return 0
|
||||
}
|
||||
return *p.MergablePulls
|
||||
}
|
||||
|
||||
// GetMergedPulls returns the MergedPulls field if it's non-nil, zero value otherwise.
|
||||
func (p *PullStats) GetMergedPulls() int {
|
||||
if p == nil || p.MergedPulls == nil {
|
||||
return 0
|
||||
}
|
||||
return *p.MergedPulls
|
||||
}
|
||||
|
||||
// GetTotalPulls returns the TotalPulls field if it's non-nil, zero value otherwise.
|
||||
func (p *PullStats) GetTotalPulls() int {
|
||||
if p == nil || p.TotalPulls == nil {
|
||||
return 0
|
||||
}
|
||||
return *p.TotalPulls
|
||||
}
|
||||
|
||||
// GetUnmergablePulls returns the UnmergablePulls field if it's non-nil, zero value otherwise.
|
||||
func (p *PullStats) GetUnmergablePulls() int {
|
||||
if p == nil || p.UnmergablePulls == nil {
|
||||
return 0
|
||||
}
|
||||
return *p.UnmergablePulls
|
||||
}
|
||||
|
||||
// GetCommits returns the Commits field if it's non-nil, zero value otherwise.
|
||||
func (p *PunchCard) GetCommits() int {
|
||||
if p == nil || p.Commits == nil {
|
||||
|
@ -6044,6 +6356,54 @@ func (r *RepositoryTag) GetZipballURL() string {
|
|||
return *r.ZipballURL
|
||||
}
|
||||
|
||||
// GetForkRepos returns the ForkRepos field if it's non-nil, zero value otherwise.
|
||||
func (r *RepoStats) GetForkRepos() int {
|
||||
if r == nil || r.ForkRepos == nil {
|
||||
return 0
|
||||
}
|
||||
return *r.ForkRepos
|
||||
}
|
||||
|
||||
// GetOrgRepos returns the OrgRepos field if it's non-nil, zero value otherwise.
|
||||
func (r *RepoStats) GetOrgRepos() int {
|
||||
if r == nil || r.OrgRepos == nil {
|
||||
return 0
|
||||
}
|
||||
return *r.OrgRepos
|
||||
}
|
||||
|
||||
// GetRootRepos returns the RootRepos field if it's non-nil, zero value otherwise.
|
||||
func (r *RepoStats) GetRootRepos() int {
|
||||
if r == nil || r.RootRepos == nil {
|
||||
return 0
|
||||
}
|
||||
return *r.RootRepos
|
||||
}
|
||||
|
||||
// GetTotalPushes returns the TotalPushes field if it's non-nil, zero value otherwise.
|
||||
func (r *RepoStats) GetTotalPushes() int {
|
||||
if r == nil || r.TotalPushes == nil {
|
||||
return 0
|
||||
}
|
||||
return *r.TotalPushes
|
||||
}
|
||||
|
||||
// GetTotalRepos returns the TotalRepos field if it's non-nil, zero value otherwise.
|
||||
func (r *RepoStats) GetTotalRepos() int {
|
||||
if r == nil || r.TotalRepos == nil {
|
||||
return 0
|
||||
}
|
||||
return *r.TotalRepos
|
||||
}
|
||||
|
||||
// GetTotalWikis returns the TotalWikis field if it's non-nil, zero value otherwise.
|
||||
func (r *RepoStats) GetTotalWikis() int {
|
||||
if r == nil || r.TotalWikis == nil {
|
||||
return 0
|
||||
}
|
||||
return *r.TotalWikis
|
||||
}
|
||||
|
||||
// GetContext returns the Context field if it's non-nil, zero value otherwise.
|
||||
func (r *RepoStatus) GetContext() string {
|
||||
if r == nil || r.Context == nil {
|
||||
|
@ -7340,6 +7700,30 @@ func (u *UsersSearchResult) GetTotal() int {
|
|||
return *u.Total
|
||||
}
|
||||
|
||||
// GetAdminUsers returns the AdminUsers field if it's non-nil, zero value otherwise.
|
||||
func (u *UserStats) GetAdminUsers() int {
|
||||
if u == nil || u.AdminUsers == nil {
|
||||
return 0
|
||||
}
|
||||
return *u.AdminUsers
|
||||
}
|
||||
|
||||
// GetSuspendedUsers returns the SuspendedUsers field if it's non-nil, zero value otherwise.
|
||||
func (u *UserStats) GetSuspendedUsers() int {
|
||||
if u == nil || u.SuspendedUsers == nil {
|
||||
return 0
|
||||
}
|
||||
return *u.SuspendedUsers
|
||||
}
|
||||
|
||||
// GetTotalUsers returns the TotalUsers field if it's non-nil, zero value otherwise.
|
||||
func (u *UserStats) GetTotalUsers() int {
|
||||
if u == nil || u.TotalUsers == nil {
|
||||
return 0
|
||||
}
|
||||
return *u.TotalUsers
|
||||
}
|
||||
|
||||
// GetAction returns the Action field if it's non-nil, zero value otherwise.
|
||||
func (w *WatchEvent) GetAction() string {
|
||||
if w == nil || w.Action == nil {
|
||||
|
|
|
@ -27,7 +27,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
libraryVersion = "13"
|
||||
libraryVersion = "14"
|
||||
defaultBaseURL = "https://api.github.com/"
|
||||
uploadBaseURL = "https://uploads.github.com/"
|
||||
userAgent = "go-github/" + libraryVersion
|
||||
|
@ -102,6 +102,9 @@ const (
|
|||
|
||||
// https://developer.github.com/changes/2017-07-26-team-review-request-thor-preview/
|
||||
mediaTypeTeamReviewPreview = "application/vnd.github.thor-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2017-08-30-preview-nested-teams/
|
||||
mediaTypeNestedTeamsPreview = "application/vnd.github.hellcat-preview+json"
|
||||
)
|
||||
|
||||
// A Client manages communication with the GitHub API.
|
||||
|
@ -235,6 +238,37 @@ func NewClient(httpClient *http.Client) *Client {
|
|||
return c
|
||||
}
|
||||
|
||||
// NewEnterpriseClient returns a new GitHub API client with provided
|
||||
// base URL and upload URL (often the same URL).
|
||||
// If either URL does not have a trailing slash, one is added automatically.
|
||||
// If a nil httpClient is provided, http.DefaultClient will be used.
|
||||
//
|
||||
// Note that NewEnterpriseClient is a convenience helper only;
|
||||
// its behavior is equivalent to using NewClient, followed by setting
|
||||
// the BaseURL and UploadURL fields.
|
||||
func NewEnterpriseClient(baseURL, uploadURL string, httpClient *http.Client) (*Client, error) {
|
||||
baseEndpoint, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !strings.HasSuffix(baseEndpoint.Path, "/") {
|
||||
baseEndpoint.Path += "/"
|
||||
}
|
||||
|
||||
uploadEndpoint, err := url.Parse(uploadURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !strings.HasSuffix(uploadEndpoint.Path, "/") {
|
||||
uploadEndpoint.Path += "/"
|
||||
}
|
||||
|
||||
c := NewClient(httpClient)
|
||||
c.BaseURL = baseEndpoint
|
||||
c.UploadURL = uploadEndpoint
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewRequest creates an API request. A relative URL can be provided in urlStr,
|
||||
// in which case it is resolved relative to the BaseURL of the Client.
|
||||
// Relative URLs should always be specified without a preceding slash. If
|
||||
|
|
|
@ -8,6 +8,7 @@ package github
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -20,11 +21,7 @@ type Team struct {
|
|||
URL *string `json:"url,omitempty"`
|
||||
Slug *string `json:"slug,omitempty"`
|
||||
|
||||
// Permission is deprecated when creating or editing a team in an org
|
||||
// using the new GitHub permission model. It no longer identifies the
|
||||
// permission a team has on its repos, but only specifies the default
|
||||
// permission a repo is initially added with. Avoid confusion by
|
||||
// specifying a permission value when calling AddTeamRepo.
|
||||
// Permission specifies the default permission for repositories owned by the team.
|
||||
Permission *string `json:"permission,omitempty"`
|
||||
|
||||
// Privacy identifies the level of privacy this team should have.
|
||||
|
@ -39,6 +36,7 @@ type Team struct {
|
|||
Organization *Organization `json:"organization,omitempty"`
|
||||
MembersURL *string `json:"members_url,omitempty"`
|
||||
RepositoriesURL *string `json:"repositories_url,omitempty"`
|
||||
Parent *Team `json:"parent,omitempty"`
|
||||
|
||||
// LDAPDN is only available in GitHub Enterprise and when the team
|
||||
// membership is synchronized with LDAP.
|
||||
|
@ -79,6 +77,9 @@ func (s *OrganizationsService) ListTeams(ctx context.Context, org string, opt *L
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
var teams []*Team
|
||||
resp, err := s.client.Do(ctx, req, &teams)
|
||||
if err != nil {
|
||||
|
@ -98,6 +99,9 @@ func (s *OrganizationsService) GetTeam(ctx context.Context, team int) (*Team, *R
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
t := new(Team)
|
||||
resp, err := s.client.Do(ctx, req, t)
|
||||
if err != nil {
|
||||
|
@ -107,16 +111,50 @@ func (s *OrganizationsService) GetTeam(ctx context.Context, team int) (*Team, *R
|
|||
return t, resp, nil
|
||||
}
|
||||
|
||||
// NewTeam represents a team to be created or modified.
|
||||
type NewTeam struct {
|
||||
Name string `json:"name"` // Name of the team. (Required.)
|
||||
Description *string `json:"description,omitempty"`
|
||||
Maintainers []string `json:"maintainers,omitempty"`
|
||||
RepoNames []string `json:"repo_names,omitempty"`
|
||||
ParentTeamID *int `json:"parent_team_id,omitempty"`
|
||||
|
||||
// Deprecated: Permission is deprecated when creating or editing a team in an org
|
||||
// using the new GitHub permission model. It no longer identifies the
|
||||
// permission a team has on its repos, but only specifies the default
|
||||
// permission a repo is initially added with. Avoid confusion by
|
||||
// specifying a permission value when calling AddTeamRepo.
|
||||
Permission *string `json:"permission,omitempty"`
|
||||
|
||||
// Privacy identifies the level of privacy this team should have.
|
||||
// Possible values are:
|
||||
// secret - only visible to organization owners and members of this team
|
||||
// closed - visible to all members of this organization
|
||||
// Default is "secret".
|
||||
Privacy *string `json:"privacy,omitempty"`
|
||||
|
||||
// LDAPDN may be used in GitHub Enterprise when the team membership
|
||||
// is synchronized with LDAP.
|
||||
LDAPDN *string `json:"ldap_dn,omitempty"`
|
||||
}
|
||||
|
||||
func (s NewTeam) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// CreateTeam creates a new team within an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#create-team
|
||||
func (s *OrganizationsService) CreateTeam(ctx context.Context, org string, team *Team) (*Team, *Response, error) {
|
||||
func (s *OrganizationsService) CreateTeam(ctx context.Context, org string, team *NewTeam) (*Team, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/teams", org)
|
||||
req, err := s.client.NewRequest("POST", u, team)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
t := new(Team)
|
||||
resp, err := s.client.Do(ctx, req, t)
|
||||
if err != nil {
|
||||
|
@ -129,13 +167,16 @@ func (s *OrganizationsService) CreateTeam(ctx context.Context, org string, team
|
|||
// EditTeam edits a team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#edit-team
|
||||
func (s *OrganizationsService) EditTeam(ctx context.Context, id int, team *Team) (*Team, *Response, error) {
|
||||
func (s *OrganizationsService) EditTeam(ctx context.Context, id int, team *NewTeam) (*Team, *Response, error) {
|
||||
u := fmt.Sprintf("teams/%v", id)
|
||||
req, err := s.client.NewRequest("PATCH", u, team)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
t := new(Team)
|
||||
resp, err := s.client.Do(ctx, req, t)
|
||||
if err != nil {
|
||||
|
@ -155,6 +196,8 @@ func (s *OrganizationsService) DeleteTeam(ctx context.Context, team int) (*Respo
|
|||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
|
@ -168,6 +211,32 @@ type OrganizationListTeamMembersOptions struct {
|
|||
ListOptions
|
||||
}
|
||||
|
||||
// ListChildTeams lists child teams for a team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-child-teams
|
||||
func (s *OrganizationsService) ListChildTeams(ctx context.Context, teamID int, opt *ListOptions) ([]*Team, *Response, error) {
|
||||
u := fmt.Sprintf("teams/%v/teams", teamID)
|
||||
u, err := addOptions(u, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
var teams []*Team
|
||||
resp, err := s.client.Do(ctx, req, &teams)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return teams, resp, nil
|
||||
}
|
||||
|
||||
// ListTeamMembers lists all of the users who are members of the specified
|
||||
// team.
|
||||
//
|
||||
|
@ -184,6 +253,8 @@ func (s *OrganizationsService) ListTeamMembers(ctx context.Context, team int, op
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
var members []*User
|
||||
resp, err := s.client.Do(ctx, req, &members)
|
||||
if err != nil {
|
||||
|
@ -227,7 +298,8 @@ func (s *OrganizationsService) ListTeamRepos(ctx context.Context, team int, opt
|
|||
}
|
||||
|
||||
// TODO: remove custom Accept header when topics API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeTopicsPreview)
|
||||
headers := []string{mediaTypeTopicsPreview, mediaTypeNestedTeamsPreview}
|
||||
req.Header.Set("Accept", strings.Join(headers, ", "))
|
||||
|
||||
var repos []*Repository
|
||||
resp, err := s.client.Do(ctx, req, &repos)
|
||||
|
@ -250,7 +322,8 @@ func (s *OrganizationsService) IsTeamRepo(ctx context.Context, team int, owner s
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", mediaTypeOrgPermissionRepo)
|
||||
headers := []string{mediaTypeOrgPermissionRepo, mediaTypeNestedTeamsPreview}
|
||||
req.Header.Set("Accept", strings.Join(headers, ", "))
|
||||
|
||||
repository := new(Repository)
|
||||
resp, err := s.client.Do(ctx, req, repository)
|
||||
|
@ -318,6 +391,9 @@ func (s *OrganizationsService) ListUserTeams(ctx context.Context, opt *ListOptio
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
var teams []*Team
|
||||
resp, err := s.client.Do(ctx, req, &teams)
|
||||
if err != nil {
|
||||
|
@ -337,6 +413,8 @@ func (s *OrganizationsService) GetTeamMembership(ctx context.Context, team int,
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
t := new(Membership)
|
||||
resp, err := s.client.Do(ctx, req, t)
|
||||
if err != nil {
|
||||
|
|
|
@ -138,7 +138,7 @@ func (s *PullRequestsService) Get(ctx context.Context, owner string, repo string
|
|||
return pull, resp, nil
|
||||
}
|
||||
|
||||
// GetRaw gets raw (diff or patch) format of a pull request.
|
||||
// GetRaw gets a single pull request in raw (diff or patch) format.
|
||||
func (s *PullRequestsService) GetRaw(ctx context.Context, owner string, repo string, number int, opt RawOptions) (string, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
@ -155,13 +155,13 @@ func (s *PullRequestsService) GetRaw(ctx context.Context, owner string, repo str
|
|||
return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type)
|
||||
}
|
||||
|
||||
ret := new(bytes.Buffer)
|
||||
resp, err := s.client.Do(ctx, req, ret)
|
||||
var buf bytes.Buffer
|
||||
resp, err := s.client.Do(ctx, req, &buf)
|
||||
if err != nil {
|
||||
return "", resp, err
|
||||
}
|
||||
|
||||
return ret.String(), resp, nil
|
||||
return buf.String(), resp, nil
|
||||
}
|
||||
|
||||
// NewPullRequest represents a new pull request to be created.
|
||||
|
|
|
@ -84,5 +84,5 @@ func (s *PullRequestsService) RemoveReviewers(ctx context.Context, owner, repo s
|
|||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeTeamReviewPreview)
|
||||
|
||||
return s.client.Do(ctx, req, reviewers)
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
|
|
@ -481,6 +481,8 @@ func (s *RepositoriesService) ListTeams(ctx context.Context, owner string, repo
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
var teams []*Team
|
||||
resp, err := s.client.Do(ctx, req, &teams)
|
||||
if err != nil {
|
||||
|
|
|
@ -41,6 +41,8 @@ func (s *RepositoriesService) ListCollaborators(ctx context.Context, owner, repo
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
|
||||
|
||||
var users []*User
|
||||
resp, err := s.client.Do(ctx, req, &users)
|
||||
if err != nil {
|
||||
|
|
|
@ -140,10 +140,9 @@ func (s *RepositoriesService) ListCommits(ctx context.Context, owner, repo strin
|
|||
}
|
||||
|
||||
// GetCommit fetches the specified commit, including all details about it.
|
||||
// todo: support media formats - https://github.com/google/go-github/issues/6
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-a-single-commit
|
||||
// See also: https://developer.github.com//v3/git/commits/#get-a-single-commit provides the same functionality
|
||||
// See also: https://developer.github.com/v3/git/commits/#get-a-single-commit provides the same functionality
|
||||
func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha string) (*RepositoryCommit, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha)
|
||||
|
||||
|
@ -164,6 +163,32 @@ func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha st
|
|||
return commit, resp, nil
|
||||
}
|
||||
|
||||
// GetCommitRaw fetches the specified commit in raw (diff or patch) format.
|
||||
func (s *RepositoriesService) GetCommitRaw(ctx context.Context, owner string, repo string, sha string, opt RawOptions) (string, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
switch opt.Type {
|
||||
case Diff:
|
||||
req.Header.Set("Accept", mediaTypeV3Diff)
|
||||
case Patch:
|
||||
req.Header.Set("Accept", mediaTypeV3Patch)
|
||||
default:
|
||||
return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
resp, err := s.client.Do(ctx, req, &buf)
|
||||
if err != nil {
|
||||
return "", resp, err
|
||||
}
|
||||
|
||||
return buf.String(), resp, nil
|
||||
}
|
||||
|
||||
// GetCommitSHA1 gets the SHA-1 of a commit reference. If a last-known SHA1 is
|
||||
// supplied and no new commits have occurred, a 304 Unmodified response is returned.
|
||||
//
|
||||
|
|
|
@ -15,6 +15,7 @@ type AgentCheck struct {
|
|||
Output string
|
||||
ServiceID string
|
||||
ServiceName string
|
||||
Definition HealthCheckDefinition
|
||||
}
|
||||
|
||||
// AgentService represents a service known to the agent
|
||||
|
|
|
@ -42,6 +42,7 @@ type CatalogRegistration struct {
|
|||
Datacenter string
|
||||
Service *AgentService
|
||||
Check *AgentCheck
|
||||
SkipNodeUpdate bool
|
||||
}
|
||||
|
||||
type CatalogDeregistration struct {
|
||||
|
|
|
@ -66,3 +66,41 @@ func (c *Coordinate) Nodes(q *QueryOptions) ([]*CoordinateEntry, *QueryMeta, err
|
|||
}
|
||||
return out, qm, nil
|
||||
}
|
||||
|
||||
// Update inserts or updates the LAN coordinate of a node.
|
||||
func (c *Coordinate) Update(coord *CoordinateEntry, q *WriteOptions) (*WriteMeta, error) {
|
||||
r := c.c.newRequest("PUT", "/v1/coordinate/update")
|
||||
r.setWriteOptions(q)
|
||||
r.obj = coord
|
||||
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{}
|
||||
wm.RequestTime = rtt
|
||||
|
||||
return wm, nil
|
||||
}
|
||||
|
||||
// Node is used to return the coordinates of a single in the LAN pool.
|
||||
func (c *Coordinate) Node(node string, q *QueryOptions) ([]*CoordinateEntry, *QueryMeta, error) {
|
||||
r := c.c.newRequest("GET", "/v1/coordinate/node/"+node)
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out []*CoordinateEntry
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return out, qm, nil
|
||||
}
|
||||
|
|
|
@ -34,6 +34,21 @@ type HealthCheck struct {
|
|||
ServiceID string
|
||||
ServiceName string
|
||||
ServiceTags []string
|
||||
|
||||
Definition HealthCheckDefinition
|
||||
}
|
||||
|
||||
// HealthCheckDefinition is used to store the details about
|
||||
// a health check's execution.
|
||||
type HealthCheckDefinition struct {
|
||||
HTTP string
|
||||
Header map[string][]string
|
||||
Method string
|
||||
TLSSkipVerify bool
|
||||
TCP string
|
||||
Interval ReadableDuration
|
||||
Timeout ReadableDuration
|
||||
DeregisterCriticalServiceAfter ReadableDuration
|
||||
}
|
||||
|
||||
// HealthChecks is a collection of HealthCheck structs.
|
||||
|
|
|
@ -5,6 +5,12 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// minRate is the minimum rate at which we allow an action to be performed
|
||||
// across the whole cluster. The value is once a day: 1 / (1 * time.Day)
|
||||
minRate = 1.0 / 86400
|
||||
)
|
||||
|
||||
// DurationMinusBuffer returns a duration, minus a buffer and jitter
|
||||
// subtracted from the duration. This function is used primarily for
|
||||
// servicing Consul TTL Checks in advance of the TTL.
|
||||
|
@ -43,7 +49,6 @@ func RandomStagger(intv time.Duration) time.Duration {
|
|||
// order to target an aggregate number of actions per second across the whole
|
||||
// cluster.
|
||||
func RateScaledInterval(rate float64, min time.Duration, n int) time.Duration {
|
||||
const minRate = 1 / 86400 // 1/(1 * time.Day)
|
||||
if rate <= minRate {
|
||||
return min
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ must be properly secured to protect this configuration.
|
|||
## Architecture
|
||||
|
||||
The HashiCorp plugin system works by launching subprocesses and communicating
|
||||
over RPC (using standard `net/rpc` or [gRPC](http://www.grpc.io). A single
|
||||
over RPC (using standard `net/rpc` or [gRPC](http://www.grpc.io)). A single
|
||||
connection is made between any plugin and the host process. For net/rpc-based
|
||||
plugins, we use a [connection multiplexing](https://github.com/hashicorp/yamux)
|
||||
library to multiplex any other connections on top. For gRPC-based plugins,
|
||||
|
|
|
@ -606,7 +606,7 @@ func (c *Client) Start() (addr net.Addr, err error) {
|
|||
|
||||
if int(coreProtocol) != CoreProtocolVersion {
|
||||
err = fmt.Errorf("Incompatible core API version with plugin. "+
|
||||
"Plugin version: %s, Ours: %d\n\n"+
|
||||
"Plugin version: %s, Core version: %d\n\n"+
|
||||
"To fix this, the plugin usually only needs to be recompiled.\n"+
|
||||
"Please report this to the plugin author.", parts[0], CoreProtocolVersion)
|
||||
return
|
||||
|
@ -624,7 +624,7 @@ func (c *Client) Start() (addr net.Addr, err error) {
|
|||
// Test the API version
|
||||
if uint(protocol) != c.config.ProtocolVersion {
|
||||
err = fmt.Errorf("Incompatible API version with plugin. "+
|
||||
"Plugin version: %s, Ours: %d", parts[1], c.config.ProtocolVersion)
|
||||
"Plugin version: %s, Core version: %d", parts[1], c.config.ProtocolVersion)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package sockaddr
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
@ -866,6 +867,80 @@ func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) {
|
|||
default:
|
||||
return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
|
||||
}
|
||||
case "mask":
|
||||
// "mask" operates on the IP address and returns the IP address on
|
||||
// which the given integer mask has been applied. If the applied mask
|
||||
// corresponds to a larger network than the mask of the IP address,
|
||||
// the latter will be replaced by the former.
|
||||
switch sockType := inputIfAddr.SockAddr.Type(); sockType {
|
||||
case TypeIPv4:
|
||||
i, err := strconv.ParseUint(value, 10, 32)
|
||||
if err != nil {
|
||||
return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
|
||||
}
|
||||
|
||||
if i > 32 {
|
||||
return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation)
|
||||
}
|
||||
|
||||
ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
|
||||
|
||||
ipv4Mask := net.CIDRMask(int(i), 32)
|
||||
ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask)
|
||||
|
||||
maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask)
|
||||
maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4)
|
||||
|
||||
maskedIpv4MaskUint32 := uint32(ipv4.Mask)
|
||||
|
||||
if ipv4MaskUint32 < maskedIpv4MaskUint32 {
|
||||
maskedIpv4MaskUint32 = ipv4MaskUint32
|
||||
}
|
||||
|
||||
return IfAddr{
|
||||
SockAddr: IPv4Addr{
|
||||
Address: IPv4Address(maskedIpv4Uint32),
|
||||
Mask: IPv4Mask(maskedIpv4MaskUint32),
|
||||
},
|
||||
Interface: inputIfAddr.Interface,
|
||||
}, nil
|
||||
case TypeIPv6:
|
||||
i, err := strconv.ParseUint(value, 10, 32)
|
||||
if err != nil {
|
||||
return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
|
||||
}
|
||||
|
||||
if i > 128 {
|
||||
return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation)
|
||||
}
|
||||
|
||||
ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
|
||||
|
||||
ipv6Mask := net.CIDRMask(int(i), 128)
|
||||
ipv6MaskBigInt := new(big.Int)
|
||||
ipv6MaskBigInt.SetBytes(ipv6Mask)
|
||||
|
||||
maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask)
|
||||
maskedIpv6BigInt := new(big.Int)
|
||||
maskedIpv6BigInt.SetBytes(maskedIpv6)
|
||||
|
||||
maskedIpv6MaskBigInt := new(big.Int)
|
||||
maskedIpv6MaskBigInt.Set(ipv6.Mask)
|
||||
|
||||
if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 {
|
||||
maskedIpv6MaskBigInt = ipv6MaskBigInt
|
||||
}
|
||||
|
||||
return IfAddr{
|
||||
SockAddr: IPv6Addr{
|
||||
Address: IPv6Address(maskedIpv6BigInt),
|
||||
Mask: IPv6Mask(maskedIpv6MaskBigInt),
|
||||
},
|
||||
Interface: inputIfAddr.Interface,
|
||||
}, nil
|
||||
default:
|
||||
return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
|
||||
}
|
||||
default:
|
||||
return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Vault Plugin: Kubernetes Auth Backend
|
||||
|
||||
This is a standalone backend plugin for use with [Hashicorp Vault](https://www.github.com/hashicorp/vault).
|
||||
This plugin allows for Kubernets Service Accounts to authenticate with Vault.
|
||||
This plugin allows for Kubernetes Service Accounts to authenticate with Vault.
|
||||
|
||||
**Please note**: We take Vault's security and our users' trust very seriously. If you believe you have found a security issue in Vault, _please responsibly disclose_ by contacting us at [security@hashicorp.com](mailto:security@hashicorp.com).
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
package isatty
|
||||
|
||||
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
|
||||
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
|
||||
// terminal. This is also always false on this environment.
|
||||
func IsCygwinTerminal(fd uintptr) bool {
|
||||
return false
|
||||
|
|
|
@ -3,6 +3,8 @@ package complete
|
|||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Args describes command line arguments
|
||||
|
@ -37,16 +39,41 @@ func (a Args) Directory() string {
|
|||
return fixPathForm(a.Last, dir)
|
||||
}
|
||||
|
||||
func newArgs(line []string) Args {
|
||||
completed := removeLast(line[1:])
|
||||
func newArgs(line string) Args {
|
||||
var (
|
||||
all []string
|
||||
completed []string
|
||||
)
|
||||
parts := splitFields(line)
|
||||
if len(parts) > 0 {
|
||||
all = parts[1:]
|
||||
completed = removeLast(parts[1:])
|
||||
}
|
||||
return Args{
|
||||
All: line[1:],
|
||||
All: all,
|
||||
Completed: completed,
|
||||
Last: last(line),
|
||||
Last: last(parts),
|
||||
LastCompleted: last(completed),
|
||||
}
|
||||
}
|
||||
|
||||
func splitFields(line string) []string {
|
||||
parts := strings.Fields(line)
|
||||
if len(line) > 0 && unicode.IsSpace(rune(line[len(line)-1])) {
|
||||
parts = append(parts, "")
|
||||
}
|
||||
parts = splitLastEqual(parts)
|
||||
return parts
|
||||
}
|
||||
|
||||
func splitLastEqual(line []string) []string {
|
||||
if len(line) == 0 {
|
||||
return line
|
||||
}
|
||||
parts := strings.Split(line[len(line)-1], "=")
|
||||
return append(line[:len(line)-1], parts...)
|
||||
}
|
||||
|
||||
func (a Args) from(i int) Args {
|
||||
if i > len(a.All) {
|
||||
i = len(a.All)
|
||||
|
@ -67,9 +94,9 @@ func removeLast(a []string) []string {
|
|||
return a
|
||||
}
|
||||
|
||||
func last(args []string) (last string) {
|
||||
if len(args) > 0 {
|
||||
last = args[len(args)-1]
|
||||
func last(args []string) string {
|
||||
if len(args) == 0 {
|
||||
return ""
|
||||
}
|
||||
return
|
||||
return args[len(args)-1]
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package complete
|
||||
|
||||
import "github.com/posener/complete/match"
|
||||
|
||||
// Command represents a command line
|
||||
// It holds the data that enables auto completion of command line
|
||||
// Command can also be a sub command.
|
||||
|
@ -25,9 +23,9 @@ type Command struct {
|
|||
}
|
||||
|
||||
// Predict returns all possible predictions for args according to the command struct
|
||||
func (c *Command) Predict(a Args) (predictions []string) {
|
||||
predictions, _ = c.predict(a)
|
||||
return
|
||||
func (c *Command) Predict(a Args) []string {
|
||||
options, _ := c.predict(a)
|
||||
return options
|
||||
}
|
||||
|
||||
// Commands is the type of Sub member, it maps a command name to a command struct
|
||||
|
@ -36,9 +34,7 @@ type Commands map[string]Command
|
|||
// Predict completion of sub command names names according to command line arguments
|
||||
func (c Commands) Predict(a Args) (prediction []string) {
|
||||
for sub := range c {
|
||||
if match.Prefix(sub, a.Last) {
|
||||
prediction = append(prediction, sub)
|
||||
}
|
||||
prediction = append(prediction, sub)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -56,10 +52,7 @@ func (f Flags) Predict(a Args) (prediction []string) {
|
|||
if flagHyphenStart && !lastHyphenStart {
|
||||
continue
|
||||
}
|
||||
|
||||
if match.Prefix(flag, a.Last) {
|
||||
prediction = append(prediction, flag)
|
||||
}
|
||||
prediction = append(prediction, flag)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -8,10 +8,11 @@ package complete
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/posener/complete/cmd"
|
||||
"github.com/posener/complete/match"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -23,6 +24,7 @@ const (
|
|||
type Complete struct {
|
||||
Command Command
|
||||
cmd.CLI
|
||||
Out io.Writer
|
||||
}
|
||||
|
||||
// New creates a new complete command.
|
||||
|
@ -34,6 +36,7 @@ func New(name string, command Command) *Complete {
|
|||
return &Complete{
|
||||
Command: command,
|
||||
CLI: cmd.CLI{Name: name},
|
||||
Out: os.Stdout,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,28 +62,34 @@ func (c *Complete) Complete() bool {
|
|||
return c.CLI.Run()
|
||||
}
|
||||
Log("Completing line: %s", line)
|
||||
|
||||
a := newArgs(line)
|
||||
|
||||
Log("Completing last field: %s", a.Last)
|
||||
options := c.Command.Predict(a)
|
||||
Log("Options: %s", options)
|
||||
|
||||
Log("Completion: %s", options)
|
||||
output(options)
|
||||
// filter only options that match the last argument
|
||||
matches := []string{}
|
||||
for _, option := range options {
|
||||
if match.Prefix(option, a.Last) {
|
||||
matches = append(matches, option)
|
||||
}
|
||||
}
|
||||
Log("Matches: %s", matches)
|
||||
c.output(matches)
|
||||
return true
|
||||
}
|
||||
|
||||
func getLine() ([]string, bool) {
|
||||
func getLine() (string, bool) {
|
||||
line := os.Getenv(envComplete)
|
||||
if line == "" {
|
||||
return nil, false
|
||||
return "", false
|
||||
}
|
||||
return strings.Split(line, " "), true
|
||||
return line, true
|
||||
}
|
||||
|
||||
func output(options []string) {
|
||||
Log("")
|
||||
func (c *Complete) output(options []string) {
|
||||
// stdout of program defines the complete options
|
||||
for _, option := range options {
|
||||
fmt.Println(option)
|
||||
fmt.Fprintln(c.Out, option)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package complete
|
||||
|
||||
import "github.com/posener/complete/match"
|
||||
|
||||
// PredictSet expects specific set of terms, given in the options argument.
|
||||
func PredictSet(options ...string) Predictor {
|
||||
return predictSet(options)
|
||||
|
@ -9,11 +7,6 @@ func PredictSet(options ...string) Predictor {
|
|||
|
||||
type predictSet []string
|
||||
|
||||
func (p predictSet) Predict(a Args) (prediction []string) {
|
||||
for _, m := range p {
|
||||
if match.Prefix(m, a.Last) {
|
||||
prediction = append(prediction, m)
|
||||
}
|
||||
}
|
||||
return
|
||||
func (p predictSet) Predict(a Args) []string {
|
||||
return p
|
||||
}
|
||||
|
|
|
@ -568,6 +568,10 @@ func UnquoteUsage(flag *Flag) (name string, usage string) {
|
|||
name = "strings"
|
||||
case "intSlice":
|
||||
name = "ints"
|
||||
case "uintSlice":
|
||||
name = "uints"
|
||||
case "boolSlice":
|
||||
name = "bools"
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
@ -65,24 +65,18 @@ type bincEncDriver struct {
|
|||
encDriverNoopContainerWriter
|
||||
}
|
||||
|
||||
func (e *bincEncDriver) IsBuiltinType(rt uintptr) bool {
|
||||
return rt == timeTypId
|
||||
}
|
||||
// func (e *bincEncDriver) IsBuiltinType(rt uintptr) bool {
|
||||
// return rt == timeTypId
|
||||
// }
|
||||
|
||||
func (e *bincEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {
|
||||
if rt == timeTypId {
|
||||
var bs []byte
|
||||
switch x := v.(type) {
|
||||
case time.Time:
|
||||
bs = encodeTime(x)
|
||||
case *time.Time:
|
||||
bs = encodeTime(*x)
|
||||
default:
|
||||
e.e.errorf("binc error encoding builtin: expect time.Time, received %T", v)
|
||||
}
|
||||
bs := encodeTime(v.(time.Time))
|
||||
e.w.writen1(bincVdTimestamp<<4 | uint8(len(bs)))
|
||||
e.w.writeb(bs)
|
||||
return
|
||||
}
|
||||
e.e.errorf("binc error encoding builtin: expect time.Time, received %T", v)
|
||||
}
|
||||
|
||||
func (e *bincEncDriver) EncodeNil() {
|
||||
|
@ -388,9 +382,9 @@ func (d *bincDecDriver) TryDecodeAsNil() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (d *bincDecDriver) IsBuiltinType(rt uintptr) bool {
|
||||
return rt == timeTypId
|
||||
}
|
||||
// func (d *bincDecDriver) IsBuiltinType(rt uintptr) bool {
|
||||
// return rt == timeTypId
|
||||
// }
|
||||
|
||||
func (d *bincDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {
|
||||
if !d.bdRead {
|
||||
|
@ -408,7 +402,9 @@ func (d *bincDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {
|
|||
var vt *time.Time = v.(*time.Time)
|
||||
*vt = tt
|
||||
d.bdRead = false
|
||||
return
|
||||
}
|
||||
d.d.errorf("binc error decoding builtin: expect *time.Time, received %T", v)
|
||||
}
|
||||
|
||||
func (d *bincDecDriver) decFloatPre(vs, defaultLen byte) {
|
||||
|
|
|
@ -974,13 +974,13 @@ func (d *Decoder) kInterfaceNaked(f *codecFnInfo) (rvn reflect.Value) {
|
|||
rvn = reflect.ValueOf(&v2).Elem()
|
||||
}
|
||||
} else {
|
||||
rvn = reflect.New(d.h.MapType)
|
||||
if useLookupRecognizedTypes && d.mtr { // isRecognizedRtid(d.mtid) {
|
||||
if d.mtr {
|
||||
rvn = reflect.New(d.h.MapType)
|
||||
d.decode(rv2i(rvn))
|
||||
rvn = rvn.Elem()
|
||||
} else {
|
||||
rvn = rvn.Elem()
|
||||
d.decodeValue(rvn, nil, false, true)
|
||||
rvn = reflect.New(d.h.MapType).Elem()
|
||||
d.decodeValue(rvn, nil, true)
|
||||
}
|
||||
}
|
||||
case valueTypeArray:
|
||||
|
@ -1002,13 +1002,13 @@ func (d *Decoder) kInterfaceNaked(f *codecFnInfo) (rvn reflect.Value) {
|
|||
rvn = rvn2
|
||||
}
|
||||
} else {
|
||||
rvn = reflect.New(d.h.SliceType)
|
||||
if useLookupRecognizedTypes && d.str { // isRecognizedRtid(d.stid) {
|
||||
if d.str {
|
||||
rvn = reflect.New(d.h.SliceType)
|
||||
d.decode(rv2i(rvn))
|
||||
rvn = rvn.Elem()
|
||||
} else {
|
||||
rvn = rvn.Elem()
|
||||
d.decodeValue(rvn, nil, false, true)
|
||||
rvn = reflect.New(d.h.SliceType).Elem()
|
||||
d.decodeValue(rvn, nil, true)
|
||||
}
|
||||
}
|
||||
case valueTypeExt:
|
||||
|
@ -1104,25 +1104,17 @@ func (d *Decoder) kInterface(f *codecFnInfo, rv reflect.Value) {
|
|||
|
||||
rvn2, canDecode := isDecodeable(rvn)
|
||||
if canDecode {
|
||||
d.decodeValue(rvn2, nil, true, true)
|
||||
d.decodeValue(rvn2, nil, true)
|
||||
return
|
||||
}
|
||||
|
||||
rvn2 = reflect.New(rvn.Type()).Elem()
|
||||
rvn2.Set(rvn)
|
||||
d.decodeValue(rvn2, nil, true, true)
|
||||
d.decodeValue(rvn2, nil, true)
|
||||
rv.Set(rvn2)
|
||||
}
|
||||
|
||||
func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
|
||||
// checking if recognized within kstruct is too expensive.
|
||||
// only check where you can determine if valid outside the loop
|
||||
// ie on homogenous collections: slices, arrays and maps.
|
||||
//
|
||||
// if true, we don't create too many decFn's.
|
||||
// It's a delicate balance.
|
||||
const checkRecognized bool = false // false: TODO
|
||||
|
||||
fti := f.ti
|
||||
dd := d.d
|
||||
elemsep := d.hh.hasElemSeparators()
|
||||
|
@ -1153,7 +1145,7 @@ func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
|
|||
if dd.TryDecodeAsNil() {
|
||||
si.setToZeroValue(rv)
|
||||
} else {
|
||||
d.decodeValue(sfn.field(si), nil, checkRecognized, true)
|
||||
d.decodeValue(sfn.field(si), nil, true)
|
||||
}
|
||||
} else {
|
||||
d.structFieldNotFound(-1, rvkencname)
|
||||
|
@ -1180,7 +1172,7 @@ func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
|
|||
if dd.TryDecodeAsNil() {
|
||||
si.setToZeroValue(rv)
|
||||
} else {
|
||||
d.decodeValue(sfn.field(si), nil, checkRecognized, true)
|
||||
d.decodeValue(sfn.field(si), nil, true)
|
||||
}
|
||||
}
|
||||
if containerLen > len(fti.sfip) {
|
||||
|
@ -1256,7 +1248,6 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
|
|||
|
||||
rtelem0Size := int(rtelem0.Size())
|
||||
rtElem0Kind := rtelem0.Kind()
|
||||
rtElem0Id := rt2id(rtelem0)
|
||||
rtelem0Mut := !isImmutableKind(rtElem0Kind)
|
||||
rtelem := rtelem0
|
||||
rtelemkind := rtelem.Kind()
|
||||
|
@ -1304,12 +1295,6 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
|
|||
}
|
||||
}
|
||||
|
||||
var recognizedRtid, recognizedRtidPtr bool
|
||||
if useLookupRecognizedTypes {
|
||||
recognizedRtid = isRecognizedRtid(rtElem0Id)
|
||||
recognizedRtidPtr = isRecognizedRtidPtr(rtElem0Id)
|
||||
}
|
||||
|
||||
// consider creating new element once, and just decoding into it.
|
||||
var rtelem0Zero reflect.Value
|
||||
var rtelem0ZeroValid bool
|
||||
|
@ -1339,14 +1324,10 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
|
|||
if rtelem0Mut || !rv9.IsValid() { // || (rtElem0Kind == reflect.Ptr && rv9.IsNil()) {
|
||||
rv9 = reflect.New(rtelem0).Elem()
|
||||
}
|
||||
if useLookupRecognizedTypes && (recognizedRtid || recognizedRtidPtr) {
|
||||
d.decode(rv2i(rv9.Addr()))
|
||||
} else {
|
||||
if fn == nil {
|
||||
fn = d.cf.get(rtelem, true, true)
|
||||
}
|
||||
d.decodeValue(rv9, fn, false, true)
|
||||
if fn == nil {
|
||||
fn = d.cf.get(rtelem, true, true)
|
||||
}
|
||||
d.decodeValue(rv9, fn, true)
|
||||
rv.Send(rv9)
|
||||
} else {
|
||||
// if indefinite, etc, then expand the slice if necessary
|
||||
|
@ -1383,19 +1364,10 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
|
|||
continue
|
||||
}
|
||||
|
||||
if useLookupRecognizedTypes && recognizedRtid {
|
||||
d.decode(rv2i(rv9.Addr()))
|
||||
} else if useLookupRecognizedTypes && recognizedRtidPtr { // && !rv9.IsNil() {
|
||||
if rv9.IsNil() {
|
||||
rv9.Set(reflect.New(rtelem))
|
||||
}
|
||||
d.decode(rv2i(rv9))
|
||||
} else {
|
||||
if fn == nil {
|
||||
fn = d.cf.get(rtelem, true, true)
|
||||
}
|
||||
d.decodeValue(rv9, fn, false, true)
|
||||
if fn == nil {
|
||||
fn = d.cf.get(rtelem, true, true)
|
||||
}
|
||||
d.decodeValue(rv9, fn, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1441,15 +1413,7 @@ func (d *Decoder) kMap(f *codecFnInfo, rv reflect.Value) {
|
|||
|
||||
ktype, vtype := ti.rt.Key(), ti.rt.Elem()
|
||||
ktypeId := rt2id(ktype)
|
||||
vtypeId := rt2id(vtype)
|
||||
vtypeKind := vtype.Kind()
|
||||
var recognizedKtyp, recognizedVtyp, recognizedPtrKtyp, recognizedPtrVtyp bool
|
||||
if useLookupRecognizedTypes {
|
||||
recognizedKtyp = isRecognizedRtid(ktypeId)
|
||||
recognizedVtyp = isRecognizedRtid(vtypeId)
|
||||
recognizedPtrKtyp = isRecognizedRtidPtr(ktypeId)
|
||||
recognizedPtrVtyp = isRecognizedRtidPtr(vtypeId)
|
||||
}
|
||||
|
||||
var keyFn, valFn *codecFn
|
||||
var ktypeLo, vtypeLo reflect.Type
|
||||
|
@ -1501,26 +1465,19 @@ func (d *Decoder) kMap(f *codecFnInfo, rv reflect.Value) {
|
|||
kstrbs = dd.DecodeStringAsBytes()
|
||||
rvk.SetString(stringView(kstrbs))
|
||||
// NOTE: if doing an insert, you MUST use a real string (not stringview)
|
||||
} else if useLookupRecognizedTypes && recognizedKtyp {
|
||||
d.decode(rv2i(rvkp))
|
||||
// rvk = rvkp.Elem() //TODO: remove, unnecessary
|
||||
} else if useLookupRecognizedTypes && recognizedPtrKtyp {
|
||||
if rvk.IsNil() {
|
||||
rvk = reflect.New(ktypeLo)
|
||||
}
|
||||
d.decode(rv2i(rvk))
|
||||
} else {
|
||||
if keyFn == nil {
|
||||
keyFn = d.cf.get(ktypeLo, true, true)
|
||||
}
|
||||
d.decodeValue(rvk, keyFn, false, true)
|
||||
d.decodeValue(rvk, keyFn, true)
|
||||
}
|
||||
// special case if a byte array.
|
||||
if ktypeIsIntf {
|
||||
if rvk2 := rvk.Elem(); rvk2.IsValid() {
|
||||
rvk = rvk2
|
||||
if rvk.Type() == uint8SliceTyp {
|
||||
rvk = reflect.ValueOf(d.string(rvk.Bytes()))
|
||||
if rvk2.Type() == uint8SliceTyp {
|
||||
rvk = reflect.ValueOf(d.string(rvk2.Bytes()))
|
||||
} else {
|
||||
rvk = rvk2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1579,21 +1536,11 @@ func (d *Decoder) kMap(f *codecFnInfo, rv reflect.Value) {
|
|||
if mapSet && ktypeIsString {
|
||||
rvk.SetString(d.string(kstrbs))
|
||||
}
|
||||
if useLookupRecognizedTypes && recognizedVtyp && rvv.CanAddr() {
|
||||
d.decode(rv2i(rvv.Addr()))
|
||||
} else if useLookupRecognizedTypes && recognizedPtrVtyp {
|
||||
if rvv.IsNil() {
|
||||
rvv = reflect.New(vtypeLo)
|
||||
mapSet = true
|
||||
}
|
||||
d.decode(rv2i(rvv))
|
||||
} else {
|
||||
if valFn == nil {
|
||||
valFn = d.cf.get(vtypeLo, true, true)
|
||||
}
|
||||
d.decodeValue(rvv, valFn, false, true)
|
||||
// d.decodeValueFn(rvv, valFn)
|
||||
if valFn == nil {
|
||||
valFn = d.cf.get(vtypeLo, true, true)
|
||||
}
|
||||
d.decodeValue(rvv, valFn, true)
|
||||
// d.decodeValueFn(rvv, valFn)
|
||||
if mapSet {
|
||||
rv.SetMapIndex(rvk, rvv)
|
||||
}
|
||||
|
@ -1719,7 +1666,7 @@ type Decoder struct {
|
|||
hh Handle
|
||||
h *BasicHandle
|
||||
|
||||
mtr, mtrp, str, strp bool //
|
||||
mtr, str bool // whether maptype or slicetype are known types
|
||||
|
||||
be bool // is binary encoding
|
||||
bytes bool // is bytes reader
|
||||
|
@ -1812,23 +1759,16 @@ func (d *Decoder) resetCommon() {
|
|||
d.d.reset()
|
||||
d.cf.reset(d.hh)
|
||||
d.err = nil
|
||||
// reset all things which were cached from the Handle,
|
||||
// but could be changed.
|
||||
// reset all things which were cached from the Handle, but could change
|
||||
d.mtid, d.stid = 0, 0
|
||||
d.mtr, d.mtrp, d.str, d.strp = false, false, false, false
|
||||
d.mtr, d.str = false, false
|
||||
if d.h.MapType != nil {
|
||||
d.mtid = rt2id(d.h.MapType)
|
||||
if useLookupRecognizedTypes {
|
||||
d.mtr = isRecognizedRtid(d.mtid)
|
||||
d.mtrp = isRecognizedRtidPtr(d.mtid)
|
||||
}
|
||||
d.mtr = fastpathAV.index(d.mtid) != -1
|
||||
}
|
||||
if d.h.SliceType != nil {
|
||||
d.stid = rt2id(d.h.SliceType)
|
||||
if useLookupRecognizedTypes {
|
||||
d.str = isRecognizedRtid(d.stid)
|
||||
d.strp = isRecognizedRtidPtr(d.stid)
|
||||
}
|
||||
d.str = fastpathAV.index(d.stid) != -1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1917,7 +1857,7 @@ func (d *Decoder) MustDecode(v interface{}) {
|
|||
panic(d.err)
|
||||
}
|
||||
if d.d.TryDecodeAsNil() {
|
||||
d.setZero(v)
|
||||
setZero(v)
|
||||
} else {
|
||||
d.decode(v)
|
||||
}
|
||||
|
@ -1995,7 +1935,7 @@ func (d *Decoder) swallow() {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) setZero(iv interface{}) {
|
||||
func setZero(iv interface{}) {
|
||||
if iv == nil || definitelyNil(iv) {
|
||||
return
|
||||
}
|
||||
|
@ -2038,7 +1978,7 @@ func (d *Decoder) setZero(iv interface{}) {
|
|||
v.Set(reflect.Zero(v.Type()))
|
||||
} // TODO: else drain if chan, clear if map, set all to nil if slice???
|
||||
default:
|
||||
if !fastpathDecodeSetZeroTypeSwitch(iv, d) {
|
||||
if !fastpathDecodeSetZeroTypeSwitch(iv) {
|
||||
v := reflect.ValueOf(iv)
|
||||
if v, canDecode = isDecodeable(v); canDecode && v.CanSet() {
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
|
@ -2065,7 +2005,7 @@ func (d *Decoder) decode(iv interface{}) {
|
|||
|
||||
case reflect.Value:
|
||||
v = d.ensureDecodeable(v)
|
||||
d.decodeValue(v, nil, false, true) // TODO: maybe ask to recognize ...
|
||||
d.decodeValue(v, nil, true) // TODO: maybe ask to recognize ...
|
||||
|
||||
case *string:
|
||||
*v = d.d.DecodeString()
|
||||
|
@ -2102,20 +2042,20 @@ func (d *Decoder) decode(iv interface{}) {
|
|||
*v = d.rawBytes()
|
||||
|
||||
case *interface{}:
|
||||
d.decodeValue(reflect.ValueOf(iv).Elem(), nil, false, true) // TODO: consider recognize here
|
||||
d.decodeValue(reflect.ValueOf(iv).Elem(), nil, true) // TODO: consider recognize here
|
||||
// d.decodeValueNotNil(reflect.ValueOf(iv).Elem())
|
||||
|
||||
default:
|
||||
if !fastpathDecodeTypeSwitch(iv, d) {
|
||||
v := reflect.ValueOf(iv)
|
||||
v = d.ensureDecodeable(v)
|
||||
d.decodeValue(v, nil, false, false)
|
||||
d.decodeValue(v, nil, false)
|
||||
// d.decodeValueFallback(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeValue(rv reflect.Value, fn *codecFn, tryRecognized, chkAll bool) {
|
||||
func (d *Decoder) decodeValue(rv reflect.Value, fn *codecFn, chkAll bool) {
|
||||
// If stream is not containing a nil value, then we can deref to the base
|
||||
// non-pointer value, and decode into that.
|
||||
var rvp reflect.Value
|
||||
|
@ -2134,16 +2074,6 @@ func (d *Decoder) decodeValue(rv reflect.Value, fn *codecFn, tryRecognized, chkA
|
|||
}
|
||||
}
|
||||
|
||||
if useLookupRecognizedTypes && tryRecognized && isRecognizedRtid(rv2rtid(rv)) {
|
||||
if rvpValid {
|
||||
d.decode(rv2i(rvp))
|
||||
return
|
||||
} else if rv.CanAddr() {
|
||||
d.decode(rv2i(rv.Addr()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if fn == nil {
|
||||
// always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer
|
||||
fn = d.cf.get(rv.Type(), chkAll, true) // chkAll, chkAll)
|
||||
|
|
|
@ -350,10 +350,6 @@ func (e *Encoder) builtin(f *codecFnInfo, rv reflect.Value) {
|
|||
e.e.EncodeBuiltin(f.ti.rtid, rv2i(rv))
|
||||
}
|
||||
|
||||
func (e *Encoder) raw(f *codecFnInfo, rv reflect.Value) {
|
||||
e.rawBytes(rv2i(rv).(Raw))
|
||||
}
|
||||
|
||||
func (e *Encoder) rawExt(f *codecFnInfo, rv reflect.Value) {
|
||||
// rev := rv2i(rv).(RawExt)
|
||||
// e.e.EncodeRawExt(&rev, e)
|
||||
|
@ -408,28 +404,8 @@ func (e *Encoder) jsonMarshal(f *codecFnInfo, rv reflect.Value) {
|
|||
e.marshal(bs, fnerr, true, c_UTF8)
|
||||
}
|
||||
|
||||
func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeBool(rv.Bool())
|
||||
}
|
||||
|
||||
func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeString(c_UTF8, rv.String())
|
||||
}
|
||||
|
||||
func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeFloat64(rv.Float())
|
||||
}
|
||||
|
||||
func (e *Encoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeFloat32(float32(rv.Float()))
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeInt(rv.Int())
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeUint(rv.Uint())
|
||||
func (e *Encoder) raw(f *codecFnInfo, rv reflect.Value) {
|
||||
e.rawBytes(rv2i(rv).(Raw))
|
||||
}
|
||||
|
||||
func (e *Encoder) kInvalid(f *codecFnInfo, rv reflect.Value) {
|
||||
|
@ -508,20 +484,14 @@ func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
|
|||
|
||||
if l > 0 {
|
||||
var fn *codecFn
|
||||
var recognizedVtyp bool
|
||||
if useLookupRecognizedTypes {
|
||||
recognizedVtyp = isRecognizedRtidOrPtr(rt2id(rtelem))
|
||||
for rtelem.Kind() == reflect.Ptr {
|
||||
rtelem = rtelem.Elem()
|
||||
}
|
||||
if !(useLookupRecognizedTypes && recognizedVtyp) {
|
||||
for rtelem.Kind() == reflect.Ptr {
|
||||
rtelem = rtelem.Elem()
|
||||
}
|
||||
// if kind is reflect.Interface, do not pre-determine the
|
||||
// encoding type, because preEncodeValue may break it down to
|
||||
// a concrete type and kInterface will bomb.
|
||||
if rtelem.Kind() != reflect.Interface {
|
||||
fn = e.cf.get(rtelem, true, true)
|
||||
}
|
||||
// if kind is reflect.Interface, do not pre-determine the
|
||||
// encoding type, because preEncodeValue may break it down to
|
||||
// a concrete type and kInterface will bomb.
|
||||
if rtelem.Kind() != reflect.Interface {
|
||||
fn = e.cf.get(rtelem, true, true)
|
||||
}
|
||||
// TODO: Consider perf implication of encoding odd index values as symbols if type is string
|
||||
for j := 0; j < l; j++ {
|
||||
|
@ -538,20 +508,12 @@ func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
|
|||
}
|
||||
if f.seq == seqTypeChan {
|
||||
if rv2, ok2 := rv.Recv(); ok2 {
|
||||
if useLookupRecognizedTypes && recognizedVtyp {
|
||||
e.encode(rv2i(rv2))
|
||||
} else {
|
||||
e.encodeValue(rv2, fn, true)
|
||||
}
|
||||
e.encodeValue(rv2, fn, true)
|
||||
} else {
|
||||
ee.EncodeNil() // WE HAVE TO DO SOMETHING, so nil if nothing received.
|
||||
}
|
||||
} else {
|
||||
if useLookupRecognizedTypes && recognizedVtyp {
|
||||
e.encode(rv2i(rv.Index(j)))
|
||||
} else {
|
||||
e.encodeValue(rv.Index(j), fn, true)
|
||||
}
|
||||
e.encodeValue(rv.Index(j), fn, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -768,7 +730,6 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
|
|||
rtval0 := ti.rt.Elem()
|
||||
rtval := rtval0
|
||||
rtkeyid := rt2id(rtkey0)
|
||||
rtvalid := rt2id(rtval0)
|
||||
for rtval.Kind() == reflect.Ptr {
|
||||
rtval = rtval.Elem()
|
||||
}
|
||||
|
@ -783,17 +744,10 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
|
|||
return
|
||||
}
|
||||
|
||||
var recognizedKtyp, recognizedVtyp bool
|
||||
var keyTypeIsString = rtkeyid == stringTypId
|
||||
if keyTypeIsString {
|
||||
asSymbols = e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
|
||||
} else {
|
||||
if useLookupRecognizedTypes {
|
||||
recognizedKtyp = isRecognizedRtidOrPtr(rtkeyid)
|
||||
if recognizedKtyp {
|
||||
goto LABEL1
|
||||
}
|
||||
}
|
||||
for rtkey.Kind() == reflect.Ptr {
|
||||
rtkey = rtkey.Elem()
|
||||
}
|
||||
|
@ -804,10 +758,6 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
|
|||
}
|
||||
|
||||
// for j, lmks := 0, len(mks); j < lmks; j++ {
|
||||
LABEL1:
|
||||
if useLookupRecognizedTypes {
|
||||
recognizedVtyp = isRecognizedRtidOrPtr(rtvalid)
|
||||
}
|
||||
for j := range mks {
|
||||
if elemsep {
|
||||
ee.WriteMapElemKey()
|
||||
|
@ -818,19 +768,14 @@ LABEL1:
|
|||
} else {
|
||||
ee.EncodeString(c_UTF8, mks[j].String())
|
||||
}
|
||||
} else if useLookupRecognizedTypes && recognizedKtyp {
|
||||
e.encode(rv2i(mks[j]))
|
||||
} else {
|
||||
e.encodeValue(mks[j], keyFn, true)
|
||||
}
|
||||
if elemsep {
|
||||
ee.WriteMapElemValue()
|
||||
}
|
||||
if useLookupRecognizedTypes && recognizedVtyp {
|
||||
e.encode(rv2i(rv.MapIndex(mks[j])))
|
||||
} else {
|
||||
e.encodeValue(rv.MapIndex(mks[j]), valFn, true)
|
||||
}
|
||||
e.encodeValue(rv.MapIndex(mks[j]), valFn, true)
|
||||
|
||||
}
|
||||
ee.WriteMapEnd()
|
||||
}
|
||||
|
@ -1321,11 +1266,6 @@ TOP:
|
|||
|
||||
if fn == nil {
|
||||
rt := rv.Type()
|
||||
// TODO: calling isRecognizedRtid here is a major slowdown
|
||||
if false && useLookupRecognizedTypes && isRecognizedRtidOrPtr(rt2id(rt)) {
|
||||
e.encode(rv2i(rv))
|
||||
return
|
||||
}
|
||||
// always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer
|
||||
fn = e.cf.get(rt, checkFastpath, true)
|
||||
}
|
||||
|
|
|
@ -80,19 +80,12 @@ var fastpathAV fastpathA
|
|||
|
||||
// due to possible initialization loop error, make fastpath in an init()
|
||||
func init() {
|
||||
if useLookupRecognizedTypes && recognizedRtidsLoaded {
|
||||
panic("recognizedRtidsLoaded = true - cannot happen")
|
||||
}
|
||||
i := 0
|
||||
fn := func(v interface{},
|
||||
fe func(*Encoder, *codecFnInfo, reflect.Value),
|
||||
fd func(*Decoder, *codecFnInfo, reflect.Value)) (f fastpathE) {
|
||||
xrt := reflect.TypeOf(v)
|
||||
xptr := rt2id(xrt)
|
||||
if useLookupRecognizedTypes {
|
||||
recognizedRtids = append(recognizedRtids, xptr)
|
||||
recognizedRtidPtrs = append(recognizedRtidPtrs, rt2id(reflect.PtrTo(xrt)))
|
||||
}
|
||||
fastpathAV[i] = fastpathE{xptr, xrt, fe, fd}
|
||||
i++
|
||||
return
|
||||
|
@ -15563,7 +15556,7 @@ func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func fastpathDecodeSetZeroTypeSwitch(iv interface{}, d *Decoder) bool {
|
||||
func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool {
|
||||
switch v := iv.(type) {
|
||||
|
||||
case *[]interface{}:
|
||||
|
|
|
@ -80,19 +80,12 @@ var fastpathAV fastpathA
|
|||
|
||||
// due to possible initialization loop error, make fastpath in an init()
|
||||
func init() {
|
||||
if useLookupRecognizedTypes && recognizedRtidsLoaded {
|
||||
panic("recognizedRtidsLoaded = true - cannot happen")
|
||||
}
|
||||
i := 0
|
||||
fn := func(v interface{},
|
||||
fe func(*Encoder, *codecFnInfo, reflect.Value),
|
||||
fd func(*Decoder, *codecFnInfo, reflect.Value)) (f fastpathE) {
|
||||
xrt := reflect.TypeOf(v)
|
||||
xptr := rt2id(xrt)
|
||||
if useLookupRecognizedTypes {
|
||||
recognizedRtids = append(recognizedRtids, xptr)
|
||||
recognizedRtidPtrs = append(recognizedRtidPtrs, rt2id(reflect.PtrTo(xrt)))
|
||||
}
|
||||
fastpathAV[i] = fastpathE{xptr, xrt, fe, fd}
|
||||
i++
|
||||
return
|
||||
|
@ -289,7 +282,7 @@ func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func fastpathDecodeSetZeroTypeSwitch(iv interface{}, d *Decoder) bool {
|
||||
func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool {
|
||||
switch v := iv.(type) {
|
||||
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
|
||||
case *[]{{ .Elem }}: {{else}}
|
||||
|
|
|
@ -14,11 +14,11 @@ const fastpathEnabled = false
|
|||
// This tag disables fastpath during build, allowing for faster build, test execution,
|
||||
// short-program runs, etc.
|
||||
|
||||
func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { return false }
|
||||
func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { return false }
|
||||
func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { return false }
|
||||
func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { return false }
|
||||
func fastpathDecodeSetZeroTypeSwitch(iv interface{}, d *Decoder) bool { return false }
|
||||
func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { return false }
|
||||
func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { return false }
|
||||
func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { return false }
|
||||
func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { return false }
|
||||
func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool { return false }
|
||||
|
||||
type fastpathT struct{}
|
||||
type fastpathE struct {
|
||||
|
@ -33,3 +33,6 @@ func (x fastpathA) index(rtid uintptr) int { return -1 }
|
|||
|
||||
var fastpathAV fastpathA
|
||||
var fastpathTV fastpathT
|
||||
|
||||
// ----
|
||||
type TestMammoth2Wrapper struct{} // to allow testMammoth work in notfastpath mode
|
||||
|
|
|
@ -155,7 +155,7 @@ func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
|
|||
if chkPtr {
|
||||
rv = f.d.ensureDecodeable(rv)
|
||||
}
|
||||
f.d.decodeValue(rv, nil, false, false)
|
||||
f.d.decodeValue(rv, nil, false)
|
||||
// f.d.decodeValueFallback(rv)
|
||||
}
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
|
|||
if chkPtr {
|
||||
rv = f.d.ensureDecodeable(rv)
|
||||
}
|
||||
f.d.decodeValue(rv, nil, false, false)
|
||||
f.d.decodeValue(rv, nil, false)
|
||||
// f.d.decodeValueFallback(rv)
|
||||
}
|
||||
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
|
||||
|
|
|
@ -504,7 +504,7 @@ func (x *genRunner) selfer(encode bool) {
|
|||
t0 := t
|
||||
// always make decode use a pointer receiver,
|
||||
// and structs always use a ptr receiver (encode|decode)
|
||||
isptr := !encode || t.Kind() == reflect.Struct
|
||||
isptr := !encode || (t.Kind() == reflect.Struct || t.Kind() == reflect.Array)
|
||||
x.varsfxreset()
|
||||
fnSigPfx := "func (x "
|
||||
if isptr {
|
||||
|
@ -701,11 +701,11 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
|
|||
defer func() { x.line("}") }() //end if block
|
||||
|
||||
if t == rawTyp {
|
||||
x.linef("} else { z.EncRaw(%v)", varname)
|
||||
x.linef("} else { z.EncRaw(%s)", varname)
|
||||
return
|
||||
}
|
||||
if t == rawExtTyp {
|
||||
x.linef("} else { r.EncodeRawExt(%v, e)", varname)
|
||||
x.linef("} else { r.EncodeRawExt(%s, e)", varname)
|
||||
return
|
||||
}
|
||||
// HACK: Support for Builtins.
|
||||
|
@ -714,7 +714,7 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
|
|||
if t == timeTyp {
|
||||
vrtid := genTempVarPfx + "m" + x.varsfx()
|
||||
x.linef("} else if %s := z.TimeRtidIfBinc(); %s != 0 { ", vrtid, vrtid)
|
||||
x.linef("r.EncodeBuiltin(%s, %s)", vrtid, varname)
|
||||
x.linef("r.EncodeBuiltin(%s, *%s)", vrtid, varname)
|
||||
}
|
||||
// only check for extensions if the type is named, and has a packagePath.
|
||||
if !x.nx && genImportPath(t) != "" && t.Name() != "" {
|
||||
|
@ -999,7 +999,7 @@ func (x *genRunner) encListFallback(varname string, t reflect.Type) {
|
|||
return
|
||||
}
|
||||
if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
|
||||
x.linef("r.EncodeStringBytes(codecSelferC_RAW%s, ([%v]byte(%s))[:])", x.xs, t.Len(), varname)
|
||||
x.linef("r.EncodeStringBytes(codecSelferC_RAW%s, ((*[%d]byte)(%s))[:])", x.xs, t.Len(), varname)
|
||||
return
|
||||
}
|
||||
i := x.varsfx()
|
||||
|
@ -1332,7 +1332,7 @@ func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type
|
|||
return
|
||||
}
|
||||
if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
|
||||
x.linef("r.DecodeBytes( ((*[%s]byte)(%s))[:], true)", t.Len(), varname)
|
||||
x.linef("r.DecodeBytes( ((*[%d]byte)(%s))[:], true)", t.Len(), varname)
|
||||
return
|
||||
}
|
||||
type tstruc struct {
|
||||
|
|
|
@ -128,40 +128,6 @@ const (
|
|||
// allowing zero-alloc initialization.
|
||||
arrayCacheLen = 8
|
||||
|
||||
// We tried an optimization, where we detect if a type is one of the known types
|
||||
// we optimized for (e.g. int, []uint64, etc).
|
||||
//
|
||||
// However, we notice some worse performance when using this optimization.
|
||||
// So we hide it behind a flag, to turn on if needed.
|
||||
useLookupRecognizedTypes = false
|
||||
|
||||
// using recognized allows us to do d.decode(interface{}) instead of d.decodeValue(reflect.Value)
|
||||
// when we can infer that the kind of the interface{} is one of the ones hard-coded in the
|
||||
// type switch for known types or the ones defined by fast-path.
|
||||
//
|
||||
// However, it seems we get better performance when we don't recognize, and just let
|
||||
// reflection handle it.
|
||||
//
|
||||
// Reasoning is as below:
|
||||
// typeswitch is a binary search with a branch to a code-point.
|
||||
// getdecfn is a binary search with a call to a function pointer.
|
||||
//
|
||||
// both are about the same.
|
||||
//
|
||||
// so: why prefer typeswitch?
|
||||
//
|
||||
// is recognized does the following:
|
||||
// - lookup rtid
|
||||
// - check if in sorted list
|
||||
// - calls decode(type switch)
|
||||
// - 1 or 2 binary search to a point in code
|
||||
// - branch there
|
||||
//
|
||||
// vs getdecfn
|
||||
// - lookup rtid
|
||||
// - check in sorted list for a function pointer
|
||||
// - calls it to decode using reflection (optimized)
|
||||
|
||||
// always set xDebug = false before releasing software
|
||||
xDebug = true
|
||||
)
|
||||
|
@ -224,32 +190,25 @@ const (
|
|||
// valueTypeInvalid = 0xff
|
||||
)
|
||||
|
||||
var valueTypeStrings = [...]string{
|
||||
"Unset",
|
||||
"Nil",
|
||||
"Int",
|
||||
"Uint",
|
||||
"Float",
|
||||
"Bool",
|
||||
"String",
|
||||
"Symbol",
|
||||
"Bytes",
|
||||
"Map",
|
||||
"Array",
|
||||
"Timestamp",
|
||||
"Ext",
|
||||
}
|
||||
|
||||
func (x valueType) String() string {
|
||||
switch x {
|
||||
case valueTypeNil:
|
||||
return "Nil"
|
||||
case valueTypeInt:
|
||||
return "Int"
|
||||
case valueTypeUint:
|
||||
return "Uint"
|
||||
case valueTypeFloat:
|
||||
return "Float"
|
||||
case valueTypeBool:
|
||||
return "Bool"
|
||||
case valueTypeString:
|
||||
return "String"
|
||||
case valueTypeSymbol:
|
||||
return "Symbol"
|
||||
case valueTypeBytes:
|
||||
return "Bytes"
|
||||
case valueTypeMap:
|
||||
return "Map"
|
||||
case valueTypeArray:
|
||||
return "Array"
|
||||
case valueTypeTimestamp:
|
||||
return "Timestamp"
|
||||
case valueTypeExt:
|
||||
return "Ext"
|
||||
if int(x) < len(valueTypeStrings) {
|
||||
return valueTypeStrings[x]
|
||||
}
|
||||
return strconv.FormatInt(int64(x), 10)
|
||||
}
|
||||
|
@ -408,85 +367,6 @@ var immutableKindsSet = [32]bool{
|
|||
// reflect.UnsafePointer
|
||||
}
|
||||
|
||||
var (
|
||||
recognizedRtids []uintptr
|
||||
recognizedRtidPtrs []uintptr
|
||||
recognizedRtidOrPtrs []uintptr
|
||||
recognizedRtidsLoaded bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
if !useLookupRecognizedTypes {
|
||||
return
|
||||
}
|
||||
if recognizedRtidsLoaded {
|
||||
panic("recognizedRtidsLoaded = true - cannot happen")
|
||||
}
|
||||
for _, v := range [...]interface{}{
|
||||
float32(0),
|
||||
float64(0),
|
||||
uintptr(0),
|
||||
uint(0),
|
||||
uint8(0),
|
||||
uint16(0),
|
||||
uint32(0),
|
||||
uint64(0),
|
||||
uintptr(0),
|
||||
int(0),
|
||||
int8(0),
|
||||
int16(0),
|
||||
int32(0),
|
||||
int64(0),
|
||||
bool(false),
|
||||
string(""),
|
||||
Raw{},
|
||||
[]byte(nil),
|
||||
} {
|
||||
rt := reflect.TypeOf(v)
|
||||
recognizedRtids = append(recognizedRtids, rt2id(rt))
|
||||
recognizedRtidPtrs = append(recognizedRtidPtrs, rt2id(reflect.PtrTo(rt)))
|
||||
}
|
||||
|
||||
// now sort it.
|
||||
sort.Sort(uintptrSlice(recognizedRtids))
|
||||
sort.Sort(uintptrSlice(recognizedRtidPtrs))
|
||||
recognizedRtidOrPtrs = make([]uintptr, len(recognizedRtids)+len(recognizedRtidPtrs))
|
||||
copy(recognizedRtidOrPtrs, recognizedRtids)
|
||||
copy(recognizedRtidOrPtrs[len(recognizedRtids):], recognizedRtidPtrs)
|
||||
sort.Sort(uintptrSlice(recognizedRtidOrPtrs))
|
||||
|
||||
recognizedRtidsLoaded = true
|
||||
}
|
||||
|
||||
func containsU(s []uintptr, v uintptr) bool {
|
||||
// return false // TODO: REMOVE
|
||||
h, i, j := 0, 0, len(s)
|
||||
for i < j {
|
||||
h = i + (j-i)/2
|
||||
if s[h] < v {
|
||||
i = h + 1
|
||||
} else {
|
||||
j = h
|
||||
}
|
||||
}
|
||||
if i < len(s) && s[i] == v {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isRecognizedRtid(rtid uintptr) bool {
|
||||
return containsU(recognizedRtids, rtid)
|
||||
}
|
||||
|
||||
func isRecognizedRtidPtr(rtid uintptr) bool {
|
||||
return containsU(recognizedRtidPtrs, rtid)
|
||||
}
|
||||
|
||||
func isRecognizedRtidOrPtr(rtid uintptr) bool {
|
||||
return containsU(recognizedRtidOrPtrs, rtid)
|
||||
}
|
||||
|
||||
// Selfer defines methods by which a value can encode or decode itself.
|
||||
//
|
||||
// Any type which implements Selfer will be able to encode or decode itself.
|
||||
|
@ -823,10 +703,10 @@ func (si *structFieldInfo) field(v reflect.Value, update bool) (rv2 reflect.Valu
|
|||
return v, true
|
||||
}
|
||||
|
||||
func (si *structFieldInfo) fieldval(v reflect.Value, update bool) reflect.Value {
|
||||
v, _ = si.field(v, update)
|
||||
return v
|
||||
}
|
||||
// func (si *structFieldInfo) fieldval(v reflect.Value, update bool) reflect.Value {
|
||||
// v, _ = si.field(v, update)
|
||||
// return v
|
||||
// }
|
||||
|
||||
func parseStructFieldInfo(fname string, stag string) *structFieldInfo {
|
||||
// if fname == "" {
|
||||
|
@ -1555,36 +1435,36 @@ func (c *codecFner) get(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (
|
|||
fn.fd = (*Decoder).kInt
|
||||
fn.fe = (*Encoder).kInt
|
||||
case reflect.Int8:
|
||||
fn.fe = (*Encoder).kInt
|
||||
fn.fe = (*Encoder).kInt8
|
||||
fn.fd = (*Decoder).kInt8
|
||||
case reflect.Int16:
|
||||
fn.fe = (*Encoder).kInt
|
||||
fn.fe = (*Encoder).kInt16
|
||||
fn.fd = (*Decoder).kInt16
|
||||
case reflect.Int32:
|
||||
fn.fe = (*Encoder).kInt
|
||||
fn.fe = (*Encoder).kInt32
|
||||
fn.fd = (*Decoder).kInt32
|
||||
case reflect.Int64:
|
||||
fn.fe = (*Encoder).kInt
|
||||
fn.fe = (*Encoder).kInt64
|
||||
fn.fd = (*Decoder).kInt64
|
||||
case reflect.Uint:
|
||||
fn.fd = (*Decoder).kUint
|
||||
fn.fe = (*Encoder).kUint
|
||||
case reflect.Uint8:
|
||||
fn.fe = (*Encoder).kUint
|
||||
fn.fe = (*Encoder).kUint8
|
||||
fn.fd = (*Decoder).kUint8
|
||||
case reflect.Uint16:
|
||||
fn.fe = (*Encoder).kUint
|
||||
fn.fe = (*Encoder).kUint16
|
||||
fn.fd = (*Decoder).kUint16
|
||||
case reflect.Uint32:
|
||||
fn.fe = (*Encoder).kUint
|
||||
fn.fe = (*Encoder).kUint32
|
||||
fn.fd = (*Decoder).kUint32
|
||||
case reflect.Uint64:
|
||||
fn.fe = (*Encoder).kUint
|
||||
fn.fe = (*Encoder).kUint64
|
||||
fn.fd = (*Decoder).kUint64
|
||||
// case reflect.Ptr:
|
||||
// fn.fd = (*Decoder).kPtr
|
||||
case reflect.Uintptr:
|
||||
fn.fe = (*Encoder).kUint
|
||||
fn.fe = (*Encoder).kUintptr
|
||||
fn.fd = (*Decoder).kUintptr
|
||||
case reflect.Float32:
|
||||
fn.fe = (*Encoder).kFloat32
|
||||
|
@ -1594,6 +1474,7 @@ func (c *codecFner) get(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (
|
|||
fn.fd = (*Decoder).kFloat64
|
||||
case reflect.Invalid:
|
||||
fn.fe = (*Encoder).kInvalid
|
||||
fn.fd = (*Decoder).kErr
|
||||
case reflect.Chan:
|
||||
fi.seq = seqTypeChan
|
||||
fn.fe = (*Encoder).kSlice
|
||||
|
@ -1631,6 +1512,7 @@ func (c *codecFner) get(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (
|
|||
case reflect.Interface:
|
||||
// encode: reflect.Interface are handled already by preEncodeValue
|
||||
fn.fd = (*Decoder).kInterface
|
||||
fn.fe = (*Encoder).kErr
|
||||
default:
|
||||
fn.fe = (*Encoder).kErr
|
||||
fn.fd = (*Decoder).kErr
|
||||
|
@ -1886,39 +1768,42 @@ func (s *set) remove(v uintptr) (exists bool) {
|
|||
|
||||
type bitset256 [32]byte
|
||||
|
||||
func (x *bitset256) set(pos byte) {
|
||||
x[pos>>3] |= (1 << (pos & 7))
|
||||
}
|
||||
func (x *bitset256) unset(pos byte) {
|
||||
x[pos>>3] &^= (1 << (pos & 7))
|
||||
}
|
||||
func (x *bitset256) isset(pos byte) bool {
|
||||
return x[pos>>3]&(1<<(pos&7)) != 0
|
||||
}
|
||||
func (x *bitset256) set(pos byte) {
|
||||
x[pos>>3] |= (1 << (pos & 7))
|
||||
}
|
||||
|
||||
// func (x *bitset256) unset(pos byte) {
|
||||
// x[pos>>3] &^= (1 << (pos & 7))
|
||||
// }
|
||||
|
||||
type bitset128 [16]byte
|
||||
|
||||
func (x *bitset128) set(pos byte) {
|
||||
x[pos>>3] |= (1 << (pos & 7))
|
||||
}
|
||||
func (x *bitset128) unset(pos byte) {
|
||||
x[pos>>3] &^= (1 << (pos & 7))
|
||||
}
|
||||
func (x *bitset128) isset(pos byte) bool {
|
||||
return x[pos>>3]&(1<<(pos&7)) != 0
|
||||
}
|
||||
func (x *bitset128) set(pos byte) {
|
||||
x[pos>>3] |= (1 << (pos & 7))
|
||||
}
|
||||
|
||||
// func (x *bitset128) unset(pos byte) {
|
||||
// x[pos>>3] &^= (1 << (pos & 7))
|
||||
// }
|
||||
|
||||
type bitset32 [4]byte
|
||||
|
||||
func (x *bitset32) set(pos byte) {
|
||||
x[pos>>3] |= (1 << (pos & 7))
|
||||
}
|
||||
func (x *bitset32) unset(pos byte) {
|
||||
x[pos>>3] &^= (1 << (pos & 7))
|
||||
}
|
||||
func (x *bitset32) isset(pos byte) bool {
|
||||
return x[pos>>3]&(1<<(pos&7)) != 0
|
||||
}
|
||||
func (x *bitset32) set(pos byte) {
|
||||
x[pos>>3] |= (1 << (pos & 7))
|
||||
}
|
||||
|
||||
// func (x *bitset32) unset(pos byte) {
|
||||
// x[pos>>3] &^= (1 << (pos & 7))
|
||||
// }
|
||||
|
||||
// ------------
|
||||
|
||||
|
|
|
@ -158,3 +158,65 @@ func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) {
|
|||
func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) {
|
||||
rv.SetUint(d.d.DecodeUint(64))
|
||||
}
|
||||
|
||||
// ----------------
|
||||
|
||||
func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeBool(rv.Bool())
|
||||
}
|
||||
|
||||
func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeString(c_UTF8, rv.String())
|
||||
}
|
||||
|
||||
func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeFloat64(rv.Float())
|
||||
}
|
||||
|
||||
func (e *Encoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeFloat32(float32(rv.Float()))
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeInt(rv.Int())
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt8(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeInt(rv.Int())
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt16(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeInt(rv.Int())
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt32(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeInt(rv.Int())
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt64(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeInt(rv.Int())
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeUint(rv.Uint())
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint8(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeUint(rv.Uint())
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint16(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeUint(rv.Uint())
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint32(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeUint(rv.Uint())
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint64(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeUint(rv.Uint())
|
||||
}
|
||||
|
||||
func (e *Encoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
|
||||
e.e.EncodeUint(rv.Uint())
|
||||
}
|
||||
|
|
|
@ -219,6 +219,83 @@ func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) {
|
|||
|
||||
// ------------
|
||||
|
||||
func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeBool(*(*bool)(v.ptr))
|
||||
}
|
||||
|
||||
func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeString(c_UTF8, *(*string)(v.ptr))
|
||||
}
|
||||
|
||||
func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeFloat64(*(*float64)(v.ptr))
|
||||
}
|
||||
|
||||
func (e *Encoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeFloat32(*(*float32)(v.ptr))
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeInt(int64(*(*int)(v.ptr)))
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt8(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeInt(int64(*(*int8)(v.ptr)))
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt16(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeInt(int64(*(*int16)(v.ptr)))
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt32(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeInt(int64(*(*int32)(v.ptr)))
|
||||
}
|
||||
|
||||
func (e *Encoder) kInt64(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeInt(int64(*(*int64)(v.ptr)))
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeUint(uint64(*(*uint)(v.ptr)))
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint8(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeUint(uint64(*(*uint8)(v.ptr)))
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint16(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeUint(uint64(*(*uint16)(v.ptr)))
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint32(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeUint(uint64(*(*uint32)(v.ptr)))
|
||||
}
|
||||
|
||||
func (e *Encoder) kUint64(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeUint(uint64(*(*uint64)(v.ptr)))
|
||||
}
|
||||
|
||||
func (e *Encoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
|
||||
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
|
||||
e.e.EncodeUint(uint64(*(*uintptr)(v.ptr)))
|
||||
}
|
||||
|
||||
// ------------
|
||||
|
||||
// func rt2id(rt reflect.Type) uintptr {
|
||||
// return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word)
|
||||
// // var i interface{} = rt
|
||||
|
|
|
@ -49,11 +49,11 @@ func doTestMammothSlices(t *testing.T, h Handle) {
|
|||
// fmt.Printf(">>>> running mammoth slice v{{$i}}: %v\n", v)
|
||||
var v{{$i}}v1, v{{$i}}v2, v{{$i}}v3, v{{$i}}v4 []{{ .Elem }}
|
||||
v{{$i}}v1 = v
|
||||
bs{{$i}}, _ := testMarshalErr(v{{$i}}v1, h, t, "enc-slice-v{{$i}}")
|
||||
bs{{$i}} := testMarshalErr(v{{$i}}v1, h, t, "enc-slice-v{{$i}}")
|
||||
if v != nil { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) }
|
||||
testUnmarshalErr(v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}")
|
||||
testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}")
|
||||
bs{{$i}}, _ = testMarshalErr(&v{{$i}}v1, h, t, "enc-slice-v{{$i}}-p")
|
||||
bs{{$i}} = testMarshalErr(&v{{$i}}v1, h, t, "enc-slice-v{{$i}}-p")
|
||||
v{{$i}}v2 = nil
|
||||
testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p")
|
||||
testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p")
|
||||
|
@ -61,12 +61,12 @@ func doTestMammothSlices(t *testing.T, h Handle) {
|
|||
v{{$i}}v2 = nil
|
||||
if v != nil { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) }
|
||||
v{{$i}}v3 = {{ .MethodNamePfx "type" false }}(v{{$i}}v1)
|
||||
bs{{$i}}, _ = testMarshalErr(v{{$i}}v3, h, t, "enc-slice-v{{$i}}-custom")
|
||||
bs{{$i}} = testMarshalErr(v{{$i}}v3, h, t, "enc-slice-v{{$i}}-custom")
|
||||
v{{$i}}v4 = {{ .MethodNamePfx "type" false }}(v{{$i}}v2)
|
||||
testUnmarshalErr(v{{$i}}v4, bs{{$i}}, h, t, "dec-slice-v{{$i}}-custom")
|
||||
testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-slice-v{{$i}}-custom")
|
||||
v{{$i}}v2 = nil
|
||||
bs{{$i}}, _ = testMarshalErr(&v{{$i}}v3, h, t, "enc-slice-v{{$i}}-custom-p")
|
||||
bs{{$i}} = testMarshalErr(&v{{$i}}v3, h, t, "enc-slice-v{{$i}}-custom-p")
|
||||
v{{$i}}v4 = {{ .MethodNamePfx "type" false }}(v{{$i}}v2)
|
||||
testUnmarshalErr(&v{{$i}}v4, bs{{$i}}, h, t, "dec-slice-v{{$i}}-custom-p")
|
||||
testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-slice-v{{$i}}-custom-p")
|
||||
|
@ -81,11 +81,11 @@ func doTestMammothMaps(t *testing.T, h Handle) {
|
|||
// fmt.Printf(">>>> running mammoth map v{{$i}}: %v\n", v)
|
||||
var v{{$i}}v1, v{{$i}}v2 map[{{ .MapKey }}]{{ .Elem }}
|
||||
v{{$i}}v1 = v
|
||||
bs{{$i}}, _ := testMarshalErr(v{{$i}}v1, h, t, "enc-map-v{{$i}}")
|
||||
bs{{$i}} := testMarshalErr(v{{$i}}v1, h, t, "enc-map-v{{$i}}")
|
||||
if v != nil { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) }
|
||||
testUnmarshalErr(v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}")
|
||||
testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}")
|
||||
bs{{$i}}, _ = testMarshalErr(&v{{$i}}v1, h, t, "enc-map-v{{$i}}-p")
|
||||
bs{{$i}} = testMarshalErr(&v{{$i}}v1, h, t, "enc-map-v{{$i}}-p")
|
||||
v{{$i}}v2 = nil
|
||||
testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}-p")
|
||||
testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}-p")
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
// +build !notfastpath
|
||||
|
||||
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||
|
||||
// ************************************************************
|
||||
// DO NOT EDIT.
|
||||
// THIS FILE IS AUTO-GENERATED from mammoth2-test.go.tmpl
|
||||
// ************************************************************
|
||||
|
||||
package codec
|
||||
|
||||
// Increase codecoverage by covering all the codecgen paths, in fast-path and gen-helper.go....
|
||||
//
|
||||
// Add:
|
||||
// - test file for creating a mammoth generated file as _mammoth_generated.go
|
||||
// - generate a second mammoth files in a different file: mammoth2_generated_test.go
|
||||
// - mammoth-test.go.tmpl will do this
|
||||
// - run codecgen on it, into mammoth2_codecgen_generated_test.go (no build tags)
|
||||
// - as part of TestMammoth, run it also
|
||||
// - this will cover all the codecgen, gen-helper, etc in one full run
|
||||
// - check in mammoth* files into github also
|
||||
// - then
|
||||
//
|
||||
// Now, add some types:
|
||||
// - some that implement BinaryMarshal, TextMarshal, JSONMarshal, and one that implements none of it
|
||||
// - create a wrapper type that includes TestMammoth2, with it in slices, and maps, and the custom types
|
||||
// - this wrapper object is what we work encode/decode (so that the codecgen methods are called)
|
||||
|
||||
|
||||
// import "encoding/binary"
|
||||
import "fmt"
|
||||
|
||||
type TestMammoth2 struct {
|
||||
|
||||
{{range .Values }}{{if .Primitive }}{{/*
|
||||
*/}}{{ .MethodNamePfx "F" true }} {{ .Primitive }}
|
||||
{{ .MethodNamePfx "Fptr" true }} *{{ .Primitive }}
|
||||
{{end}}{{end}}
|
||||
|
||||
{{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/*
|
||||
*/}}{{ .MethodNamePfx "F" false }} []{{ .Elem }}
|
||||
{{ .MethodNamePfx "Fptr" false }} *[]{{ .Elem }}
|
||||
{{end}}{{end}}{{end}}
|
||||
|
||||
{{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/*
|
||||
*/}}{{ .MethodNamePfx "F" false }} map[{{ .MapKey }}]{{ .Elem }}
|
||||
{{ .MethodNamePfx "Fptr" false }} *map[{{ .MapKey }}]{{ .Elem }}
|
||||
{{end}}{{end}}{{end}}
|
||||
|
||||
}
|
||||
|
||||
// -----------
|
||||
|
||||
type testMammoth2Binary uint64
|
||||
func (x testMammoth2Binary) MarshalBinary() (data []byte, err error) {
|
||||
data = make([]byte, 8)
|
||||
bigen.PutUint64(data, uint64(x))
|
||||
return
|
||||
}
|
||||
func (x *testMammoth2Binary) UnmarshalBinary(data []byte) (err error) {
|
||||
*x = testMammoth2Binary(bigen.Uint64(data))
|
||||
return
|
||||
}
|
||||
|
||||
type testMammoth2Text uint64
|
||||
func (x testMammoth2Text) MarshalText() (data []byte, err error) {
|
||||
data = []byte(fmt.Sprintf("%b", uint64(x)))
|
||||
return
|
||||
}
|
||||
func (x *testMammoth2Text) UnmarshalText(data []byte) (err error) {
|
||||
_, err = fmt.Sscanf(string(data), "%b", (*uint64)(x))
|
||||
return
|
||||
}
|
||||
|
||||
type testMammoth2Json uint64
|
||||
func (x testMammoth2Json) MarshalJSON() (data []byte, err error) {
|
||||
data = []byte(fmt.Sprintf("%v", uint64(x)))
|
||||
return
|
||||
}
|
||||
func (x *testMammoth2Json) UnmarshalJSON(data []byte) (err error) {
|
||||
_, err = fmt.Sscanf(string(data), "%v", (*uint64)(x))
|
||||
return
|
||||
}
|
||||
|
||||
type testMammoth2Basic [4]uint64
|
||||
|
||||
type TestMammoth2Wrapper struct {
|
||||
V TestMammoth2
|
||||
T testMammoth2Text
|
||||
B testMammoth2Binary
|
||||
J testMammoth2Json
|
||||
C testMammoth2Basic
|
||||
M map[testMammoth2Basic]TestMammoth2
|
||||
L []TestMammoth2
|
||||
A [4]int64
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue