Upgrade k8s.io/client-go to version 2

This commit is contained in:
Ed Robinson 2017-04-07 11:49:53 +01:00
parent a3b95f798b
commit 6f4c5dd4ce
No known key found for this signature in database
GPG key ID: EC501FCA6421CCF0
675 changed files with 109006 additions and 90744 deletions

255
glide.lock generated
View file

@ -1,12 +1,13 @@
hash: fa4c40400ed94e105a9a1a0d163ac9c4ecea4598ad4ee4fef5237a39d4f28d0a hash: b1cbcbd938a47a246b0d4d634037b76e63486c63e5867b339f92bcbd7453b75c
updated: 2017-04-07T10:50:34.091189379+01:00 updated: 2017-04-07T11:34:46.101385591+01:00
imports: imports:
- name: bitbucket.org/ww/goautoneg - name: bitbucket.org/ww/goautoneg
version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675 version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675
- name: cloud.google.com/go - name: cloud.google.com/go
version: c116c7972ec94f148459a304d07a67ecbc770d4b version: 2e6a95edb1071d750f6d7db777bf66cd2997af6c
subpackages: subpackages:
- compute/metadata - compute/metadata
- internal
- name: github.com/abbot/go-http-auth - name: github.com/abbot/go-http-auth
version: cb4372376e1e00e9f6ab9ec142e029302c9e7140 version: cb4372376e1e00e9f6ab9ec142e029302c9e7140
- name: github.com/ArthurHlt/go-eureka-client - name: github.com/ArthurHlt/go-eureka-client
@ -112,9 +113,8 @@ imports:
subpackages: subpackages:
- daemon - daemon
- name: github.com/coreos/pkg - name: github.com/coreos/pkg
version: 2c77715c4df99b5420ffcae14ead08f52104065d version: fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
subpackages: subpackages:
- capnslog
- health - health
- httputil - httputil
- timeutil - timeutil
@ -239,6 +239,8 @@ imports:
- query - query
- name: github.com/google/gofuzz - name: github.com/google/gofuzz
version: bbcb9da2d746f8bdbd6a936686a0a6067ada0ec5 version: bbcb9da2d746f8bdbd6a936686a0a6067ada0ec5
- name: github.com/googleapis/gax-go
version: 9af46dd5a1713e8b5cd71106287eba3cefdde50b
- name: github.com/gorilla/context - name: github.com/gorilla/context
version: 1ea25387ff6f684839d82767c1733ff4d4d15d0a version: 1ea25387ff6f684839d82767c1733ff4d4d15d0a
- name: github.com/gorilla/websocket - name: github.com/gorilla/websocket
@ -369,7 +371,7 @@ imports:
- name: github.com/Sirupsen/logrus - name: github.com/Sirupsen/logrus
version: a283a10442df8dc09befd873fab202bf8a253d6a version: a283a10442df8dc09befd873fab202bf8a253d6a
- name: github.com/spf13/pflag - name: github.com/spf13/pflag
version: 5644820622454e71517561946e3d94b9f9db6842 version: 5ccb023bc27df288a957c5e994cd44fd19619465
- name: github.com/streamrail/concurrent-map - name: github.com/streamrail/concurrent-map
version: 65a174a3a4188c0b7099acbc6cfa0c53628d3287 version: 65a174a3a4188c0b7099acbc6cfa0c53628d3287
- name: github.com/stretchr/objx - name: github.com/stretchr/objx
@ -457,11 +459,13 @@ imports:
- http2 - http2
- http2/hpack - http2/hpack
- idna - idna
- internal/timeseries
- lex/httplex - lex/httplex
- proxy - proxy
- publicsuffix - publicsuffix
- trace
- name: golang.org/x/oauth2 - name: golang.org/x/oauth2
version: 3046bc76d6dfd7d3707f6640f85e42d9c4050f50 version: 7fdf09982454086d5570c7db3e11f360194830ca
subpackages: subpackages:
- google - google
- internal - internal
@ -473,13 +477,9 @@ imports:
- unix - unix
- windows - windows
- name: golang.org/x/text - name: golang.org/x/text
version: a49bea13b776691cb1b49873e5d8df96ec74831a version: 2910a502d2bf9e43193af9d68ca516529614eed3
repo: https://github.com/golang/text.git
vcs: git
subpackages: subpackages:
- .
- cases - cases
- internal
- internal/tag - internal/tag
- language - language
- runes - runes
@ -497,7 +497,7 @@ imports:
- googleapi - googleapi
- googleapi/internal/uritemplates - googleapi/internal/uritemplates
- name: google.golang.org/appengine - name: google.golang.org/appengine
version: 12d5545dc1cfa6047a286d5e853841b6471f4c19 version: 4f7eeb5305a4ba1966344836ba4af9996b7b4e05
subpackages: subpackages:
- internal - internal
- internal/app_identity - internal/app_identity
@ -508,11 +508,20 @@ imports:
- internal/remote_api - internal/remote_api
- internal/urlfetch - internal/urlfetch
- urlfetch - urlfetch
- name: google.golang.org/cloud - name: google.golang.org/grpc
version: f20d6dcccb44ed49de45ae3703312cb46e627db1 version: cdee119ee21e61eef7093a41ba148fa83585e143
subpackages: subpackages:
- compute/metadata - codes
- credentials
- grpclog
- internal - internal
- keepalive
- metadata
- naming
- peer
- stats
- tap
- transport
- name: gopkg.in/fsnotify.v1 - name: gopkg.in/fsnotify.v1
version: a8a77c9133d2d6fd8334f3260d06f60e8d80a5fb version: a8a77c9133d2d6fd8334f3260d06f60e8d80a5fb
- name: gopkg.in/inf.v0 - name: gopkg.in/inf.v0
@ -538,111 +547,115 @@ imports:
- cipher - cipher
- json - json
- name: gopkg.in/yaml.v2 - name: gopkg.in/yaml.v2
version: bef53efd0c76e49e6de55ead051f886bea7e9420 version: 53feefa2559fb8dfa8d81baad31be332c97d6c77
- name: k8s.io/client-go - name: k8s.io/client-go
version: 1195e3a8ee1a529d53eed7c624527a68555ddf1f version: e121606b0d09b2e1c467183ee46217fa85a6b672
subpackages: subpackages:
- 1.5/discovery - discovery
- 1.5/kubernetes - kubernetes
- 1.5/kubernetes/typed/apps/v1alpha1 - kubernetes/typed/apps/v1beta1
- 1.5/kubernetes/typed/authentication/v1beta1 - kubernetes/typed/authentication/v1beta1
- 1.5/kubernetes/typed/authorization/v1beta1 - kubernetes/typed/authorization/v1beta1
- 1.5/kubernetes/typed/autoscaling/v1 - kubernetes/typed/autoscaling/v1
- 1.5/kubernetes/typed/batch/v1 - kubernetes/typed/batch/v1
- 1.5/kubernetes/typed/certificates/v1alpha1 - kubernetes/typed/batch/v2alpha1
- 1.5/kubernetes/typed/core/v1 - kubernetes/typed/certificates/v1alpha1
- 1.5/kubernetes/typed/extensions/v1beta1 - kubernetes/typed/core/v1
- 1.5/kubernetes/typed/policy/v1alpha1 - kubernetes/typed/extensions/v1beta1
- 1.5/kubernetes/typed/rbac/v1alpha1 - kubernetes/typed/policy/v1beta1
- 1.5/kubernetes/typed/storage/v1beta1 - kubernetes/typed/rbac/v1alpha1
- 1.5/pkg/api - kubernetes/typed/storage/v1beta1
- 1.5/pkg/api/errors - pkg/api
- 1.5/pkg/api/install - pkg/api/errors
- 1.5/pkg/api/meta - pkg/api/install
- 1.5/pkg/api/meta/metatypes - pkg/api/meta
- 1.5/pkg/api/resource - pkg/api/meta/metatypes
- 1.5/pkg/api/unversioned - pkg/api/resource
- 1.5/pkg/api/v1 - pkg/api/unversioned
- 1.5/pkg/api/validation/path - pkg/api/v1
- 1.5/pkg/apimachinery - pkg/api/validation/path
- 1.5/pkg/apimachinery/announced - pkg/apimachinery
- 1.5/pkg/apimachinery/registered - pkg/apimachinery/announced
- 1.5/pkg/apis/apps - pkg/apimachinery/registered
- 1.5/pkg/apis/apps/install - pkg/apis/apps
- 1.5/pkg/apis/apps/v1alpha1 - pkg/apis/apps/install
- 1.5/pkg/apis/authentication - pkg/apis/apps/v1beta1
- 1.5/pkg/apis/authentication/install - pkg/apis/authentication
- 1.5/pkg/apis/authentication/v1beta1 - pkg/apis/authentication/install
- 1.5/pkg/apis/authorization - pkg/apis/authentication/v1beta1
- 1.5/pkg/apis/authorization/install - pkg/apis/authorization
- 1.5/pkg/apis/authorization/v1beta1 - pkg/apis/authorization/install
- 1.5/pkg/apis/autoscaling - pkg/apis/authorization/v1beta1
- 1.5/pkg/apis/autoscaling/install - pkg/apis/autoscaling
- 1.5/pkg/apis/autoscaling/v1 - pkg/apis/autoscaling/install
- 1.5/pkg/apis/batch - pkg/apis/autoscaling/v1
- 1.5/pkg/apis/batch/install - pkg/apis/batch
- 1.5/pkg/apis/batch/v1 - pkg/apis/batch/install
- 1.5/pkg/apis/batch/v2alpha1 - pkg/apis/batch/v1
- 1.5/pkg/apis/certificates - pkg/apis/batch/v2alpha1
- 1.5/pkg/apis/certificates/install - pkg/apis/certificates
- 1.5/pkg/apis/certificates/v1alpha1 - pkg/apis/certificates/install
- 1.5/pkg/apis/extensions - pkg/apis/certificates/v1alpha1
- 1.5/pkg/apis/extensions/install - pkg/apis/extensions
- 1.5/pkg/apis/extensions/v1beta1 - pkg/apis/extensions/install
- 1.5/pkg/apis/policy - pkg/apis/extensions/v1beta1
- 1.5/pkg/apis/policy/install - pkg/apis/policy
- 1.5/pkg/apis/policy/v1alpha1 - pkg/apis/policy/install
- 1.5/pkg/apis/rbac - pkg/apis/policy/v1beta1
- 1.5/pkg/apis/rbac/install - pkg/apis/rbac
- 1.5/pkg/apis/rbac/v1alpha1 - pkg/apis/rbac/install
- 1.5/pkg/apis/storage - pkg/apis/rbac/v1alpha1
- 1.5/pkg/apis/storage/install - pkg/apis/storage
- 1.5/pkg/apis/storage/v1beta1 - pkg/apis/storage/install
- 1.5/pkg/auth/user - pkg/apis/storage/v1beta1
- 1.5/pkg/conversion - pkg/auth/user
- 1.5/pkg/conversion/queryparams - pkg/conversion
- 1.5/pkg/fields - pkg/conversion/queryparams
- 1.5/pkg/genericapiserver/openapi/common - pkg/fields
- 1.5/pkg/labels - pkg/genericapiserver/openapi/common
- 1.5/pkg/runtime - pkg/labels
- 1.5/pkg/runtime/serializer - pkg/runtime
- 1.5/pkg/runtime/serializer/json - pkg/runtime/serializer
- 1.5/pkg/runtime/serializer/protobuf - pkg/runtime/serializer/json
- 1.5/pkg/runtime/serializer/recognizer - pkg/runtime/serializer/protobuf
- 1.5/pkg/runtime/serializer/streaming - pkg/runtime/serializer/recognizer
- 1.5/pkg/runtime/serializer/versioning - pkg/runtime/serializer/streaming
- 1.5/pkg/selection - pkg/runtime/serializer/versioning
- 1.5/pkg/third_party/forked/golang/reflect - pkg/selection
- 1.5/pkg/types - pkg/third_party/forked/golang/reflect
- 1.5/pkg/util - pkg/third_party/forked/golang/template
- 1.5/pkg/util/cert - pkg/types
- 1.5/pkg/util/clock - pkg/util
- 1.5/pkg/util/errors - pkg/util/cert
- 1.5/pkg/util/flowcontrol - pkg/util/clock
- 1.5/pkg/util/framer - pkg/util/diff
- 1.5/pkg/util/integer - pkg/util/errors
- 1.5/pkg/util/intstr - pkg/util/flowcontrol
- 1.5/pkg/util/json - pkg/util/framer
- 1.5/pkg/util/labels - pkg/util/integer
- 1.5/pkg/util/net - pkg/util/intstr
- 1.5/pkg/util/parsers - pkg/util/json
- 1.5/pkg/util/rand - pkg/util/jsonpath
- 1.5/pkg/util/runtime - pkg/util/labels
- 1.5/pkg/util/sets - pkg/util/net
- 1.5/pkg/util/uuid - pkg/util/parsers
- 1.5/pkg/util/validation - pkg/util/rand
- 1.5/pkg/util/validation/field - pkg/util/runtime
- 1.5/pkg/util/wait - pkg/util/sets
- 1.5/pkg/util/yaml - pkg/util/uuid
- 1.5/pkg/version - pkg/util/validation
- 1.5/pkg/watch - pkg/util/validation/field
- 1.5/pkg/watch/versioned - pkg/util/wait
- 1.5/plugin/pkg/client/auth - pkg/util/yaml
- 1.5/plugin/pkg/client/auth/gcp - pkg/version
- 1.5/plugin/pkg/client/auth/oidc - pkg/watch
- 1.5/rest - pkg/watch/versioned
- 1.5/tools/cache - plugin/pkg/client/auth
- 1.5/tools/clientcmd/api - plugin/pkg/client/auth/gcp
- 1.5/tools/metrics - plugin/pkg/client/auth/oidc
- 1.5/transport - rest
- tools/cache
- tools/clientcmd/api
- tools/metrics
- transport
testImports: [] testImports: []

View file

@ -89,7 +89,7 @@ import:
- package: github.com/satori/go.uuid - package: github.com/satori/go.uuid
version: ^1.1.0 version: ^1.1.0
- package: k8s.io/client-go - package: k8s.io/client-go
version: ^v1.5.0 version: v2.0.0
- package: github.com/gambol99/go-marathon - package: github.com/gambol99/go-marathon
version: ^0.5.1 version: ^0.5.1
- package: github.com/ArthurHlt/go-eureka-client - package: github.com/ArthurHlt/go-eureka-client
@ -131,7 +131,7 @@ import:
- service/ec2 - service/ec2
- service/ecs - service/ecs
- package: cloud.google.com/go - package: cloud.google.com/go
version: v0.6.0 version: v0.7.0
subpackages: subpackages:
- compute/metadata - compute/metadata
- package: github.com/gogo/protobuf - package: github.com/gogo/protobuf
@ -140,3 +140,9 @@ import:
- proto - proto
- package: github.com/rancher/go-rancher - package: github.com/rancher/go-rancher
version: 2c43ff300f3eafcbd7d0b89b10427fc630efdc1e version: 2c43ff300f3eafcbd7d0b89b10427fc630efdc1e
- package: golang.org/x/oauth2/google
version: 7fdf09982454086d5570c7db3e11f360194830ca
- package: github.com/googleapis/gax-go
version: 9af46dd5a1713e8b5cd71106287eba3cefdde50b
- package: google.golang.org/grpc
version: v1.2.0

View file

@ -6,16 +6,16 @@ import (
"io/ioutil" "io/ioutil"
"time" "time"
"k8s.io/client-go/1.5/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/client-go/1.5/pkg/api" "k8s.io/client-go/pkg/api"
"k8s.io/client-go/1.5/pkg/api/v1" "k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1" "k8s.io/client-go/pkg/apis/extensions/v1beta1"
"k8s.io/client-go/1.5/pkg/fields" "k8s.io/client-go/pkg/fields"
"k8s.io/client-go/1.5/pkg/labels" "k8s.io/client-go/pkg/labels"
"k8s.io/client-go/1.5/pkg/runtime" "k8s.io/client-go/pkg/runtime"
"k8s.io/client-go/1.5/pkg/watch" "k8s.io/client-go/pkg/watch"
"k8s.io/client-go/1.5/rest" "k8s.io/client-go/rest"
"k8s.io/client-go/1.5/tools/cache" "k8s.io/client-go/tools/cache"
) )
const resyncPeriod = time.Minute * 5 const resyncPeriod = time.Minute * 5
@ -111,7 +111,7 @@ func (c *clientImpl) GetIngresses(namespaces Namespaces) []*v1beta1.Ingress {
// WatchIngresses starts the watch of Kubernetes Ingresses resources and updates the corresponding store // WatchIngresses starts the watch of Kubernetes Ingresses resources and updates the corresponding store
func (c *clientImpl) WatchIngresses(labelSelector labels.Selector, watchCh chan<- interface{}, stopCh <-chan struct{}) { func (c *clientImpl) WatchIngresses(labelSelector labels.Selector, watchCh chan<- interface{}, stopCh <-chan struct{}) {
source := NewListWatchFromClient( source := NewListWatchFromClient(
c.clientset.ExtensionsClient, c.clientset.ExtensionsV1beta1().RESTClient(),
"ingresses", "ingresses",
api.NamespaceAll, api.NamespaceAll,
fields.Everything(), fields.Everything(),
@ -157,7 +157,7 @@ func (c *clientImpl) GetService(namespace, name string) (*v1.Service, bool, erro
// WatchServices starts the watch of Kubernetes Service resources and updates the corresponding store // WatchServices starts the watch of Kubernetes Service resources and updates the corresponding store
func (c *clientImpl) WatchServices(watchCh chan<- interface{}, stopCh <-chan struct{}) { func (c *clientImpl) WatchServices(watchCh chan<- interface{}, stopCh <-chan struct{}) {
source := cache.NewListWatchFromClient( source := cache.NewListWatchFromClient(
c.clientset.CoreClient, c.clientset.CoreV1().RESTClient(),
"services", "services",
api.NamespaceAll, api.NamespaceAll,
fields.Everything()) fields.Everything())
@ -186,7 +186,7 @@ func (c *clientImpl) GetEndpoints(namespace, name string) (*v1.Endpoints, bool,
// WatchEndpoints starts the watch of Kubernetes Endpoints resources and updates the corresponding store // WatchEndpoints starts the watch of Kubernetes Endpoints resources and updates the corresponding store
func (c *clientImpl) WatchEndpoints(watchCh chan<- interface{}, stopCh <-chan struct{}) { func (c *clientImpl) WatchEndpoints(watchCh chan<- interface{}, stopCh <-chan struct{}) {
source := cache.NewListWatchFromClient( source := cache.NewListWatchFromClient(
c.clientset.CoreClient, c.clientset.CoreV1().RESTClient(),
"endpoints", "endpoints",
api.NamespaceAll, api.NamespaceAll,
fields.Everything()) fields.Everything())

View file

@ -15,8 +15,8 @@ import (
"github.com/containous/traefik/provider/k8s" "github.com/containous/traefik/provider/k8s"
"github.com/containous/traefik/safe" "github.com/containous/traefik/safe"
"github.com/containous/traefik/types" "github.com/containous/traefik/types"
"k8s.io/client-go/1.5/pkg/api/v1" "k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/1.5/pkg/util/intstr" "k8s.io/client-go/pkg/util/intstr"
) )
var _ Provider = (*Kubernetes)(nil) var _ Provider = (*Kubernetes)(nil)

View file

@ -9,9 +9,9 @@ import (
"github.com/containous/traefik/provider/k8s" "github.com/containous/traefik/provider/k8s"
"github.com/containous/traefik/types" "github.com/containous/traefik/types"
"k8s.io/client-go/1.5/pkg/api/v1" "k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1" "k8s.io/client-go/pkg/apis/extensions/v1beta1"
"k8s.io/client-go/1.5/pkg/util/intstr" "k8s.io/client-go/pkg/util/intstr"
) )
func TestLoadIngresses(t *testing.T) { func TestLoadIngresses(t *testing.T) {

64
vendor/cloud.google.com/go/internal/cloud.go generated vendored Normal file
View file

@ -0,0 +1,64 @@
// Copyright 2014 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 provides support for the cloud packages.
//
// Users should not import this package directly.
package internal
import (
"fmt"
"net/http"
)
const userAgent = "gcloud-golang/0.1"
// Transport is an http.RoundTripper that appends Google Cloud client's
// user-agent to the original request's user-agent header.
type Transport struct {
// TODO(bradfitz): delete internal.Transport. It's too wrappy for what it does.
// Do User-Agent some other way.
// Base is the actual http.RoundTripper
// requests will use. It must not be nil.
Base http.RoundTripper
}
// RoundTrip appends a user-agent to the existing user-agent
// header and delegates the request to the base http.RoundTripper.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
req = cloneRequest(req)
ua := req.Header.Get("User-Agent")
if ua == "" {
ua = userAgent
} else {
ua = fmt.Sprintf("%s %s", ua, userAgent)
}
req.Header.Set("User-Agent", ua)
return t.Base.RoundTrip(req)
}
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
// shallow copy of the struct
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header)
for k, s := range r.Header {
r2.Header[k] = s
}
return r2
}

55
vendor/cloud.google.com/go/internal/retry.go generated vendored Normal file
View file

@ -0,0 +1,55 @@
// Copyright 2016 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"
"time"
gax "github.com/googleapis/gax-go"
"golang.org/x/net/context"
)
// Retry calls the supplied function f repeatedly according to the provided
// backoff parameters. It returns when one of the following occurs:
// When f's first return value is true, Retry immediately returns with f's second
// return value.
// When the provided context is done, Retry returns with ctx.Err().
func Retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error)) error {
return retry(ctx, bo, f, gax.Sleep)
}
func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error),
sleep func(context.Context, time.Duration) error) error {
var lastErr error
for {
stop, err := f()
if stop {
return err
}
// Remember the last "real" error from f.
if err != nil && err != context.Canceled && err != context.DeadlineExceeded {
lastErr = err
}
p := bo.Pause()
if cerr := sleep(ctx, p); cerr != nil {
if lastErr != nil {
return fmt.Errorf("%v; last function err: %v", cerr, lastErr)
}
return cerr
}
}
}

View file

@ -1,106 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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 capnslog
import (
"bufio"
"fmt"
"io"
"runtime"
"strings"
"time"
)
type Formatter interface {
Format(pkg string, level LogLevel, depth int, entries ...interface{})
Flush()
}
func NewStringFormatter(w io.Writer) *StringFormatter {
return &StringFormatter{
w: bufio.NewWriter(w),
}
}
type StringFormatter struct {
w *bufio.Writer
}
func (s *StringFormatter) Format(pkg string, l LogLevel, i int, entries ...interface{}) {
now := time.Now().UTC()
s.w.WriteString(now.Format(time.RFC3339))
s.w.WriteByte(' ')
writeEntries(s.w, pkg, l, i, entries...)
s.Flush()
}
func writeEntries(w *bufio.Writer, pkg string, _ LogLevel, _ int, entries ...interface{}) {
if pkg != "" {
w.WriteString(pkg + ": ")
}
str := fmt.Sprint(entries...)
endsInNL := strings.HasSuffix(str, "\n")
w.WriteString(str)
if !endsInNL {
w.WriteString("\n")
}
}
func (s *StringFormatter) Flush() {
s.w.Flush()
}
func NewPrettyFormatter(w io.Writer, debug bool) Formatter {
return &PrettyFormatter{
w: bufio.NewWriter(w),
debug: debug,
}
}
type PrettyFormatter struct {
w *bufio.Writer
debug bool
}
func (c *PrettyFormatter) Format(pkg string, l LogLevel, depth int, entries ...interface{}) {
now := time.Now()
ts := now.Format("2006-01-02 15:04:05")
c.w.WriteString(ts)
ms := now.Nanosecond() / 1000
c.w.WriteString(fmt.Sprintf(".%06d", ms))
if c.debug {
_, file, line, ok := runtime.Caller(depth) // It's always the same number of frames to the user's call.
if !ok {
file = "???"
line = 1
} else {
slash := strings.LastIndex(file, "/")
if slash >= 0 {
file = file[slash+1:]
}
}
if line < 0 {
line = 0 // not a real line number
}
c.w.WriteString(fmt.Sprintf(" [%s:%d]", file, line))
}
c.w.WriteString(fmt.Sprint(" ", l.Char(), " | "))
writeEntries(c.w, pkg, l, depth, entries...)
c.Flush()
}
func (c *PrettyFormatter) Flush() {
c.w.Flush()
}

View file

@ -1,96 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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 capnslog
import (
"bufio"
"bytes"
"io"
"os"
"runtime"
"strconv"
"strings"
"time"
)
var pid = os.Getpid()
type GlogFormatter struct {
StringFormatter
}
func NewGlogFormatter(w io.Writer) *GlogFormatter {
g := &GlogFormatter{}
g.w = bufio.NewWriter(w)
return g
}
func (g GlogFormatter) Format(pkg string, level LogLevel, depth int, entries ...interface{}) {
g.w.Write(GlogHeader(level, depth+1))
g.StringFormatter.Format(pkg, level, depth+1, entries...)
}
func GlogHeader(level LogLevel, depth int) []byte {
// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
now := time.Now().UTC()
_, file, line, ok := runtime.Caller(depth) // It's always the same number of frames to the user's call.
if !ok {
file = "???"
line = 1
} else {
slash := strings.LastIndex(file, "/")
if slash >= 0 {
file = file[slash+1:]
}
}
if line < 0 {
line = 0 // not a real line number
}
buf := &bytes.Buffer{}
buf.Grow(30)
_, month, day := now.Date()
hour, minute, second := now.Clock()
buf.WriteString(level.Char())
twoDigits(buf, int(month))
twoDigits(buf, day)
buf.WriteByte(' ')
twoDigits(buf, hour)
buf.WriteByte(':')
twoDigits(buf, minute)
buf.WriteByte(':')
twoDigits(buf, second)
buf.WriteByte('.')
buf.WriteString(strconv.Itoa(now.Nanosecond() / 1000))
buf.WriteByte('Z')
buf.WriteByte(' ')
buf.WriteString(strconv.Itoa(pid))
buf.WriteByte(' ')
buf.WriteString(file)
buf.WriteByte(':')
buf.WriteString(strconv.Itoa(line))
buf.WriteByte(']')
buf.WriteByte(' ')
return buf.Bytes()
}
const digits = "0123456789"
func twoDigits(b *bytes.Buffer, d int) {
c2 := digits[d%10]
d /= 10
c1 := digits[d%10]
b.WriteByte(c1)
b.WriteByte(c2)
}

View file

@ -1,49 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
//
// +build !windows
package capnslog
import (
"io"
"os"
"syscall"
)
// Here's where the opinionation comes in. We need some sensible defaults,
// especially after taking over the log package. Your project (whatever it may
// be) may see things differently. That's okay; there should be no defaults in
// the main package that cannot be controlled or overridden programatically,
// otherwise it's a bug. Doing so is creating your own init_log.go file much
// like this one.
func init() {
initHijack()
// Go `log` pacakge uses os.Stderr.
SetFormatter(NewDefaultFormatter(os.Stderr))
SetGlobalLogLevel(INFO)
}
func NewDefaultFormatter(out io.Writer) Formatter {
if syscall.Getppid() == 1 {
// We're running under init, which may be systemd.
f, err := NewJournaldFormatter()
if err == nil {
return f
}
}
return NewPrettyFormatter(out, false)
}

View file

@ -1,25 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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 capnslog
import "os"
func init() {
initHijack()
// Go `log` package uses os.Stderr.
SetFormatter(NewPrettyFormatter(os.Stderr, false))
SetGlobalLogLevel(INFO)
}

View file

@ -1,68 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
//
// +build !windows
package capnslog
import (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/coreos/go-systemd/journal"
)
func NewJournaldFormatter() (Formatter, error) {
if !journal.Enabled() {
return nil, errors.New("No systemd detected")
}
return &journaldFormatter{}, nil
}
type journaldFormatter struct{}
func (j *journaldFormatter) Format(pkg string, l LogLevel, _ int, entries ...interface{}) {
var pri journal.Priority
switch l {
case CRITICAL:
pri = journal.PriCrit
case ERROR:
pri = journal.PriErr
case WARNING:
pri = journal.PriWarning
case NOTICE:
pri = journal.PriNotice
case INFO:
pri = journal.PriInfo
case DEBUG:
pri = journal.PriDebug
case TRACE:
pri = journal.PriDebug
default:
panic("Unhandled loglevel")
}
msg := fmt.Sprint(entries...)
tags := map[string]string{
"PACKAGE": pkg,
"SYSLOG_IDENTIFIER": filepath.Base(os.Args[0]),
}
err := journal.Send(msg, pri, tags)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
func (j *journaldFormatter) Flush() {}

View file

@ -1,39 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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 capnslog
import (
"log"
)
func initHijack() {
pkg := NewPackageLogger("log", "")
w := packageWriter{pkg}
log.SetFlags(0)
log.SetPrefix("")
log.SetOutput(w)
}
type packageWriter struct {
pl *PackageLogger
}
func (p packageWriter) Write(b []byte) (int, error) {
if p.pl.level < INFO {
return 0, nil
}
p.pl.internalLog(calldepth+2, INFO, string(b))
return len(b), nil
}

View file

@ -1,240 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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 capnslog
import (
"errors"
"strings"
"sync"
)
// LogLevel is the set of all log levels.
type LogLevel int8
const (
// CRITICAL is the lowest log level; only errors which will end the program will be propagated.
CRITICAL LogLevel = iota - 1
// ERROR is for errors that are not fatal but lead to troubling behavior.
ERROR
// WARNING is for errors which are not fatal and not errors, but are unusual. Often sourced from misconfigurations.
WARNING
// NOTICE is for normal but significant conditions.
NOTICE
// INFO is a log level for common, everyday log updates.
INFO
// DEBUG is the default hidden level for more verbose updates about internal processes.
DEBUG
// TRACE is for (potentially) call by call tracing of programs.
TRACE
)
// Char returns a single-character representation of the log level.
func (l LogLevel) Char() string {
switch l {
case CRITICAL:
return "C"
case ERROR:
return "E"
case WARNING:
return "W"
case NOTICE:
return "N"
case INFO:
return "I"
case DEBUG:
return "D"
case TRACE:
return "T"
default:
panic("Unhandled loglevel")
}
}
// String returns a multi-character representation of the log level.
func (l LogLevel) String() string {
switch l {
case CRITICAL:
return "CRITICAL"
case ERROR:
return "ERROR"
case WARNING:
return "WARNING"
case NOTICE:
return "NOTICE"
case INFO:
return "INFO"
case DEBUG:
return "DEBUG"
case TRACE:
return "TRACE"
default:
panic("Unhandled loglevel")
}
}
// Update using the given string value. Fulfills the flag.Value interface.
func (l *LogLevel) Set(s string) error {
value, err := ParseLevel(s)
if err != nil {
return err
}
*l = value
return nil
}
// ParseLevel translates some potential loglevel strings into their corresponding levels.
func ParseLevel(s string) (LogLevel, error) {
switch s {
case "CRITICAL", "C":
return CRITICAL, nil
case "ERROR", "0", "E":
return ERROR, nil
case "WARNING", "1", "W":
return WARNING, nil
case "NOTICE", "2", "N":
return NOTICE, nil
case "INFO", "3", "I":
return INFO, nil
case "DEBUG", "4", "D":
return DEBUG, nil
case "TRACE", "5", "T":
return TRACE, nil
}
return CRITICAL, errors.New("couldn't parse log level " + s)
}
type RepoLogger map[string]*PackageLogger
type loggerStruct struct {
sync.Mutex
repoMap map[string]RepoLogger
formatter Formatter
}
// logger is the global logger
var logger = new(loggerStruct)
// SetGlobalLogLevel sets the log level for all packages in all repositories
// registered with capnslog.
func SetGlobalLogLevel(l LogLevel) {
logger.Lock()
defer logger.Unlock()
for _, r := range logger.repoMap {
r.setRepoLogLevelInternal(l)
}
}
// GetRepoLogger may return the handle to the repository's set of packages' loggers.
func GetRepoLogger(repo string) (RepoLogger, error) {
logger.Lock()
defer logger.Unlock()
r, ok := logger.repoMap[repo]
if !ok {
return nil, errors.New("no packages registered for repo " + repo)
}
return r, nil
}
// MustRepoLogger returns the handle to the repository's packages' loggers.
func MustRepoLogger(repo string) RepoLogger {
r, err := GetRepoLogger(repo)
if err != nil {
panic(err)
}
return r
}
// SetRepoLogLevel sets the log level for all packages in the repository.
func (r RepoLogger) SetRepoLogLevel(l LogLevel) {
logger.Lock()
defer logger.Unlock()
r.setRepoLogLevelInternal(l)
}
func (r RepoLogger) setRepoLogLevelInternal(l LogLevel) {
for _, v := range r {
v.level = l
}
}
// ParseLogLevelConfig parses a comma-separated string of "package=loglevel", in
// order, and returns a map of the results, for use in SetLogLevel.
func (r RepoLogger) ParseLogLevelConfig(conf string) (map[string]LogLevel, error) {
setlist := strings.Split(conf, ",")
out := make(map[string]LogLevel)
for _, setstring := range setlist {
setting := strings.Split(setstring, "=")
if len(setting) != 2 {
return nil, errors.New("oddly structured `pkg=level` option: " + setstring)
}
l, err := ParseLevel(setting[1])
if err != nil {
return nil, err
}
out[setting[0]] = l
}
return out, nil
}
// SetLogLevel takes a map of package names within a repository to their desired
// loglevel, and sets the levels appropriately. Unknown packages are ignored.
// "*" is a special package name that corresponds to all packages, and will be
// processed first.
func (r RepoLogger) SetLogLevel(m map[string]LogLevel) {
logger.Lock()
defer logger.Unlock()
if l, ok := m["*"]; ok {
r.setRepoLogLevelInternal(l)
}
for k, v := range m {
l, ok := r[k]
if !ok {
continue
}
l.level = v
}
}
// SetFormatter sets the formatting function for all logs.
func SetFormatter(f Formatter) {
logger.Lock()
defer logger.Unlock()
logger.formatter = f
}
// NewPackageLogger creates a package logger object.
// This should be defined as a global var in your package, referencing your repo.
func NewPackageLogger(repo string, pkg string) (p *PackageLogger) {
logger.Lock()
defer logger.Unlock()
if logger.repoMap == nil {
logger.repoMap = make(map[string]RepoLogger)
}
r, rok := logger.repoMap[repo]
if !rok {
logger.repoMap[repo] = make(RepoLogger)
r = logger.repoMap[repo]
}
p, pok := r[pkg]
if !pok {
r[pkg] = &PackageLogger{
pkg: pkg,
level: INFO,
}
p = r[pkg]
}
return
}

View file

@ -1,158 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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 capnslog
import (
"fmt"
"os"
)
type PackageLogger struct {
pkg string
level LogLevel
}
const calldepth = 2
func (p *PackageLogger) internalLog(depth int, inLevel LogLevel, entries ...interface{}) {
if inLevel != CRITICAL && p.level < inLevel {
return
}
logger.Lock()
defer logger.Unlock()
if logger.formatter != nil {
logger.formatter.Format(p.pkg, inLevel, depth+1, entries...)
}
}
func (p *PackageLogger) LevelAt(l LogLevel) bool {
return p.level >= l
}
// Log a formatted string at any level between ERROR and TRACE
func (p *PackageLogger) Logf(l LogLevel, format string, args ...interface{}) {
p.internalLog(calldepth, l, fmt.Sprintf(format, args...))
}
// Log a message at any level between ERROR and TRACE
func (p *PackageLogger) Log(l LogLevel, args ...interface{}) {
p.internalLog(calldepth, l, fmt.Sprint(args...))
}
// log stdlib compatibility
func (p *PackageLogger) Println(args ...interface{}) {
p.internalLog(calldepth, INFO, fmt.Sprintln(args...))
}
func (p *PackageLogger) Printf(format string, args ...interface{}) {
p.internalLog(calldepth, INFO, fmt.Sprintf(format, args...))
}
func (p *PackageLogger) Print(args ...interface{}) {
p.internalLog(calldepth, INFO, fmt.Sprint(args...))
}
// Panic and fatal
func (p *PackageLogger) Panicf(format string, args ...interface{}) {
s := fmt.Sprintf(format, args...)
p.internalLog(calldepth, CRITICAL, s)
panic(s)
}
func (p *PackageLogger) Panic(args ...interface{}) {
s := fmt.Sprint(args...)
p.internalLog(calldepth, CRITICAL, s)
panic(s)
}
func (p *PackageLogger) Fatalf(format string, args ...interface{}) {
s := fmt.Sprintf(format, args...)
p.internalLog(calldepth, CRITICAL, s)
os.Exit(1)
}
func (p *PackageLogger) Fatal(args ...interface{}) {
s := fmt.Sprint(args...)
p.internalLog(calldepth, CRITICAL, s)
os.Exit(1)
}
// Error Functions
func (p *PackageLogger) Errorf(format string, args ...interface{}) {
p.internalLog(calldepth, ERROR, fmt.Sprintf(format, args...))
}
func (p *PackageLogger) Error(entries ...interface{}) {
p.internalLog(calldepth, ERROR, entries...)
}
// Warning Functions
func (p *PackageLogger) Warningf(format string, args ...interface{}) {
p.internalLog(calldepth, WARNING, fmt.Sprintf(format, args...))
}
func (p *PackageLogger) Warning(entries ...interface{}) {
p.internalLog(calldepth, WARNING, entries...)
}
// Notice Functions
func (p *PackageLogger) Noticef(format string, args ...interface{}) {
p.internalLog(calldepth, NOTICE, fmt.Sprintf(format, args...))
}
func (p *PackageLogger) Notice(entries ...interface{}) {
p.internalLog(calldepth, NOTICE, entries...)
}
// Info Functions
func (p *PackageLogger) Infof(format string, args ...interface{}) {
p.internalLog(calldepth, INFO, fmt.Sprintf(format, args...))
}
func (p *PackageLogger) Info(entries ...interface{}) {
p.internalLog(calldepth, INFO, entries...)
}
// Debug Functions
func (p *PackageLogger) Debugf(format string, args ...interface{}) {
p.internalLog(calldepth, DEBUG, fmt.Sprintf(format, args...))
}
func (p *PackageLogger) Debug(entries ...interface{}) {
p.internalLog(calldepth, DEBUG, entries...)
}
// Trace Functions
func (p *PackageLogger) Tracef(format string, args ...interface{}) {
p.internalLog(calldepth, TRACE, fmt.Sprintf(format, args...))
}
func (p *PackageLogger) Trace(entries ...interface{}) {
p.internalLog(calldepth, TRACE, entries...)
}
func (p *PackageLogger) Flush() {
logger.Lock()
defer logger.Unlock()
logger.formatter.Flush()
}

View file

@ -1,65 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
//
// +build !windows
package capnslog
import (
"fmt"
"log/syslog"
)
func NewSyslogFormatter(w *syslog.Writer) Formatter {
return &syslogFormatter{w}
}
func NewDefaultSyslogFormatter(tag string) (Formatter, error) {
w, err := syslog.New(syslog.LOG_DEBUG, tag)
if err != nil {
return nil, err
}
return NewSyslogFormatter(w), nil
}
type syslogFormatter struct {
w *syslog.Writer
}
func (s *syslogFormatter) Format(pkg string, l LogLevel, _ int, entries ...interface{}) {
for _, entry := range entries {
str := fmt.Sprint(entry)
switch l {
case CRITICAL:
s.w.Crit(str)
case ERROR:
s.w.Err(str)
case WARNING:
s.w.Warning(str)
case NOTICE:
s.w.Notice(str)
case INFO:
s.w.Info(str)
case DEBUG:
s.w.Debug(str)
case TRACE:
s.w.Debug(str)
default:
panic("Unhandled loglevel")
}
}
}
func (s *syslogFormatter) Flush() {
}

27
vendor/github.com/googleapis/gax-go/LICENSE generated vendored Normal file
View file

@ -0,0 +1,27 @@
Copyright 2016, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

149
vendor/github.com/googleapis/gax-go/call_option.go generated vendored Normal file
View file

@ -0,0 +1,149 @@
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package gax
import (
"math/rand"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
)
// CallOption is an option used by Invoke to control behaviors of RPC calls.
// CallOption works by modifying relevant fields of CallSettings.
type CallOption interface {
// Resolve applies the option by modifying cs.
Resolve(cs *CallSettings)
}
// Retryer is used by Invoke to determine retry behavior.
type Retryer interface {
// Retry reports whether a request should be retriedand how long to pause before retrying
// if the previous attempt returned with err. Invoke never calls Retry with nil error.
Retry(err error) (pause time.Duration, shouldRetry bool)
}
type retryerOption func() Retryer
func (o retryerOption) Resolve(s *CallSettings) {
s.Retry = o
}
// WithRetry sets CallSettings.Retry to fn.
func WithRetry(fn func() Retryer) CallOption {
return retryerOption(fn)
}
// OnCodes returns a Retryer that retries if and only if
// the previous attempt returns a GRPC error whose error code is stored in cc.
// Pause times between retries are specified by bo.
//
// bo is only used for its parameters; each Retryer has its own copy.
func OnCodes(cc []codes.Code, bo Backoff) Retryer {
return &boRetryer{
backoff: bo,
codes: append([]codes.Code(nil), cc...),
}
}
type boRetryer struct {
backoff Backoff
codes []codes.Code
}
func (r *boRetryer) Retry(err error) (time.Duration, bool) {
c := grpc.Code(err)
for _, rc := range r.codes {
if c == rc {
return r.backoff.Pause(), true
}
}
return 0, false
}
// Backoff implements exponential backoff.
// The wait time between retries is a random value between 0 and the "retry envelope".
// The envelope starts at Initial and increases by the factor of Multiplier every retry,
// but is capped at Max.
type Backoff struct {
// Initial is the initial value of the retry envelope, defaults to 1 second.
Initial time.Duration
// Max is the maximum value of the retry envelope, defaults to 30 seconds.
Max time.Duration
// Multiplier is the factor by which the retry envelope increases.
// It should be greater than 1 and defaults to 2.
Multiplier float64
// cur is the current retry envelope
cur time.Duration
}
func (bo *Backoff) Pause() time.Duration {
if bo.Initial == 0 {
bo.Initial = time.Second
}
if bo.cur == 0 {
bo.cur = bo.Initial
}
if bo.Max == 0 {
bo.Max = 30 * time.Second
}
if bo.Multiplier < 1 {
bo.Multiplier = 2
}
d := time.Duration(rand.Int63n(int64(bo.cur)))
bo.cur = time.Duration(float64(bo.cur) * bo.Multiplier)
if bo.cur > bo.Max {
bo.cur = bo.Max
}
return d
}
type grpcOpt []grpc.CallOption
func (o grpcOpt) Resolve(s *CallSettings) {
s.GRPC = o
}
func WithGRPCOptions(opt ...grpc.CallOption) CallOption {
return grpcOpt(append([]grpc.CallOption(nil), opt...))
}
type CallSettings struct {
// Retry returns a Retryer to be used to control retry logic of a method call.
// If Retry is nil or the returned Retryer is nil, the call will not be retried.
Retry func() Retryer
// CallOptions to be forwarded to GRPC.
GRPC []grpc.CallOption
}

40
vendor/github.com/googleapis/gax-go/gax.go generated vendored Normal file
View file

@ -0,0 +1,40 @@
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Package gax contains a set of modules which aid the development of APIs
// for clients and servers based on gRPC and Google API conventions.
//
// Application code will rarely need to use this library directly.
// However, code generated automatically from API definition files can use it
// to simplify code generation and to provide more convenient and idiomatic API surfaces.
//
// This project is currently experimental and not supported.
package gax
const Version = "0.1.0"

24
vendor/github.com/googleapis/gax-go/header.go generated vendored Normal file
View file

@ -0,0 +1,24 @@
package gax
import "bytes"
// XGoogHeader is for use by the Google Cloud Libraries only.
//
// XGoogHeader formats key-value pairs.
// The resulting string is suitable for x-goog-api-client header.
func XGoogHeader(keyval ...string) string {
if len(keyval) == 0 {
return ""
}
if len(keyval)%2 != 0 {
panic("gax.Header: odd argument count")
}
var buf bytes.Buffer
for i := 0; i < len(keyval); i += 2 {
buf.WriteByte(' ')
buf.WriteString(keyval[i])
buf.WriteByte('/')
buf.WriteString(keyval[i+1])
}
return buf.String()[1:]
}

90
vendor/github.com/googleapis/gax-go/invoke.go generated vendored Normal file
View file

@ -0,0 +1,90 @@
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package gax
import (
"time"
"golang.org/x/net/context"
)
// A user defined call stub.
type APICall func(context.Context, CallSettings) error
// Invoke calls the given APICall,
// performing retries as specified by opts, if any.
func Invoke(ctx context.Context, call APICall, opts ...CallOption) error {
var settings CallSettings
for _, opt := range opts {
opt.Resolve(&settings)
}
return invoke(ctx, call, settings, Sleep)
}
// Sleep is similar to time.Sleep, but it can be interrupted by ctx.Done() closing.
// If interrupted, Sleep returns ctx.Err().
func Sleep(ctx context.Context, d time.Duration) error {
t := time.NewTimer(d)
select {
case <-ctx.Done():
t.Stop()
return ctx.Err()
case <-t.C:
return nil
}
}
type sleeper func(ctx context.Context, d time.Duration) error
// invoke implements Invoke, taking an additional sleeper argument for testing.
func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper) error {
var retryer Retryer
for {
err := call(ctx, settings)
if err == nil {
return nil
}
if settings.Retry == nil {
return err
}
if retryer == nil {
if r := settings.Retry(); r != nil {
retryer = r
} else {
return err
}
}
if d, ok := retryer.Retry(err); !ok {
return err
} else if err = sp(ctx, d); err != nil {
return err
}
}
}

176
vendor/github.com/googleapis/gax-go/path_template.go generated vendored Normal file
View file

@ -0,0 +1,176 @@
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package gax
import (
"errors"
"fmt"
"strings"
)
type matcher interface {
match([]string) (int, error)
String() string
}
type segment struct {
matcher
name string
}
type labelMatcher string
func (ls labelMatcher) match(segments []string) (int, error) {
if len(segments) == 0 {
return 0, fmt.Errorf("expected %s but no more segments found", ls)
}
if segments[0] != string(ls) {
return 0, fmt.Errorf("expected %s but got %s", ls, segments[0])
}
return 1, nil
}
func (ls labelMatcher) String() string {
return string(ls)
}
type wildcardMatcher int
func (wm wildcardMatcher) match(segments []string) (int, error) {
if len(segments) == 0 {
return 0, errors.New("no more segments found")
}
return 1, nil
}
func (wm wildcardMatcher) String() string {
return "*"
}
type pathWildcardMatcher int
func (pwm pathWildcardMatcher) match(segments []string) (int, error) {
length := len(segments) - int(pwm)
if length <= 0 {
return 0, errors.New("not sufficient segments are supplied for path wildcard")
}
return length, nil
}
func (pwm pathWildcardMatcher) String() string {
return "**"
}
type ParseError struct {
Pos int
Template string
Message string
}
func (pe ParseError) Error() string {
return fmt.Sprintf("at %d of template '%s', %s", pe.Pos, pe.Template, pe.Message)
}
// PathTemplate manages the template to build and match with paths used
// by API services. It holds a template and variable names in it, and
// it can extract matched patterns from a path string or build a path
// string from a binding.
//
// See http.proto in github.com/googleapis/googleapis/ for the details of
// the template syntax.
type PathTemplate struct {
segments []segment
}
// NewPathTemplate parses a path template, and returns a PathTemplate
// instance if successful.
func NewPathTemplate(template string) (*PathTemplate, error) {
return parsePathTemplate(template)
}
// MustCompilePathTemplate is like NewPathTemplate but panics if the
// expression cannot be parsed. It simplifies safe initialization of
// global variables holding compiled regular expressions.
func MustCompilePathTemplate(template string) *PathTemplate {
pt, err := NewPathTemplate(template)
if err != nil {
panic(err)
}
return pt
}
// Match attempts to match the given path with the template, and returns
// the mapping of the variable name to the matched pattern string.
func (pt *PathTemplate) Match(path string) (map[string]string, error) {
paths := strings.Split(path, "/")
values := map[string]string{}
for _, segment := range pt.segments {
length, err := segment.match(paths)
if err != nil {
return nil, err
}
if segment.name != "" {
value := strings.Join(paths[:length], "/")
if oldValue, ok := values[segment.name]; ok {
values[segment.name] = oldValue + "/" + value
} else {
values[segment.name] = value
}
}
paths = paths[length:]
}
if len(paths) != 0 {
return nil, fmt.Errorf("Trailing path %s remains after the matching", strings.Join(paths, "/"))
}
return values, nil
}
// Render creates a path string from its template and the binding from
// the variable name to the value.
func (pt *PathTemplate) Render(binding map[string]string) (string, error) {
result := make([]string, 0, len(pt.segments))
var lastVariableName string
for _, segment := range pt.segments {
name := segment.name
if lastVariableName != "" && name == lastVariableName {
continue
}
lastVariableName = name
if name == "" {
result = append(result, segment.String())
} else if value, ok := binding[name]; ok {
result = append(result, value)
} else {
return "", fmt.Errorf("%s is not found", name)
}
}
built := strings.Join(result, "/")
return built, nil
}

View file

@ -0,0 +1,227 @@
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package gax
import (
"fmt"
"io"
"strings"
)
// This parser follows the syntax of path templates, from
// https://github.com/googleapis/googleapis/blob/master/google/api/http.proto.
// The differences are that there is no custom verb, we allow the initial slash
// to be absent, and that we are not strict as
// https://tools.ietf.org/html/rfc6570 about the characters in identifiers and
// literals.
type pathTemplateParser struct {
r *strings.Reader
runeCount int // the number of the current rune in the original string
nextVar int // the number to use for the next unnamed variable
seenName map[string]bool // names we've seen already
seenPathWildcard bool // have we seen "**" already?
}
func parsePathTemplate(template string) (pt *PathTemplate, err error) {
p := &pathTemplateParser{
r: strings.NewReader(template),
seenName: map[string]bool{},
}
// Handle panics with strings like errors.
// See pathTemplateParser.error, below.
defer func() {
if x := recover(); x != nil {
errmsg, ok := x.(errString)
if !ok {
panic(x)
}
pt = nil
err = ParseError{p.runeCount, template, string(errmsg)}
}
}()
segs := p.template()
// If there is a path wildcard, set its length. We can't do this
// until we know how many segments we've got all together.
for i, seg := range segs {
if _, ok := seg.matcher.(pathWildcardMatcher); ok {
segs[i].matcher = pathWildcardMatcher(len(segs) - i - 1)
break
}
}
return &PathTemplate{segments: segs}, nil
}
// Used to indicate errors "thrown" by this parser. We don't use string because
// many parts of the standard library panic with strings.
type errString string
// Terminates parsing immediately with an error.
func (p *pathTemplateParser) error(msg string) {
panic(errString(msg))
}
// Template = [ "/" ] Segments
func (p *pathTemplateParser) template() []segment {
var segs []segment
if p.consume('/') {
// Initial '/' needs an initial empty matcher.
segs = append(segs, segment{matcher: labelMatcher("")})
}
return append(segs, p.segments("")...)
}
// Segments = Segment { "/" Segment }
func (p *pathTemplateParser) segments(name string) []segment {
var segs []segment
for {
subsegs := p.segment(name)
segs = append(segs, subsegs...)
if !p.consume('/') {
break
}
}
return segs
}
// Segment = "*" | "**" | LITERAL | Variable
func (p *pathTemplateParser) segment(name string) []segment {
if p.consume('*') {
if name == "" {
name = fmt.Sprintf("$%d", p.nextVar)
p.nextVar++
}
if p.consume('*') {
if p.seenPathWildcard {
p.error("multiple '**' disallowed")
}
p.seenPathWildcard = true
// We'll change 0 to the right number at the end.
return []segment{{name: name, matcher: pathWildcardMatcher(0)}}
}
return []segment{{name: name, matcher: wildcardMatcher(0)}}
}
if p.consume('{') {
if name != "" {
p.error("recursive named bindings are not allowed")
}
return p.variable()
}
return []segment{{name: name, matcher: labelMatcher(p.literal())}}
}
// Variable = "{" FieldPath [ "=" Segments ] "}"
// "{" is already consumed.
func (p *pathTemplateParser) variable() []segment {
// Simplification: treat FieldPath as LITERAL, instead of IDENT { '.' IDENT }
name := p.literal()
if p.seenName[name] {
p.error(name + " appears multiple times")
}
p.seenName[name] = true
var segs []segment
if p.consume('=') {
segs = p.segments(name)
} else {
// "{var}" is equivalent to "{var=*}"
segs = []segment{{name: name, matcher: wildcardMatcher(0)}}
}
if !p.consume('}') {
p.error("expected '}'")
}
return segs
}
// A literal is any sequence of characters other than a few special ones.
// The list of stop characters is not quite the same as in the template RFC.
func (p *pathTemplateParser) literal() string {
lit := p.consumeUntil("/*}{=")
if lit == "" {
p.error("empty literal")
}
return lit
}
// Read runes until EOF or one of the runes in stopRunes is encountered.
// If the latter, unread the stop rune. Return the accumulated runes as a string.
func (p *pathTemplateParser) consumeUntil(stopRunes string) string {
var runes []rune
for {
r, ok := p.readRune()
if !ok {
break
}
if strings.IndexRune(stopRunes, r) >= 0 {
p.unreadRune()
break
}
runes = append(runes, r)
}
return string(runes)
}
// If the next rune is r, consume it and return true.
// Otherwise, leave the input unchanged and return false.
func (p *pathTemplateParser) consume(r rune) bool {
rr, ok := p.readRune()
if !ok {
return false
}
if r == rr {
return true
}
p.unreadRune()
return false
}
// Read the next rune from the input. Return it.
// The second return value is false at EOF.
func (p *pathTemplateParser) readRune() (rune, bool) {
r, _, err := p.r.ReadRune()
if err == io.EOF {
return r, false
}
if err != nil {
p.error(err.Error())
}
p.runeCount++
return r, true
}
// Put the last rune that was read back on the input.
func (p *pathTemplateParser) unreadRune() {
if err := p.r.UnreadRune(); err != nil {
p.error(err.Error())
}
p.runeCount--
}

View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// optional interface to indicate boolean flags that can be // optional interface to indicate boolean flags that can be
// supplied without "=value" text // supplied without "=value" text
@ -30,41 +27,54 @@ func (b *boolValue) Type() string {
return "bool" return "bool"
} }
func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) } func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) }
func (b *boolValue) IsBoolFlag() bool { return true } func (b *boolValue) IsBoolFlag() bool { return true }
func boolConv(sval string) (interface{}, error) {
return strconv.ParseBool(sval)
}
// GetBool return the bool value of a flag with the given name
func (f *FlagSet) GetBool(name string) (bool, error) {
val, err := f.getFlagType(name, "bool", boolConv)
if err != nil {
return false, err
}
return val.(bool), nil
}
// BoolVar defines a bool flag with specified name, default value, and usage string. // BoolVar defines a bool flag with specified name, default value, and usage string.
// The argument p points to a bool variable in which to store the value of the flag. // The argument p points to a bool variable in which to store the value of the flag.
func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) { func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
f.VarP(newBoolValue(value, p), name, "", usage) f.BoolVarP(p, name, "", value, usage)
} }
// Like BoolVar, but accepts a shorthand letter that can be used after a single dash. // BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) { func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) {
f.VarP(newBoolValue(value, p), name, shorthand, usage) flag := f.VarPF(newBoolValue(value, p), name, shorthand, usage)
flag.NoOptDefVal = "true"
} }
// BoolVar defines a bool flag with specified name, default value, and usage string. // BoolVar defines a bool flag with specified name, default value, and usage string.
// The argument p points to a bool variable in which to store the value of the flag. // The argument p points to a bool variable in which to store the value of the flag.
func BoolVar(p *bool, name string, value bool, usage string) { func BoolVar(p *bool, name string, value bool, usage string) {
CommandLine.VarP(newBoolValue(value, p), name, "", usage) BoolVarP(p, name, "", value, usage)
} }
// Like BoolVar, but accepts a shorthand letter that can be used after a single dash. // BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash.
func BoolVarP(p *bool, name, shorthand string, value bool, usage string) { func BoolVarP(p *bool, name, shorthand string, value bool, usage string) {
CommandLine.VarP(newBoolValue(value, p), name, shorthand, usage) flag := CommandLine.VarPF(newBoolValue(value, p), name, shorthand, usage)
flag.NoOptDefVal = "true"
} }
// Bool defines a bool flag with specified name, default value, and usage string. // Bool defines a bool flag with specified name, default value, and usage string.
// The return value is the address of a bool variable that stores the value of the flag. // The return value is the address of a bool variable that stores the value of the flag.
func (f *FlagSet) Bool(name string, value bool, usage string) *bool { func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
p := new(bool) return f.BoolP(name, "", value, usage)
f.BoolVarP(p, name, "", value, usage)
return p
} }
// Like Bool, but accepts a shorthand letter that can be used after a single dash. // BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool { func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool {
p := new(bool) p := new(bool)
f.BoolVarP(p, name, shorthand, value, usage) f.BoolVarP(p, name, shorthand, value, usage)
@ -74,10 +84,11 @@ func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool
// Bool defines a bool flag with specified name, default value, and usage string. // Bool defines a bool flag with specified name, default value, and usage string.
// The return value is the address of a bool variable that stores the value of the flag. // The return value is the address of a bool variable that stores the value of the flag.
func Bool(name string, value bool, usage string) *bool { func Bool(name string, value bool, usage string) *bool {
return CommandLine.BoolP(name, "", value, usage) return BoolP(name, "", value, usage)
} }
// Like Bool, but accepts a shorthand letter that can be used after a single dash. // BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash.
func BoolP(name, shorthand string, value bool, usage string) *bool { func BoolP(name, shorthand string, value bool, usage string) *bool {
return CommandLine.BoolP(name, shorthand, value, usage) b := CommandLine.BoolP(name, shorthand, value, usage)
return b
} }

94
vendor/github.com/spf13/pflag/count.go generated vendored Normal file
View file

@ -0,0 +1,94 @@
package pflag
import "strconv"
// -- count Value
type countValue int
func newCountValue(val int, p *int) *countValue {
*p = val
return (*countValue)(p)
}
func (i *countValue) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 64)
// -1 means that no specific value was passed, so increment
if v == -1 {
*i = countValue(*i + 1)
} else {
*i = countValue(v)
}
return err
}
func (i *countValue) Type() string {
return "count"
}
func (i *countValue) String() string { return strconv.Itoa(int(*i)) }
func countConv(sval string) (interface{}, error) {
i, err := strconv.Atoi(sval)
if err != nil {
return nil, err
}
return i, nil
}
// GetCount return the int value of a flag with the given name
func (f *FlagSet) GetCount(name string) (int, error) {
val, err := f.getFlagType(name, "count", countConv)
if err != nil {
return 0, err
}
return val.(int), nil
}
// CountVar defines a count flag with specified name, default value, and usage string.
// The argument p points to an int variable in which to store the value of the flag.
// A count flag will add 1 to its value evey time it is found on the command line
func (f *FlagSet) CountVar(p *int, name string, usage string) {
f.CountVarP(p, name, "", usage)
}
// CountVarP is like CountVar only take a shorthand for the flag name.
func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) {
flag := f.VarPF(newCountValue(0, p), name, shorthand, usage)
flag.NoOptDefVal = "-1"
}
// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set
func CountVar(p *int, name string, usage string) {
CommandLine.CountVar(p, name, usage)
}
// CountVarP is like CountVar only take a shorthand for the flag name.
func CountVarP(p *int, name, shorthand string, usage string) {
CommandLine.CountVarP(p, name, shorthand, usage)
}
// Count defines a count flag with specified name, default value, and usage string.
// The return value is the address of an int variable that stores the value of the flag.
// A count flag will add 1 to its value evey time it is found on the command line
func (f *FlagSet) Count(name string, usage string) *int {
p := new(int)
f.CountVarP(p, name, "", usage)
return p
}
// CountP is like Count only takes a shorthand for the flag name.
func (f *FlagSet) CountP(name, shorthand string, usage string) *int {
p := new(int)
f.CountVarP(p, name, shorthand, usage)
return p
}
// Count like Count only the flag is placed on the CommandLine isntead of a given flag set
func Count(name string, usage string) *int {
return CommandLine.CountP(name, "", usage)
}
// CountP is like Count only takes a shorthand for the flag name.
func CountP(name, shorthand string, usage string) *int {
return CommandLine.CountP(name, shorthand, usage)
}

View file

@ -1,6 +1,8 @@
package pflag package pflag
import "time" import (
"time"
)
// -- time.Duration Value // -- time.Duration Value
type durationValue time.Duration type durationValue time.Duration
@ -22,13 +24,26 @@ func (d *durationValue) Type() string {
func (d *durationValue) String() string { return (*time.Duration)(d).String() } func (d *durationValue) String() string { return (*time.Duration)(d).String() }
func durationConv(sval string) (interface{}, error) {
return time.ParseDuration(sval)
}
// GetDuration return the duration value of a flag with the given name
func (f *FlagSet) GetDuration(name string) (time.Duration, error) {
val, err := f.getFlagType(name, "duration", durationConv)
if err != nil {
return 0, err
}
return val.(time.Duration), nil
}
// DurationVar defines a time.Duration flag with specified name, default value, and usage string. // DurationVar defines a time.Duration flag with specified name, default value, and usage string.
// The argument p points to a time.Duration variable in which to store the value of the flag. // The argument p points to a time.Duration variable in which to store the value of the flag.
func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) { func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
f.VarP(newDurationValue(value, p), name, "", usage) f.VarP(newDurationValue(value, p), name, "", usage)
} }
// Like DurationVar, but accepts a shorthand letter that can be used after a single dash. // DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { func (f *FlagSet) DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) {
f.VarP(newDurationValue(value, p), name, shorthand, usage) f.VarP(newDurationValue(value, p), name, shorthand, usage)
} }
@ -39,7 +54,7 @@ func DurationVar(p *time.Duration, name string, value time.Duration, usage strin
CommandLine.VarP(newDurationValue(value, p), name, "", usage) CommandLine.VarP(newDurationValue(value, p), name, "", usage)
} }
// Like DurationVar, but accepts a shorthand letter that can be used after a single dash. // DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash.
func DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { func DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) {
CommandLine.VarP(newDurationValue(value, p), name, shorthand, usage) CommandLine.VarP(newDurationValue(value, p), name, shorthand, usage)
} }
@ -52,7 +67,7 @@ func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time
return p return p
} }
// Like Duration, but accepts a shorthand letter that can be used after a single dash. // DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { func (f *FlagSet) DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration {
p := new(time.Duration) p := new(time.Duration)
f.DurationVarP(p, name, shorthand, value, usage) f.DurationVarP(p, name, shorthand, value, usage)
@ -65,7 +80,7 @@ func Duration(name string, value time.Duration, usage string) *time.Duration {
return CommandLine.DurationP(name, "", value, usage) return CommandLine.DurationP(name, "", value, usage)
} }
// Like Duration, but accepts a shorthand letter that can be used after a single dash. // DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash.
func DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { func DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration {
return CommandLine.DurationP(name, shorthand, value, usage) return CommandLine.DurationP(name, shorthand, value, usage)
} }

498
vendor/github.com/spf13/pflag/flag.go generated vendored
View file

@ -3,98 +3,98 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
/* /*
pflag is a drop-in replacement for Go's flag package, implementing Package pflag is a drop-in replacement for Go's flag package, implementing
POSIX/GNU-style --flags. POSIX/GNU-style --flags.
pflag is compatible with the GNU extensions to the POSIX recommendations pflag is compatible with the GNU extensions to the POSIX recommendations
for command-line options. See for command-line options. See
http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
Usage: Usage:
pflag is a drop-in replacement of Go's native flag package. If you import pflag is a drop-in replacement of Go's native flag package. If you import
pflag under the name "flag" then all code should continue to function pflag under the name "flag" then all code should continue to function
with no changes. with no changes.
import flag "github.com/ogier/pflag" import flag "github.com/ogier/pflag"
There is one exception to this: if you directly instantiate the Flag struct There is one exception to this: if you directly instantiate the Flag struct
there is one more field "Shorthand" that you will need to set. there is one more field "Shorthand" that you will need to set.
Most code never instantiates this struct directly, and instead uses Most code never instantiates this struct directly, and instead uses
functions such as String(), BoolVar(), and Var(), and is therefore functions such as String(), BoolVar(), and Var(), and is therefore
unaffected. unaffected.
Define flags using flag.String(), Bool(), Int(), etc. Define flags using flag.String(), Bool(), Int(), etc.
This declares an integer flag, -flagname, stored in the pointer ip, with type *int. This declares an integer flag, -flagname, stored in the pointer ip, with type *int.
var ip = flag.Int("flagname", 1234, "help message for flagname") var ip = flag.Int("flagname", 1234, "help message for flagname")
If you like, you can bind the flag to a variable using the Var() functions. If you like, you can bind the flag to a variable using the Var() functions.
var flagvar int var flagvar int
func init() { func init() {
flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
} }
Or you can create custom flags that satisfy the Value interface (with Or you can create custom flags that satisfy the Value interface (with
pointer receivers) and couple them to flag parsing by pointer receivers) and couple them to flag parsing by
flag.Var(&flagVal, "name", "help message for flagname") flag.Var(&flagVal, "name", "help message for flagname")
For such flags, the default value is just the initial value of the variable. For such flags, the default value is just the initial value of the variable.
After all flags are defined, call After all flags are defined, call
flag.Parse() flag.Parse()
to parse the command line into the defined flags. to parse the command line into the defined flags.
Flags may then be used directly. If you're using the flags themselves, Flags may then be used directly. If you're using the flags themselves,
they are all pointers; if you bind to variables, they're values. they are all pointers; if you bind to variables, they're values.
fmt.Println("ip has value ", *ip) fmt.Println("ip has value ", *ip)
fmt.Println("flagvar has value ", flagvar) fmt.Println("flagvar has value ", flagvar)
After parsing, the arguments after the flag are available as the After parsing, the arguments after the flag are available as the
slice flag.Args() or individually as flag.Arg(i). slice flag.Args() or individually as flag.Arg(i).
The arguments are indexed from 0 through flag.NArg()-1. The arguments are indexed from 0 through flag.NArg()-1.
The pflag package also defines some new functions that are not in flag, The pflag package also defines some new functions that are not in flag,
that give one-letter shorthands for flags. You can use these by appending that give one-letter shorthands for flags. You can use these by appending
'P' to the name of any function that defines a flag. 'P' to the name of any function that defines a flag.
var ip = flag.IntP("flagname", "f", 1234, "help message") var ip = flag.IntP("flagname", "f", 1234, "help message")
var flagvar bool var flagvar bool
func init() { func init() {
flag.BoolVarP("boolname", "b", true, "help message") flag.BoolVarP("boolname", "b", true, "help message")
} }
flag.VarP(&flagVar, "varname", "v", 1234, "help message") flag.VarP(&flagVar, "varname", "v", 1234, "help message")
Shorthand letters can be used with single dashes on the command line. Shorthand letters can be used with single dashes on the command line.
Boolean shorthand flags can be combined with other shorthand flags. Boolean shorthand flags can be combined with other shorthand flags.
Command line flag syntax: Command line flag syntax:
--flag // boolean flags only --flag // boolean flags only
--flag=x --flag=x
Unlike the flag package, a single dash before an option means something Unlike the flag package, a single dash before an option means something
different than a double dash. Single dashes signify a series of shorthand different than a double dash. Single dashes signify a series of shorthand
letters for flags. All but the last shorthand letter must be boolean flags. letters for flags. All but the last shorthand letter must be boolean flags.
// boolean flags // boolean flags
-f -f
-abc -abc
// non-boolean flags // non-boolean flags
-n 1234 -n 1234
-Ifile -Ifile
// mixed // mixed
-abcs "hello" -abcs "hello"
-abcn1234 -abcn1234
Flag parsing stops after the terminator "--". Unlike the flag package, Flag parsing stops after the terminator "--". Unlike the flag package,
flags can be interspersed with arguments anywhere on the command line flags can be interspersed with arguments anywhere on the command line
before this terminator. before this terminator.
Integer flags accept 1234, 0664, 0x1234 and may be negative. Integer flags accept 1234, 0664, 0x1234 and may be negative.
Boolean flags (in their long form) accept 1, 0, t, f, true, false, Boolean flags (in their long form) accept 1, 0, t, f, true, false,
TRUE, FALSE, True, False. TRUE, FALSE, True, False.
Duration flags accept any input valid for time.ParseDuration. Duration flags accept any input valid for time.ParseDuration.
The default set of command-line flags is controlled by The default set of command-line flags is controlled by
top-level functions. The FlagSet type allows one to define top-level functions. The FlagSet type allows one to define
independent sets of flags, such as to implement subcommands independent sets of flags, such as to implement subcommands
in a command-line interface. The methods of FlagSet are in a command-line interface. The methods of FlagSet are
analogous to the top-level functions for the command-line analogous to the top-level functions for the command-line
flag set. flag set.
*/ */
package pflag package pflag
@ -115,8 +115,11 @@ var ErrHelp = errors.New("pflag: help requested")
type ErrorHandling int type ErrorHandling int
const ( const (
// ContinueOnError will return an err from Parse() if an error is found
ContinueOnError ErrorHandling = iota ContinueOnError ErrorHandling = iota
// ExitOnError will call os.Exit(2) if an error is found when parsing
ExitOnError ExitOnError
// PanicOnError will panic() if an error is found when parsing flags
PanicOnError PanicOnError
) )
@ -137,6 +140,7 @@ type FlagSet struct {
formal map[NormalizedName]*Flag formal map[NormalizedName]*Flag
shorthands map[byte]*Flag shorthands map[byte]*Flag
args []string // arguments after flags args []string // arguments after flags
argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no --
exitOnError bool // does the program exit if there's an error? exitOnError bool // does the program exit if there's an error?
errorHandling ErrorHandling errorHandling ErrorHandling
output io.Writer // nil means stderr; use out() accessor output io.Writer // nil means stderr; use out() accessor
@ -146,14 +150,17 @@ type FlagSet struct {
// A Flag represents the state of a flag. // A Flag represents the state of a flag.
type Flag struct { type Flag struct {
Name string // name as it appears on command line Name string // name as it appears on command line
Shorthand string // one-letter abbreviated flag Shorthand string // one-letter abbreviated flag
Usage string // help message Usage string // help message
Value Value // value as set Value Value // value as set
DefValue string // default value (as text); for usage message DefValue string // default value (as text); for usage message
Changed bool // If the user set the value (or if left to default) Changed bool // If the user set the value (or if left to default)
Deprecated string // If this flag is deprecated, this string is the new or now thing to use NoOptDefVal string //default value (as text); if the flag is on the command line without any options
Annotations map[string][]string // used by cobra.Command bash autocomple code Deprecated string // If this flag is deprecated, this string is the new or now thing to use
Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text
ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use
Annotations map[string][]string // used by cobra.Command bash autocomple code
} }
// Value is the interface to the dynamic value stored in a flag. // Value is the interface to the dynamic value stored in a flag.
@ -180,6 +187,11 @@ func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
return result return result
} }
// SetNormalizeFunc allows you to add a function which can translate flag names.
// Flags added to the FlagSet will be translated and then when anything tries to
// look up the flag that will also be translated. So it would be possible to create
// a flag named "getURL" and have it translated to "geturl". A user could then pass
// "--getUrl" which may also be translated to "geturl" and everything will work.
func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
f.normalizeNameFunc = n f.normalizeNameFunc = n
for k, v := range f.formal { for k, v := range f.formal {
@ -190,6 +202,8 @@ func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedNam
} }
} }
// GetNormalizeFunc returns the previously set NormalizeFunc of a function which
// does no translation, if not set previously.
func (f *FlagSet) GetNormalizeFunc() func(f *FlagSet, name string) NormalizedName { func (f *FlagSet) GetNormalizeFunc() func(f *FlagSet, name string) NormalizedName {
if f.normalizeNameFunc != nil { if f.normalizeNameFunc != nil {
return f.normalizeNameFunc return f.normalizeNameFunc
@ -223,10 +237,22 @@ func (f *FlagSet) VisitAll(fn func(*Flag)) {
} }
} }
// HasFlags returns a bool to indicate if the FlagSet has any flags definied.
func (f *FlagSet) HasFlags() bool { func (f *FlagSet) HasFlags() bool {
return len(f.formal) > 0 return len(f.formal) > 0
} }
// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags
// definied that are not hidden or deprecated.
func (f *FlagSet) HasAvailableFlags() bool {
for _, flag := range f.formal {
if !flag.Hidden && len(flag.Deprecated) == 0 {
return true
}
}
return false
}
// VisitAll visits the command-line flags in lexicographical order, calling // VisitAll visits the command-line flags in lexicographical order, calling
// fn for each. It visits all flags, even those not set. // fn for each. It visits all flags, even those not set.
func VisitAll(fn func(*Flag)) { func VisitAll(fn func(*Flag)) {
@ -257,16 +283,75 @@ func (f *FlagSet) lookup(name NormalizedName) *Flag {
return f.formal[name] return f.formal[name]
} }
// Mark a flag deprecated in your program // func to return a given type for a given flag name
func (f *FlagSet) getFlagType(name string, ftype string, convFunc func(sval string) (interface{}, error)) (interface{}, error) {
flag := f.Lookup(name)
if flag == nil {
err := fmt.Errorf("flag accessed but not defined: %s", name)
return nil, err
}
if flag.Value.Type() != ftype {
err := fmt.Errorf("trying to get %s value of flag of type %s", ftype, flag.Value.Type())
return nil, err
}
sval := flag.Value.String()
result, err := convFunc(sval)
if err != nil {
return nil, err
}
return result, nil
}
// ArgsLenAtDash will return the length of f.Args at the moment when a -- was
// found during arg parsing. This allows your program to know which args were
// before the -- and which came after.
func (f *FlagSet) ArgsLenAtDash() int {
return f.argsLenAtDash
}
// MarkDeprecated indicated that a flag is deprecated in your program. It will
// continue to function but will not show up in help or usage messages. Using
// this flag will also print the given usageMessage.
func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error {
flag := f.Lookup(name) flag := f.Lookup(name)
if flag == nil { if flag == nil {
return fmt.Errorf("flag %q does not exist", name) return fmt.Errorf("flag %q does not exist", name)
} }
if len(usageMessage) == 0 {
return fmt.Errorf("deprecated message for flag %q must be set", name)
}
flag.Deprecated = usageMessage flag.Deprecated = usageMessage
return nil return nil
} }
// MarkShorthandDeprecated will mark the shorthand of a flag deprecated in your
// program. It will continue to function but will not show up in help or usage
// messages. Using this flag will also print the given usageMessage.
func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) error {
flag := f.Lookup(name)
if flag == nil {
return fmt.Errorf("flag %q does not exist", name)
}
if len(usageMessage) == 0 {
return fmt.Errorf("deprecated message for flag %q must be set", name)
}
flag.ShorthandDeprecated = usageMessage
return nil
}
// MarkHidden sets a flag to 'hidden' in your program. It will continue to
// function but will not show up in help or usage messages.
func (f *FlagSet) MarkHidden(name string) error {
flag := f.Lookup(name)
if flag == nil {
return fmt.Errorf("flag %q does not exist", name)
}
flag.Hidden = true
return nil
}
// Lookup returns the Flag structure of the named command-line flag, // Lookup returns the Flag structure of the named command-line flag,
// returning nil if none exists. // returning nil if none exists.
func Lookup(name string) *Flag { func Lookup(name string) *Flag {
@ -295,6 +380,33 @@ func (f *FlagSet) Set(name, value string) error {
return nil return nil
} }
// SetAnnotation allows one to set arbitrary annotations on a flag in the FlagSet.
// This is sometimes used by spf13/cobra programs which want to generate additional
// bash completion information.
func (f *FlagSet) SetAnnotation(name, key string, values []string) error {
normalName := f.normalizeFlagName(name)
flag, ok := f.formal[normalName]
if !ok {
return fmt.Errorf("no such flag -%v", name)
}
if flag.Annotations == nil {
flag.Annotations = map[string][]string{}
}
flag.Annotations[key] = values
return nil
}
// Changed returns true if the flag was explicitly set during Parse() and false
// otherwise
func (f *FlagSet) Changed(name string) bool {
flag := f.Lookup(name)
// If a flag doesn't exist, it wasn't changed....
if flag == nil {
return false
}
return flag.Changed
}
// Set sets the value of the named command-line flag. // Set sets the value of the named command-line flag.
func Set(name, value string) error { func Set(name, value string) error {
return CommandLine.Set(name, value) return CommandLine.Set(name, value)
@ -303,44 +415,140 @@ func Set(name, value string) error {
// PrintDefaults prints, to standard error unless configured // PrintDefaults prints, to standard error unless configured
// otherwise, the default values of all defined flags in the set. // otherwise, the default values of all defined flags in the set.
func (f *FlagSet) PrintDefaults() { func (f *FlagSet) PrintDefaults() {
f.VisitAll(func(flag *Flag) { usages := f.FlagUsages()
if len(flag.Deprecated) > 0 { fmt.Fprint(f.out(), usages)
return
}
format := "--%s=%s: %s\n"
if _, ok := flag.Value.(*stringValue); ok {
// put quotes on the value
format = "--%s=%q: %s\n"
}
if len(flag.Shorthand) > 0 {
format = " -%s, " + format
} else {
format = " %s " + format
}
fmt.Fprintf(f.out(), format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage)
})
} }
// defaultIsZeroValue returns true if the default value for this flag represents
// a zero value.
func (f *Flag) defaultIsZeroValue() bool {
switch f.Value.(type) {
case boolFlag:
return f.DefValue == "false"
case *durationValue:
// Beginning in Go 1.7, duration zero values are "0s"
return f.DefValue == "0" || f.DefValue == "0s"
case *intValue, *int8Value, *int32Value, *int64Value, *uintValue, *uint8Value, *uint16Value, *uint32Value, *uint64Value, *countValue, *float32Value, *float64Value:
return f.DefValue == "0"
case *stringValue:
return f.DefValue == ""
case *ipValue, *ipMaskValue, *ipNetValue:
return f.DefValue == "<nil>"
case *intSliceValue, *stringSliceValue, *stringArrayValue:
return f.DefValue == "[]"
default:
switch f.Value.String() {
case "false":
return true
case "<nil>":
return true
case "":
return true
case "0":
return true
}
return false
}
}
// UnquoteUsage extracts a back-quoted name from the usage
// string for a flag and returns it and the un-quoted usage.
// Given "a `name` to show" it returns ("name", "a name to show").
// If there are no back quotes, the name is an educated guess of the
// type of the flag's value, or the empty string if the flag is boolean.
func UnquoteUsage(flag *Flag) (name string, usage string) {
// Look for a back-quoted name, but avoid the strings package.
usage = flag.Usage
for i := 0; i < len(usage); i++ {
if usage[i] == '`' {
for j := i + 1; j < len(usage); j++ {
if usage[j] == '`' {
name = usage[i+1 : j]
usage = usage[:i] + name + usage[j+1:]
return name, usage
}
}
break // Only one back quote; use type name.
}
}
name = flag.Value.Type()
switch name {
case "bool":
name = ""
case "float64":
name = "float"
case "int64":
name = "int"
case "uint64":
name = "uint"
}
return
}
// FlagUsages Returns a string containing the usage information for all flags in
// the FlagSet
func (f *FlagSet) FlagUsages() string { func (f *FlagSet) FlagUsages() string {
x := new(bytes.Buffer) x := new(bytes.Buffer)
lines := make([]string, 0, len(f.formal))
maxlen := 0
f.VisitAll(func(flag *Flag) { f.VisitAll(func(flag *Flag) {
if len(flag.Deprecated) > 0 { if len(flag.Deprecated) > 0 || flag.Hidden {
return return
} }
format := "--%s=%s: %s\n"
if _, ok := flag.Value.(*stringValue); ok { line := ""
// put quotes on the value if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 {
format = "--%s=%q: %s\n" line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
}
if len(flag.Shorthand) > 0 {
format = " -%s, " + format
} else { } else {
format = " %s " + format line = fmt.Sprintf(" --%s", flag.Name)
} }
fmt.Fprintf(x, format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage)
varname, usage := UnquoteUsage(flag)
if len(varname) > 0 {
line += " " + varname
}
if len(flag.NoOptDefVal) > 0 {
switch flag.Value.Type() {
case "string":
line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal)
case "bool":
if flag.NoOptDefVal != "true" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
default:
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
}
// This special character will be replaced with spacing once the
// correct alignment is calculated
line += "\x00"
if len(line) > maxlen {
maxlen = len(line)
}
line += usage
if !flag.defaultIsZeroValue() {
if flag.Value.Type() == "string" {
line += fmt.Sprintf(" (default \"%s\")", flag.DefValue)
} else {
line += fmt.Sprintf(" (default %s)", flag.DefValue)
}
}
lines = append(lines, line)
}) })
for _, line := range lines {
sidx := strings.Index(line, "\x00")
spacing := strings.Repeat(" ", maxlen-sidx)
fmt.Fprintln(x, line[:sidx], spacing, line[sidx+1:])
}
return x.String() return x.String()
} }
@ -361,6 +569,8 @@ func defaultUsage(f *FlagSet) {
// Usage prints to standard error a usage message documenting all defined command-line flags. // Usage prints to standard error a usage message documenting all defined command-line flags.
// The function is a variable that may be changed to point to a custom function. // The function is a variable that may be changed to point to a custom function.
// By default it prints a simple header and calls PrintDefaults; for details about the
// format of the output and how to control it, see the documentation for PrintDefaults.
var Usage = func() { var Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
PrintDefaults() PrintDefaults()
@ -409,8 +619,8 @@ func (f *FlagSet) Var(value Value, name string, usage string) {
f.VarP(value, name, "", usage) f.VarP(value, name, "", usage)
} }
// Like Var, but accepts a shorthand letter that can be used after a single dash. // VarPF is like VarP, but returns the flag created
func (f *FlagSet) VarP(value Value, name, shorthand, usage string) { func (f *FlagSet) VarPF(value Value, name, shorthand, usage string) *Flag {
// Remember the default value as a string; it won't change. // Remember the default value as a string; it won't change.
flag := &Flag{ flag := &Flag{
Name: name, Name: name,
@ -420,11 +630,18 @@ func (f *FlagSet) VarP(value Value, name, shorthand, usage string) {
DefValue: value.String(), DefValue: value.String(),
} }
f.AddFlag(flag) f.AddFlag(flag)
return flag
} }
// VarP is like Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) VarP(value Value, name, shorthand, usage string) {
_ = f.VarPF(value, name, shorthand, usage)
}
// AddFlag will add the flag to the FlagSet
func (f *FlagSet) AddFlag(flag *Flag) { func (f *FlagSet) AddFlag(flag *Flag) {
// Call normalizeFlagName function only once // Call normalizeFlagName function only once
var normalizedFlagName NormalizedName = f.normalizeFlagName(flag.Name) normalizedFlagName := f.normalizeFlagName(flag.Name)
_, alreadythere := f.formal[normalizedFlagName] _, alreadythere := f.formal[normalizedFlagName]
if alreadythere { if alreadythere {
@ -458,6 +675,19 @@ func (f *FlagSet) AddFlag(flag *Flag) {
f.shorthands[c] = flag f.shorthands[c] = flag
} }
// AddFlagSet adds one FlagSet to another. If a flag is already present in f
// the flag from newSet will be ignored
func (f *FlagSet) AddFlagSet(newSet *FlagSet) {
if newSet == nil {
return
}
newSet.VisitAll(func(flag *Flag) {
if f.Lookup(flag.Name) == nil {
f.AddFlag(flag)
}
})
}
// Var defines a flag with the specified name and usage string. The type and // Var defines a flag with the specified name and usage string. The type and
// value of the flag are represented by the first argument, of type Value, which // value of the flag are represented by the first argument, of type Value, which
// typically holds a user-defined implementation of Value. For instance, the // typically holds a user-defined implementation of Value. For instance, the
@ -468,7 +698,7 @@ func Var(value Value, name string, usage string) {
CommandLine.VarP(value, name, "", usage) CommandLine.VarP(value, name, "", usage)
} }
// Like Var, but accepts a shorthand letter that can be used after a single dash. // VarP is like Var, but accepts a shorthand letter that can be used after a single dash.
func VarP(value Value, name, shorthand, usage string) { func VarP(value Value, name, shorthand, usage string) {
CommandLine.VarP(value, name, shorthand, usage) CommandLine.VarP(value, name, shorthand, usage)
} }
@ -507,9 +737,21 @@ func (f *FlagSet) setFlag(flag *Flag, value string, origArg string) error {
if len(flag.Deprecated) > 0 { if len(flag.Deprecated) > 0 {
fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
} }
if len(flag.ShorthandDeprecated) > 0 && containsShorthand(origArg, flag.Shorthand) {
fmt.Fprintf(os.Stderr, "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated)
}
return nil return nil
} }
func containsShorthand(arg, shorthand string) bool {
// filter out flags --<flag_name>
if strings.HasPrefix(arg, "-") {
return false
}
arg = strings.SplitN(arg, "=", 2)[0]
return strings.Contains(arg, shorthand)
}
func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error) { func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error) {
a = args a = args
name := s[2:] name := s[2:]
@ -532,11 +774,15 @@ func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error)
if len(split) == 2 { if len(split) == 2 {
// '--flag=arg' // '--flag=arg'
value = split[1] value = split[1]
} else if bv, ok := flag.Value.(boolFlag); ok && bv.IsBoolFlag() { } else if len(flag.NoOptDefVal) > 0 {
// '--flag' (where flag is a bool) // '--flag' (arg was optional)
value = "true" value = flag.NoOptDefVal
} else if len(a) > 0 {
// '--flag arg'
value = a[0]
a = a[1:]
} else { } else {
// '--flag' (where flag was not a bool) // '--flag' (arg was required)
err = f.failf("flag needs an argument: %s", s) err = f.failf("flag needs an argument: %s", s)
return return
} }
@ -545,6 +791,9 @@ func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error)
} }
func (f *FlagSet) parseSingleShortArg(shorthands string, args []string) (outShorts string, outArgs []string, err error) { func (f *FlagSet) parseSingleShortArg(shorthands string, args []string) (outShorts string, outArgs []string, err error) {
if strings.HasPrefix(shorthands, "test.") {
return
}
outArgs = args outArgs = args
outShorts = shorthands[1:] outShorts = shorthands[1:]
c := shorthands[0] c := shorthands[0]
@ -564,8 +813,8 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string) (outShor
if len(shorthands) > 2 && shorthands[1] == '=' { if len(shorthands) > 2 && shorthands[1] == '=' {
value = shorthands[2:] value = shorthands[2:]
outShorts = "" outShorts = ""
} else if bv, ok := flag.Value.(boolFlag); ok && bv.IsBoolFlag() { } else if len(flag.NoOptDefVal) > 0 {
value = "true" value = flag.NoOptDefVal
} else if len(shorthands) > 1 { } else if len(shorthands) > 1 {
value = shorthands[1:] value = shorthands[1:]
outShorts = "" outShorts = ""
@ -610,6 +859,7 @@ func (f *FlagSet) parseArgs(args []string) (err error) {
if s[1] == '-' { if s[1] == '-' {
if len(s) == 2 { // "--" terminates the flags if len(s) == 2 { // "--" terminates the flags
f.argsLenAtDash = len(f.args)
f.args = append(f.args, args...) f.args = append(f.args, args...)
break break
} }
@ -657,7 +907,7 @@ func Parse() {
CommandLine.Parse(os.Args[1:]) CommandLine.Parse(os.Args[1:])
} }
// Whether to support interspersed option/non-option arguments. // SetInterspersed sets whether to support interspersed option/non-option arguments.
func SetInterspersed(interspersed bool) { func SetInterspersed(interspersed bool) {
CommandLine.SetInterspersed(interspersed) CommandLine.SetInterspersed(interspersed)
} }
@ -667,7 +917,7 @@ func Parsed() bool {
return CommandLine.Parsed() return CommandLine.Parsed()
} }
// The default set of command-line flags, parsed from os.Args. // CommandLine is the default set of command-line flags, parsed from os.Args.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError) var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
// NewFlagSet returns a new, empty flag set with the specified name and // NewFlagSet returns a new, empty flag set with the specified name and
@ -676,12 +926,13 @@ func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
f := &FlagSet{ f := &FlagSet{
name: name, name: name,
errorHandling: errorHandling, errorHandling: errorHandling,
argsLenAtDash: -1,
interspersed: true, interspersed: true,
} }
return f return f
} }
// Whether to support interspersed option/non-option arguments. // SetInterspersed sets whether to support interspersed option/non-option arguments.
func (f *FlagSet) SetInterspersed(interspersed bool) { func (f *FlagSet) SetInterspersed(interspersed bool) {
f.interspersed = interspersed f.interspersed = interspersed
} }
@ -692,4 +943,5 @@ func (f *FlagSet) SetInterspersed(interspersed bool) {
func (f *FlagSet) Init(name string, errorHandling ErrorHandling) { func (f *FlagSet) Init(name string, errorHandling ErrorHandling) {
f.name = name f.name = name
f.errorHandling = errorHandling f.errorHandling = errorHandling
f.argsLenAtDash = -1
} }

View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- float32 Value // -- float32 Value
type float32Value float32 type float32Value float32
@ -23,7 +20,24 @@ func (f *float32Value) Type() string {
return "float32" return "float32"
} }
func (f *float32Value) String() string { return fmt.Sprintf("%v", *f) } func (f *float32Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 32) }
func float32Conv(sval string) (interface{}, error) {
v, err := strconv.ParseFloat(sval, 32)
if err != nil {
return 0, err
}
return float32(v), nil
}
// GetFloat32 return the float32 value of a flag with the given name
func (f *FlagSet) GetFloat32(name string) (float32, error) {
val, err := f.getFlagType(name, "float32", float32Conv)
if err != nil {
return 0, err
}
return val.(float32), nil
}
// Float32Var defines a float32 flag with specified name, default value, and usage string. // Float32Var defines a float32 flag with specified name, default value, and usage string.
// The argument p points to a float32 variable in which to store the value of the flag. // The argument p points to a float32 variable in which to store the value of the flag.
@ -31,7 +45,7 @@ func (f *FlagSet) Float32Var(p *float32, name string, value float32, usage strin
f.VarP(newFloat32Value(value, p), name, "", usage) f.VarP(newFloat32Value(value, p), name, "", usage)
} }
// Like Float32Var, but accepts a shorthand letter that can be used after a single dash. // Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Float32VarP(p *float32, name, shorthand string, value float32, usage string) { func (f *FlagSet) Float32VarP(p *float32, name, shorthand string, value float32, usage string) {
f.VarP(newFloat32Value(value, p), name, shorthand, usage) f.VarP(newFloat32Value(value, p), name, shorthand, usage)
} }
@ -42,7 +56,7 @@ func Float32Var(p *float32, name string, value float32, usage string) {
CommandLine.VarP(newFloat32Value(value, p), name, "", usage) CommandLine.VarP(newFloat32Value(value, p), name, "", usage)
} }
// Like Float32Var, but accepts a shorthand letter that can be used after a single dash. // Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash.
func Float32VarP(p *float32, name, shorthand string, value float32, usage string) { func Float32VarP(p *float32, name, shorthand string, value float32, usage string) {
CommandLine.VarP(newFloat32Value(value, p), name, shorthand, usage) CommandLine.VarP(newFloat32Value(value, p), name, shorthand, usage)
} }
@ -55,7 +69,7 @@ func (f *FlagSet) Float32(name string, value float32, usage string) *float32 {
return p return p
} }
// Like Float32, but accepts a shorthand letter that can be used after a single dash. // Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Float32P(name, shorthand string, value float32, usage string) *float32 { func (f *FlagSet) Float32P(name, shorthand string, value float32, usage string) *float32 {
p := new(float32) p := new(float32)
f.Float32VarP(p, name, shorthand, value, usage) f.Float32VarP(p, name, shorthand, value, usage)
@ -68,7 +82,7 @@ func Float32(name string, value float32, usage string) *float32 {
return CommandLine.Float32P(name, "", value, usage) return CommandLine.Float32P(name, "", value, usage)
} }
// Like Float32, but accepts a shorthand letter that can be used after a single dash. // Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash.
func Float32P(name, shorthand string, value float32, usage string) *float32 { func Float32P(name, shorthand string, value float32, usage string) *float32 {
return CommandLine.Float32P(name, shorthand, value, usage) return CommandLine.Float32P(name, shorthand, value, usage)
} }

View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- float64 Value // -- float64 Value
type float64Value float64 type float64Value float64
@ -23,7 +20,20 @@ func (f *float64Value) Type() string {
return "float64" return "float64"
} }
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) } func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) }
func float64Conv(sval string) (interface{}, error) {
return strconv.ParseFloat(sval, 64)
}
// GetFloat64 return the float64 value of a flag with the given name
func (f *FlagSet) GetFloat64(name string) (float64, error) {
val, err := f.getFlagType(name, "float64", float64Conv)
if err != nil {
return 0, err
}
return val.(float64), nil
}
// Float64Var defines a float64 flag with specified name, default value, and usage string. // Float64Var defines a float64 flag with specified name, default value, and usage string.
// The argument p points to a float64 variable in which to store the value of the flag. // The argument p points to a float64 variable in which to store the value of the flag.
@ -31,7 +41,7 @@ func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage strin
f.VarP(newFloat64Value(value, p), name, "", usage) f.VarP(newFloat64Value(value, p), name, "", usage)
} }
// Like Float64Var, but accepts a shorthand letter that can be used after a single dash. // Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Float64VarP(p *float64, name, shorthand string, value float64, usage string) { func (f *FlagSet) Float64VarP(p *float64, name, shorthand string, value float64, usage string) {
f.VarP(newFloat64Value(value, p), name, shorthand, usage) f.VarP(newFloat64Value(value, p), name, shorthand, usage)
} }
@ -42,7 +52,7 @@ func Float64Var(p *float64, name string, value float64, usage string) {
CommandLine.VarP(newFloat64Value(value, p), name, "", usage) CommandLine.VarP(newFloat64Value(value, p), name, "", usage)
} }
// Like Float64Var, but accepts a shorthand letter that can be used after a single dash. // Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash.
func Float64VarP(p *float64, name, shorthand string, value float64, usage string) { func Float64VarP(p *float64, name, shorthand string, value float64, usage string) {
CommandLine.VarP(newFloat64Value(value, p), name, shorthand, usage) CommandLine.VarP(newFloat64Value(value, p), name, shorthand, usage)
} }
@ -55,7 +65,7 @@ func (f *FlagSet) Float64(name string, value float64, usage string) *float64 {
return p return p
} }
// Like Float64, but accepts a shorthand letter that can be used after a single dash. // Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Float64P(name, shorthand string, value float64, usage string) *float64 { func (f *FlagSet) Float64P(name, shorthand string, value float64, usage string) *float64 {
p := new(float64) p := new(float64)
f.Float64VarP(p, name, shorthand, value, usage) f.Float64VarP(p, name, shorthand, value, usage)
@ -68,7 +78,7 @@ func Float64(name string, value float64, usage string) *float64 {
return CommandLine.Float64P(name, "", value, usage) return CommandLine.Float64P(name, "", value, usage)
} }
// Like Float64, but accepts a shorthand letter that can be used after a single dash. // Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash.
func Float64P(name, shorthand string, value float64, usage string) *float64 { func Float64P(name, shorthand string, value float64, usage string) *float64 {
return CommandLine.Float64P(name, shorthand, value, usage) return CommandLine.Float64P(name, shorthand, value, usage)
} }

104
vendor/github.com/spf13/pflag/golangflag.go generated vendored Normal file
View file

@ -0,0 +1,104 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pflag
import (
goflag "flag"
"fmt"
"reflect"
"strings"
)
var _ = fmt.Print
// flagValueWrapper implements pflag.Value around a flag.Value. The main
// difference here is the addition of the Type method that returns a string
// name of the type. As this is generally unknown, we approximate that with
// reflection.
type flagValueWrapper struct {
inner goflag.Value
flagType string
}
// We are just copying the boolFlag interface out of goflag as that is what
// they use to decide if a flag should get "true" when no arg is given.
type goBoolFlag interface {
goflag.Value
IsBoolFlag() bool
}
func wrapFlagValue(v goflag.Value) Value {
// If the flag.Value happens to also be a pflag.Value, just use it directly.
if pv, ok := v.(Value); ok {
return pv
}
pv := &flagValueWrapper{
inner: v,
}
t := reflect.TypeOf(v)
if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr {
t = t.Elem()
}
pv.flagType = strings.TrimSuffix(t.Name(), "Value")
return pv
}
func (v *flagValueWrapper) String() string {
return v.inner.String()
}
func (v *flagValueWrapper) Set(s string) error {
return v.inner.Set(s)
}
func (v *flagValueWrapper) Type() string {
return v.flagType
}
// PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag
// If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei
// with both `-v` and `--v` in flags. If the golang flag was more than a single
// character (ex: `verbose`) it will only be accessible via `--verbose`
func PFlagFromGoFlag(goflag *goflag.Flag) *Flag {
// Remember the default value as a string; it won't change.
flag := &Flag{
Name: goflag.Name,
Usage: goflag.Usage,
Value: wrapFlagValue(goflag.Value),
// Looks like golang flags don't set DefValue correctly :-(
//DefValue: goflag.DefValue,
DefValue: goflag.Value.String(),
}
// Ex: if the golang flag was -v, allow both -v and --v to work
if len(flag.Name) == 1 {
flag.Shorthand = flag.Name
}
if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() {
flag.NoOptDefVal = "true"
}
return flag
}
// AddGoFlag will add the given *flag.Flag to the pflag.FlagSet
func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) {
if f.Lookup(goflag.Name) != nil {
return
}
newflag := PFlagFromGoFlag(goflag)
f.AddFlag(newflag)
}
// AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet
func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) {
if newSet == nil {
return
}
newSet.VisitAll(func(goflag *goflag.Flag) {
f.AddGoFlag(goflag)
})
}

28
vendor/github.com/spf13/pflag/int.go generated vendored
View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- int Value // -- int Value
type intValue int type intValue int
@ -23,7 +20,20 @@ func (i *intValue) Type() string {
return "int" return "int"
} }
func (i *intValue) String() string { return fmt.Sprintf("%v", *i) } func (i *intValue) String() string { return strconv.Itoa(int(*i)) }
func intConv(sval string) (interface{}, error) {
return strconv.Atoi(sval)
}
// GetInt return the int value of a flag with the given name
func (f *FlagSet) GetInt(name string) (int, error) {
val, err := f.getFlagType(name, "int", intConv)
if err != nil {
return 0, err
}
return val.(int), nil
}
// IntVar defines an int flag with specified name, default value, and usage string. // IntVar defines an int flag with specified name, default value, and usage string.
// The argument p points to an int variable in which to store the value of the flag. // The argument p points to an int variable in which to store the value of the flag.
@ -31,7 +41,7 @@ func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
f.VarP(newIntValue(value, p), name, "", usage) f.VarP(newIntValue(value, p), name, "", usage)
} }
// Like IntVar, but accepts a shorthand letter that can be used after a single dash. // IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) { func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) {
f.VarP(newIntValue(value, p), name, shorthand, usage) f.VarP(newIntValue(value, p), name, shorthand, usage)
} }
@ -42,7 +52,7 @@ func IntVar(p *int, name string, value int, usage string) {
CommandLine.VarP(newIntValue(value, p), name, "", usage) CommandLine.VarP(newIntValue(value, p), name, "", usage)
} }
// Like IntVar, but accepts a shorthand letter that can be used after a single dash. // IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash.
func IntVarP(p *int, name, shorthand string, value int, usage string) { func IntVarP(p *int, name, shorthand string, value int, usage string) {
CommandLine.VarP(newIntValue(value, p), name, shorthand, usage) CommandLine.VarP(newIntValue(value, p), name, shorthand, usage)
} }
@ -55,7 +65,7 @@ func (f *FlagSet) Int(name string, value int, usage string) *int {
return p return p
} }
// Like Int, but accepts a shorthand letter that can be used after a single dash. // IntP is like Int, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IntP(name, shorthand string, value int, usage string) *int { func (f *FlagSet) IntP(name, shorthand string, value int, usage string) *int {
p := new(int) p := new(int)
f.IntVarP(p, name, shorthand, value, usage) f.IntVarP(p, name, shorthand, value, usage)
@ -68,7 +78,7 @@ func Int(name string, value int, usage string) *int {
return CommandLine.IntP(name, "", value, usage) return CommandLine.IntP(name, "", value, usage)
} }
// Like Int, but accepts a shorthand letter that can be used after a single dash. // IntP is like Int, but accepts a shorthand letter that can be used after a single dash.
func IntP(name, shorthand string, value int, usage string) *int { func IntP(name, shorthand string, value int, usage string) *int {
return CommandLine.IntP(name, shorthand, value, usage) return CommandLine.IntP(name, shorthand, value, usage)
} }

View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- int32 Value // -- int32 Value
type int32Value int32 type int32Value int32
@ -23,7 +20,24 @@ func (i *int32Value) Type() string {
return "int32" return "int32"
} }
func (i *int32Value) String() string { return fmt.Sprintf("%v", *i) } func (i *int32Value) String() string { return strconv.FormatInt(int64(*i), 10) }
func int32Conv(sval string) (interface{}, error) {
v, err := strconv.ParseInt(sval, 0, 32)
if err != nil {
return 0, err
}
return int32(v), nil
}
// GetInt32 return the int32 value of a flag with the given name
func (f *FlagSet) GetInt32(name string) (int32, error) {
val, err := f.getFlagType(name, "int32", int32Conv)
if err != nil {
return 0, err
}
return val.(int32), nil
}
// Int32Var defines an int32 flag with specified name, default value, and usage string. // Int32Var defines an int32 flag with specified name, default value, and usage string.
// The argument p points to an int32 variable in which to store the value of the flag. // The argument p points to an int32 variable in which to store the value of the flag.
@ -31,7 +45,7 @@ func (f *FlagSet) Int32Var(p *int32, name string, value int32, usage string) {
f.VarP(newInt32Value(value, p), name, "", usage) f.VarP(newInt32Value(value, p), name, "", usage)
} }
// Like Int32Var, but accepts a shorthand letter that can be used after a single dash. // Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int32VarP(p *int32, name, shorthand string, value int32, usage string) { func (f *FlagSet) Int32VarP(p *int32, name, shorthand string, value int32, usage string) {
f.VarP(newInt32Value(value, p), name, shorthand, usage) f.VarP(newInt32Value(value, p), name, shorthand, usage)
} }
@ -42,7 +56,7 @@ func Int32Var(p *int32, name string, value int32, usage string) {
CommandLine.VarP(newInt32Value(value, p), name, "", usage) CommandLine.VarP(newInt32Value(value, p), name, "", usage)
} }
// Like Int32Var, but accepts a shorthand letter that can be used after a single dash. // Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash.
func Int32VarP(p *int32, name, shorthand string, value int32, usage string) { func Int32VarP(p *int32, name, shorthand string, value int32, usage string) {
CommandLine.VarP(newInt32Value(value, p), name, shorthand, usage) CommandLine.VarP(newInt32Value(value, p), name, shorthand, usage)
} }
@ -55,7 +69,7 @@ func (f *FlagSet) Int32(name string, value int32, usage string) *int32 {
return p return p
} }
// Like Int32, but accepts a shorthand letter that can be used after a single dash. // Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int32P(name, shorthand string, value int32, usage string) *int32 { func (f *FlagSet) Int32P(name, shorthand string, value int32, usage string) *int32 {
p := new(int32) p := new(int32)
f.Int32VarP(p, name, shorthand, value, usage) f.Int32VarP(p, name, shorthand, value, usage)
@ -68,7 +82,7 @@ func Int32(name string, value int32, usage string) *int32 {
return CommandLine.Int32P(name, "", value, usage) return CommandLine.Int32P(name, "", value, usage)
} }
// Like Int32, but accepts a shorthand letter that can be used after a single dash. // Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash.
func Int32P(name, shorthand string, value int32, usage string) *int32 { func Int32P(name, shorthand string, value int32, usage string) *int32 {
return CommandLine.Int32P(name, shorthand, value, usage) return CommandLine.Int32P(name, shorthand, value, usage)
} }

View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- int64 Value // -- int64 Value
type int64Value int64 type int64Value int64
@ -23,7 +20,20 @@ func (i *int64Value) Type() string {
return "int64" return "int64"
} }
func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) } func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) }
func int64Conv(sval string) (interface{}, error) {
return strconv.ParseInt(sval, 0, 64)
}
// GetInt64 return the int64 value of a flag with the given name
func (f *FlagSet) GetInt64(name string) (int64, error) {
val, err := f.getFlagType(name, "int64", int64Conv)
if err != nil {
return 0, err
}
return val.(int64), nil
}
// Int64Var defines an int64 flag with specified name, default value, and usage string. // Int64Var defines an int64 flag with specified name, default value, and usage string.
// The argument p points to an int64 variable in which to store the value of the flag. // The argument p points to an int64 variable in which to store the value of the flag.
@ -31,7 +41,7 @@ func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) {
f.VarP(newInt64Value(value, p), name, "", usage) f.VarP(newInt64Value(value, p), name, "", usage)
} }
// Like Int64Var, but accepts a shorthand letter that can be used after a single dash. // Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int64VarP(p *int64, name, shorthand string, value int64, usage string) { func (f *FlagSet) Int64VarP(p *int64, name, shorthand string, value int64, usage string) {
f.VarP(newInt64Value(value, p), name, shorthand, usage) f.VarP(newInt64Value(value, p), name, shorthand, usage)
} }
@ -42,7 +52,7 @@ func Int64Var(p *int64, name string, value int64, usage string) {
CommandLine.VarP(newInt64Value(value, p), name, "", usage) CommandLine.VarP(newInt64Value(value, p), name, "", usage)
} }
// Like Int64Var, but accepts a shorthand letter that can be used after a single dash. // Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash.
func Int64VarP(p *int64, name, shorthand string, value int64, usage string) { func Int64VarP(p *int64, name, shorthand string, value int64, usage string) {
CommandLine.VarP(newInt64Value(value, p), name, shorthand, usage) CommandLine.VarP(newInt64Value(value, p), name, shorthand, usage)
} }
@ -55,7 +65,7 @@ func (f *FlagSet) Int64(name string, value int64, usage string) *int64 {
return p return p
} }
// Like Int64, but accepts a shorthand letter that can be used after a single dash. // Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int64P(name, shorthand string, value int64, usage string) *int64 { func (f *FlagSet) Int64P(name, shorthand string, value int64, usage string) *int64 {
p := new(int64) p := new(int64)
f.Int64VarP(p, name, shorthand, value, usage) f.Int64VarP(p, name, shorthand, value, usage)
@ -68,7 +78,7 @@ func Int64(name string, value int64, usage string) *int64 {
return CommandLine.Int64P(name, "", value, usage) return CommandLine.Int64P(name, "", value, usage)
} }
// Like Int64, but accepts a shorthand letter that can be used after a single dash. // Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash.
func Int64P(name, shorthand string, value int64, usage string) *int64 { func Int64P(name, shorthand string, value int64, usage string) *int64 {
return CommandLine.Int64P(name, shorthand, value, usage) return CommandLine.Int64P(name, shorthand, value, usage)
} }

View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- int8 Value // -- int8 Value
type int8Value int8 type int8Value int8
@ -23,7 +20,24 @@ func (i *int8Value) Type() string {
return "int8" return "int8"
} }
func (i *int8Value) String() string { return fmt.Sprintf("%v", *i) } func (i *int8Value) String() string { return strconv.FormatInt(int64(*i), 10) }
func int8Conv(sval string) (interface{}, error) {
v, err := strconv.ParseInt(sval, 0, 8)
if err != nil {
return 0, err
}
return int8(v), nil
}
// GetInt8 return the int8 value of a flag with the given name
func (f *FlagSet) GetInt8(name string) (int8, error) {
val, err := f.getFlagType(name, "int8", int8Conv)
if err != nil {
return 0, err
}
return val.(int8), nil
}
// Int8Var defines an int8 flag with specified name, default value, and usage string. // Int8Var defines an int8 flag with specified name, default value, and usage string.
// The argument p points to an int8 variable in which to store the value of the flag. // The argument p points to an int8 variable in which to store the value of the flag.
@ -31,7 +45,7 @@ func (f *FlagSet) Int8Var(p *int8, name string, value int8, usage string) {
f.VarP(newInt8Value(value, p), name, "", usage) f.VarP(newInt8Value(value, p), name, "", usage)
} }
// Like Int8Var, but accepts a shorthand letter that can be used after a single dash. // Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int8VarP(p *int8, name, shorthand string, value int8, usage string) { func (f *FlagSet) Int8VarP(p *int8, name, shorthand string, value int8, usage string) {
f.VarP(newInt8Value(value, p), name, shorthand, usage) f.VarP(newInt8Value(value, p), name, shorthand, usage)
} }
@ -42,7 +56,7 @@ func Int8Var(p *int8, name string, value int8, usage string) {
CommandLine.VarP(newInt8Value(value, p), name, "", usage) CommandLine.VarP(newInt8Value(value, p), name, "", usage)
} }
// Like Int8Var, but accepts a shorthand letter that can be used after a single dash. // Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash.
func Int8VarP(p *int8, name, shorthand string, value int8, usage string) { func Int8VarP(p *int8, name, shorthand string, value int8, usage string) {
CommandLine.VarP(newInt8Value(value, p), name, shorthand, usage) CommandLine.VarP(newInt8Value(value, p), name, shorthand, usage)
} }
@ -55,7 +69,7 @@ func (f *FlagSet) Int8(name string, value int8, usage string) *int8 {
return p return p
} }
// Like Int8, but accepts a shorthand letter that can be used after a single dash. // Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int8P(name, shorthand string, value int8, usage string) *int8 { func (f *FlagSet) Int8P(name, shorthand string, value int8, usage string) *int8 {
p := new(int8) p := new(int8)
f.Int8VarP(p, name, shorthand, value, usage) f.Int8VarP(p, name, shorthand, value, usage)
@ -68,7 +82,7 @@ func Int8(name string, value int8, usage string) *int8 {
return CommandLine.Int8P(name, "", value, usage) return CommandLine.Int8P(name, "", value, usage)
} }
// Like Int8, but accepts a shorthand letter that can be used after a single dash. // Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash.
func Int8P(name, shorthand string, value int8, usage string) *int8 { func Int8P(name, shorthand string, value int8, usage string) *int8 {
return CommandLine.Int8P(name, shorthand, value, usage) return CommandLine.Int8P(name, shorthand, value, usage)
} }

128
vendor/github.com/spf13/pflag/int_slice.go generated vendored Normal file
View file

@ -0,0 +1,128 @@
package pflag
import (
"fmt"
"strconv"
"strings"
)
// -- intSlice Value
type intSliceValue struct {
value *[]int
changed bool
}
func newIntSliceValue(val []int, p *[]int) *intSliceValue {
isv := new(intSliceValue)
isv.value = p
*isv.value = val
return isv
}
func (s *intSliceValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make([]int, len(ss))
for i, d := range ss {
var err error
out[i], err = strconv.Atoi(d)
if err != nil {
return err
}
}
if !s.changed {
*s.value = out
} else {
*s.value = append(*s.value, out...)
}
s.changed = true
return nil
}
func (s *intSliceValue) Type() string {
return "intSlice"
}
func (s *intSliceValue) String() string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = fmt.Sprintf("%d", d)
}
return "[" + strings.Join(out, ",") + "]"
}
func intSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []int{}, nil
}
ss := strings.Split(val, ",")
out := make([]int, len(ss))
for i, d := range ss {
var err error
out[i], err = strconv.Atoi(d)
if err != nil {
return nil, err
}
}
return out, nil
}
// GetIntSlice return the []int value of a flag with the given name
func (f *FlagSet) GetIntSlice(name string) ([]int, error) {
val, err := f.getFlagType(name, "intSlice", intSliceConv)
if err != nil {
return []int{}, err
}
return val.([]int), nil
}
// IntSliceVar defines a intSlice flag with specified name, default value, and usage string.
// The argument p points to a []int variable in which to store the value of the flag.
func (f *FlagSet) IntSliceVar(p *[]int, name string, value []int, usage string) {
f.VarP(newIntSliceValue(value, p), name, "", usage)
}
// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) {
f.VarP(newIntSliceValue(value, p), name, shorthand, usage)
}
// IntSliceVar defines a int[] flag with specified name, default value, and usage string.
// The argument p points to a int[] variable in which to store the value of the flag.
func IntSliceVar(p *[]int, name string, value []int, usage string) {
CommandLine.VarP(newIntSliceValue(value, p), name, "", usage)
}
// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash.
func IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) {
CommandLine.VarP(newIntSliceValue(value, p), name, shorthand, usage)
}
// IntSlice defines a []int flag with specified name, default value, and usage string.
// The return value is the address of a []int variable that stores the value of the flag.
func (f *FlagSet) IntSlice(name string, value []int, usage string) *[]int {
p := []int{}
f.IntSliceVarP(&p, name, "", value, usage)
return &p
}
// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IntSliceP(name, shorthand string, value []int, usage string) *[]int {
p := []int{}
f.IntSliceVarP(&p, name, shorthand, value, usage)
return &p
}
// IntSlice defines a []int flag with specified name, default value, and usage string.
// The return value is the address of a []int variable that stores the value of the flag.
func IntSlice(name string, value []int, usage string) *[]int {
return CommandLine.IntSliceP(name, "", value, usage)
}
// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash.
func IntSliceP(name, shorthand string, value []int, usage string) *[]int {
return CommandLine.IntSliceP(name, shorthand, value, usage)
}

30
vendor/github.com/spf13/pflag/ip.go generated vendored
View file

@ -3,8 +3,11 @@ package pflag
import ( import (
"fmt" "fmt"
"net" "net"
"strings"
) )
var _ = strings.TrimSpace
// -- net.IP value // -- net.IP value
type ipValue net.IP type ipValue net.IP
@ -15,7 +18,7 @@ func newIPValue(val net.IP, p *net.IP) *ipValue {
func (i *ipValue) String() string { return net.IP(*i).String() } func (i *ipValue) String() string { return net.IP(*i).String() }
func (i *ipValue) Set(s string) error { func (i *ipValue) Set(s string) error {
ip := net.ParseIP(s) ip := net.ParseIP(strings.TrimSpace(s))
if ip == nil { if ip == nil {
return fmt.Errorf("failed to parse IP: %q", s) return fmt.Errorf("failed to parse IP: %q", s)
} }
@ -27,13 +30,30 @@ func (i *ipValue) Type() string {
return "ip" return "ip"
} }
func ipConv(sval string) (interface{}, error) {
ip := net.ParseIP(sval)
if ip != nil {
return ip, nil
}
return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval)
}
// GetIP return the net.IP value of a flag with the given name
func (f *FlagSet) GetIP(name string) (net.IP, error) {
val, err := f.getFlagType(name, "ip", ipConv)
if err != nil {
return nil, err
}
return val.(net.IP), nil
}
// IPVar defines an net.IP flag with specified name, default value, and usage string. // IPVar defines an net.IP flag with specified name, default value, and usage string.
// The argument p points to an net.IP variable in which to store the value of the flag. // The argument p points to an net.IP variable in which to store the value of the flag.
func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) { func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) {
f.VarP(newIPValue(value, p), name, "", usage) f.VarP(newIPValue(value, p), name, "", usage)
} }
// Like IPVar, but accepts a shorthand letter that can be used after a single dash. // IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { func (f *FlagSet) IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) {
f.VarP(newIPValue(value, p), name, shorthand, usage) f.VarP(newIPValue(value, p), name, shorthand, usage)
} }
@ -44,7 +64,7 @@ func IPVar(p *net.IP, name string, value net.IP, usage string) {
CommandLine.VarP(newIPValue(value, p), name, "", usage) CommandLine.VarP(newIPValue(value, p), name, "", usage)
} }
// Like IPVar, but accepts a shorthand letter that can be used after a single dash. // IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash.
func IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { func IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) {
CommandLine.VarP(newIPValue(value, p), name, shorthand, usage) CommandLine.VarP(newIPValue(value, p), name, shorthand, usage)
} }
@ -57,7 +77,7 @@ func (f *FlagSet) IP(name string, value net.IP, usage string) *net.IP {
return p return p
} }
// Like IP, but accepts a shorthand letter that can be used after a single dash. // IPP is like IP, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IPP(name, shorthand string, value net.IP, usage string) *net.IP { func (f *FlagSet) IPP(name, shorthand string, value net.IP, usage string) *net.IP {
p := new(net.IP) p := new(net.IP)
f.IPVarP(p, name, shorthand, value, usage) f.IPVarP(p, name, shorthand, value, usage)
@ -70,7 +90,7 @@ func IP(name string, value net.IP, usage string) *net.IP {
return CommandLine.IPP(name, "", value, usage) return CommandLine.IPP(name, "", value, usage)
} }
// Like IP, but accepts a shorthand letter that can be used after a single dash. // IPP is like IP, but accepts a shorthand letter that can be used after a single dash.
func IPP(name, shorthand string, value net.IP, usage string) *net.IP { func IPP(name, shorthand string, value net.IP, usage string) *net.IP {
return CommandLine.IPP(name, shorthand, value, usage) return CommandLine.IPP(name, shorthand, value, usage)
} }

View file

@ -3,6 +3,7 @@ package pflag
import ( import (
"fmt" "fmt"
"net" "net"
"strconv"
) )
// -- net.IPMask value // -- net.IPMask value
@ -27,23 +28,58 @@ func (i *ipMaskValue) Type() string {
return "ipMask" return "ipMask"
} }
// Parse IPv4 netmask written in IP form (e.g. 255.255.255.0). // ParseIPv4Mask written in IP form (e.g. 255.255.255.0).
// This function should really belong to the net package. // This function should really belong to the net package.
func ParseIPv4Mask(s string) net.IPMask { func ParseIPv4Mask(s string) net.IPMask {
mask := net.ParseIP(s) mask := net.ParseIP(s)
if mask == nil { if mask == nil {
return nil if len(s) != 8 {
return nil
}
// net.IPMask.String() actually outputs things like ffffff00
// so write a horrible parser for that as well :-(
m := []int{}
for i := 0; i < 4; i++ {
b := "0x" + s[2*i:2*i+2]
d, err := strconv.ParseInt(b, 0, 0)
if err != nil {
return nil
}
m = append(m, int(d))
}
s := fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3])
mask = net.ParseIP(s)
if mask == nil {
return nil
}
} }
return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15]) return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15])
} }
func parseIPv4Mask(sval string) (interface{}, error) {
mask := ParseIPv4Mask(sval)
if mask == nil {
return nil, fmt.Errorf("unable to parse %s as net.IPMask", sval)
}
return mask, nil
}
// GetIPv4Mask return the net.IPv4Mask value of a flag with the given name
func (f *FlagSet) GetIPv4Mask(name string) (net.IPMask, error) {
val, err := f.getFlagType(name, "ipMask", parseIPv4Mask)
if err != nil {
return nil, err
}
return val.(net.IPMask), nil
}
// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. // IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string.
// The argument p points to an net.IPMask variable in which to store the value of the flag. // The argument p points to an net.IPMask variable in which to store the value of the flag.
func (f *FlagSet) IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { func (f *FlagSet) IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) {
f.VarP(newIPMaskValue(value, p), name, "", usage) f.VarP(newIPMaskValue(value, p), name, "", usage)
} }
// Like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. // IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { func (f *FlagSet) IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) {
f.VarP(newIPMaskValue(value, p), name, shorthand, usage) f.VarP(newIPMaskValue(value, p), name, shorthand, usage)
} }
@ -54,7 +90,7 @@ func IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) {
CommandLine.VarP(newIPMaskValue(value, p), name, "", usage) CommandLine.VarP(newIPMaskValue(value, p), name, "", usage)
} }
// Like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. // IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash.
func IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { func IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) {
CommandLine.VarP(newIPMaskValue(value, p), name, shorthand, usage) CommandLine.VarP(newIPMaskValue(value, p), name, shorthand, usage)
} }
@ -67,7 +103,7 @@ func (f *FlagSet) IPMask(name string, value net.IPMask, usage string) *net.IPMas
return p return p
} }
// Like IPMask, but accepts a shorthand letter that can be used after a single dash. // IPMaskP is like IPMask, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { func (f *FlagSet) IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask {
p := new(net.IPMask) p := new(net.IPMask)
f.IPMaskVarP(p, name, shorthand, value, usage) f.IPMaskVarP(p, name, shorthand, value, usage)
@ -80,7 +116,7 @@ func IPMask(name string, value net.IPMask, usage string) *net.IPMask {
return CommandLine.IPMaskP(name, "", value, usage) return CommandLine.IPMaskP(name, "", value, usage)
} }
// Like IP, but accepts a shorthand letter that can be used after a single dash. // IPMaskP is like IP, but accepts a shorthand letter that can be used after a single dash.
func IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { func IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask {
return CommandLine.IPMaskP(name, shorthand, value, usage) return CommandLine.IPMaskP(name, shorthand, value, usage)
} }

100
vendor/github.com/spf13/pflag/ipnet.go generated vendored Normal file
View file

@ -0,0 +1,100 @@
package pflag
import (
"fmt"
"net"
"strings"
)
// IPNet adapts net.IPNet for use as a flag.
type ipNetValue net.IPNet
func (ipnet ipNetValue) String() string {
n := net.IPNet(ipnet)
return n.String()
}
func (ipnet *ipNetValue) Set(value string) error {
_, n, err := net.ParseCIDR(strings.TrimSpace(value))
if err != nil {
return err
}
*ipnet = ipNetValue(*n)
return nil
}
func (*ipNetValue) Type() string {
return "ipNet"
}
var _ = strings.TrimSpace
func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue {
*p = val
return (*ipNetValue)(p)
}
func ipNetConv(sval string) (interface{}, error) {
_, n, err := net.ParseCIDR(strings.TrimSpace(sval))
if err == nil {
return *n, nil
}
return nil, fmt.Errorf("invalid string being converted to IPNet: %s", sval)
}
// GetIPNet return the net.IPNet value of a flag with the given name
func (f *FlagSet) GetIPNet(name string) (net.IPNet, error) {
val, err := f.getFlagType(name, "ipNet", ipNetConv)
if err != nil {
return net.IPNet{}, err
}
return val.(net.IPNet), nil
}
// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string.
// The argument p points to an net.IPNet variable in which to store the value of the flag.
func (f *FlagSet) IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) {
f.VarP(newIPNetValue(value, p), name, "", usage)
}
// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) {
f.VarP(newIPNetValue(value, p), name, shorthand, usage)
}
// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string.
// The argument p points to an net.IPNet variable in which to store the value of the flag.
func IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) {
CommandLine.VarP(newIPNetValue(value, p), name, "", usage)
}
// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash.
func IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) {
CommandLine.VarP(newIPNetValue(value, p), name, shorthand, usage)
}
// IPNet defines an net.IPNet flag with specified name, default value, and usage string.
// The return value is the address of an net.IPNet variable that stores the value of the flag.
func (f *FlagSet) IPNet(name string, value net.IPNet, usage string) *net.IPNet {
p := new(net.IPNet)
f.IPNetVarP(p, name, "", value, usage)
return p
}
// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet {
p := new(net.IPNet)
f.IPNetVarP(p, name, shorthand, value, usage)
return p
}
// IPNet defines an net.IPNet flag with specified name, default value, and usage string.
// The return value is the address of an net.IPNet variable that stores the value of the flag.
func IPNet(name string, value net.IPNet, usage string) *net.IPNet {
return CommandLine.IPNetP(name, "", value, usage)
}
// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash.
func IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet {
return CommandLine.IPNetP(name, shorthand, value, usage)
}

View file

@ -1,7 +1,5 @@
package pflag package pflag
import "fmt"
// -- string Value // -- string Value
type stringValue string type stringValue string
@ -18,7 +16,20 @@ func (s *stringValue) Type() string {
return "string" return "string"
} }
func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) } func (s *stringValue) String() string { return string(*s) }
func stringConv(sval string) (interface{}, error) {
return sval, nil
}
// GetString return the string value of a flag with the given name
func (f *FlagSet) GetString(name string) (string, error) {
val, err := f.getFlagType(name, "string", stringConv)
if err != nil {
return "", err
}
return val.(string), nil
}
// StringVar defines a string flag with specified name, default value, and usage string. // StringVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a string variable in which to store the value of the flag. // The argument p points to a string variable in which to store the value of the flag.
@ -26,7 +37,7 @@ func (f *FlagSet) StringVar(p *string, name string, value string, usage string)
f.VarP(newStringValue(value, p), name, "", usage) f.VarP(newStringValue(value, p), name, "", usage)
} }
// Like StringVar, but accepts a shorthand letter that can be used after a single dash. // StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringVarP(p *string, name, shorthand string, value string, usage string) { func (f *FlagSet) StringVarP(p *string, name, shorthand string, value string, usage string) {
f.VarP(newStringValue(value, p), name, shorthand, usage) f.VarP(newStringValue(value, p), name, shorthand, usage)
} }
@ -37,7 +48,7 @@ func StringVar(p *string, name string, value string, usage string) {
CommandLine.VarP(newStringValue(value, p), name, "", usage) CommandLine.VarP(newStringValue(value, p), name, "", usage)
} }
// Like StringVar, but accepts a shorthand letter that can be used after a single dash. // StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash.
func StringVarP(p *string, name, shorthand string, value string, usage string) { func StringVarP(p *string, name, shorthand string, value string, usage string) {
CommandLine.VarP(newStringValue(value, p), name, shorthand, usage) CommandLine.VarP(newStringValue(value, p), name, shorthand, usage)
} }
@ -50,7 +61,7 @@ func (f *FlagSet) String(name string, value string, usage string) *string {
return p return p
} }
// Like String, but accepts a shorthand letter that can be used after a single dash. // StringP is like String, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringP(name, shorthand string, value string, usage string) *string { func (f *FlagSet) StringP(name, shorthand string, value string, usage string) *string {
p := new(string) p := new(string)
f.StringVarP(p, name, shorthand, value, usage) f.StringVarP(p, name, shorthand, value, usage)
@ -63,7 +74,7 @@ func String(name string, value string, usage string) *string {
return CommandLine.StringP(name, "", value, usage) return CommandLine.StringP(name, "", value, usage)
} }
// Like String, but accepts a shorthand letter that can be used after a single dash. // StringP is like String, but accepts a shorthand letter that can be used after a single dash.
func StringP(name, shorthand string, value string, usage string) *string { func StringP(name, shorthand string, value string, usage string) *string {
return CommandLine.StringP(name, shorthand, value, usage) return CommandLine.StringP(name, shorthand, value, usage)
} }

109
vendor/github.com/spf13/pflag/string_array.go generated vendored Normal file
View file

@ -0,0 +1,109 @@
package pflag
import (
"fmt"
)
var _ = fmt.Fprint
// -- stringArray Value
type stringArrayValue struct {
value *[]string
changed bool
}
func newStringArrayValue(val []string, p *[]string) *stringArrayValue {
ssv := new(stringArrayValue)
ssv.value = p
*ssv.value = val
return ssv
}
func (s *stringArrayValue) Set(val string) error {
if !s.changed {
*s.value = []string{val}
s.changed = true
} else {
*s.value = append(*s.value, val)
}
return nil
}
func (s *stringArrayValue) Type() string {
return "stringArray"
}
func (s *stringArrayValue) String() string {
str, _ := writeAsCSV(*s.value)
return "[" + str + "]"
}
func stringArrayConv(sval string) (interface{}, error) {
sval = sval[1 : len(sval)-1]
// An empty string would cause a array with one (empty) string
if len(sval) == 0 {
return []string{}, nil
}
return readAsCSV(sval)
}
// GetStringArray return the []string value of a flag with the given name
func (f *FlagSet) GetStringArray(name string) ([]string, error) {
val, err := f.getFlagType(name, "stringArray", stringArrayConv)
if err != nil {
return []string{}, err
}
return val.([]string), nil
}
// StringArrayVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the values of the multiple flags.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) {
f.VarP(newStringArrayValue(value, p), name, "", usage)
}
// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) {
f.VarP(newStringArrayValue(value, p), name, shorthand, usage)
}
// StringArrayVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the value of the flag.
// The value of each argument will not try to be separated by comma
func StringArrayVar(p *[]string, name string, value []string, usage string) {
CommandLine.VarP(newStringArrayValue(value, p), name, "", usage)
}
// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash.
func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) {
CommandLine.VarP(newStringArrayValue(value, p), name, shorthand, usage)
}
// StringArray defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string {
p := []string{}
f.StringArrayVarP(&p, name, "", value, usage)
return &p
}
// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage string) *[]string {
p := []string{}
f.StringArrayVarP(&p, name, shorthand, value, usage)
return &p
}
// StringArray defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func StringArray(name string, value []string, usage string) *[]string {
return CommandLine.StringArrayP(name, "", value, usage)
}
// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash.
func StringArrayP(name, shorthand string, value []string, usage string) *[]string {
return CommandLine.StringArrayP(name, shorthand, value, usage)
}

132
vendor/github.com/spf13/pflag/string_slice.go generated vendored Normal file
View file

@ -0,0 +1,132 @@
package pflag
import (
"bytes"
"encoding/csv"
"fmt"
"strings"
)
var _ = fmt.Fprint
// -- stringSlice Value
type stringSliceValue struct {
value *[]string
changed bool
}
func newStringSliceValue(val []string, p *[]string) *stringSliceValue {
ssv := new(stringSliceValue)
ssv.value = p
*ssv.value = val
return ssv
}
func readAsCSV(val string) ([]string, error) {
if val == "" {
return []string{}, nil
}
stringReader := strings.NewReader(val)
csvReader := csv.NewReader(stringReader)
return csvReader.Read()
}
func writeAsCSV(vals []string) (string, error) {
b := &bytes.Buffer{}
w := csv.NewWriter(b)
err := w.Write(vals)
if err != nil {
return "", err
}
w.Flush()
return strings.TrimSuffix(b.String(), fmt.Sprintln()), nil
}
func (s *stringSliceValue) Set(val string) error {
v, err := readAsCSV(val)
if err != nil {
return err
}
if !s.changed {
*s.value = v
} else {
*s.value = append(*s.value, v...)
}
s.changed = true
return nil
}
func (s *stringSliceValue) Type() string {
return "stringSlice"
}
func (s *stringSliceValue) String() string {
str, _ := writeAsCSV(*s.value)
return "[" + str + "]"
}
func stringSliceConv(sval string) (interface{}, error) {
sval = sval[1 : len(sval)-1]
// An empty string would cause a slice with one (empty) string
if len(sval) == 0 {
return []string{}, nil
}
return readAsCSV(sval)
}
// GetStringSlice return the []string value of a flag with the given name
func (f *FlagSet) GetStringSlice(name string) ([]string, error) {
val, err := f.getFlagType(name, "stringSlice", stringSliceConv)
if err != nil {
return []string{}, err
}
return val.([]string), nil
}
// StringSliceVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the value of the flag.
func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) {
f.VarP(newStringSliceValue(value, p), name, "", usage)
}
// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) {
f.VarP(newStringSliceValue(value, p), name, shorthand, usage)
}
// StringSliceVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the value of the flag.
func StringSliceVar(p *[]string, name string, value []string, usage string) {
CommandLine.VarP(newStringSliceValue(value, p), name, "", usage)
}
// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash.
func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) {
CommandLine.VarP(newStringSliceValue(value, p), name, shorthand, usage)
}
// StringSlice defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag.
func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string {
p := []string{}
f.StringSliceVarP(&p, name, "", value, usage)
return &p
}
// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage string) *[]string {
p := []string{}
f.StringSliceVarP(&p, name, shorthand, value, usage)
return &p
}
// StringSlice defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag.
func StringSlice(name string, value []string, usage string) *[]string {
return CommandLine.StringSliceP(name, "", value, usage)
}
// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash.
func StringSliceP(name, shorthand string, value []string, usage string) *[]string {
return CommandLine.StringSliceP(name, shorthand, value, usage)
}

View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- uint Value // -- uint Value
type uintValue uint type uintValue uint
@ -23,7 +20,24 @@ func (i *uintValue) Type() string {
return "uint" return "uint"
} }
func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) } func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) }
func uintConv(sval string) (interface{}, error) {
v, err := strconv.ParseUint(sval, 0, 0)
if err != nil {
return 0, err
}
return uint(v), nil
}
// GetUint return the uint value of a flag with the given name
func (f *FlagSet) GetUint(name string) (uint, error) {
val, err := f.getFlagType(name, "uint", uintConv)
if err != nil {
return 0, err
}
return val.(uint), nil
}
// UintVar defines a uint flag with specified name, default value, and usage string. // UintVar defines a uint flag with specified name, default value, and usage string.
// The argument p points to a uint variable in which to store the value of the flag. // The argument p points to a uint variable in which to store the value of the flag.
@ -31,7 +45,7 @@ func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) {
f.VarP(newUintValue(value, p), name, "", usage) f.VarP(newUintValue(value, p), name, "", usage)
} }
// Like UintVar, but accepts a shorthand letter that can be used after a single dash. // UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) UintVarP(p *uint, name, shorthand string, value uint, usage string) { func (f *FlagSet) UintVarP(p *uint, name, shorthand string, value uint, usage string) {
f.VarP(newUintValue(value, p), name, shorthand, usage) f.VarP(newUintValue(value, p), name, shorthand, usage)
} }
@ -42,7 +56,7 @@ func UintVar(p *uint, name string, value uint, usage string) {
CommandLine.VarP(newUintValue(value, p), name, "", usage) CommandLine.VarP(newUintValue(value, p), name, "", usage)
} }
// Like UintVar, but accepts a shorthand letter that can be used after a single dash. // UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash.
func UintVarP(p *uint, name, shorthand string, value uint, usage string) { func UintVarP(p *uint, name, shorthand string, value uint, usage string) {
CommandLine.VarP(newUintValue(value, p), name, shorthand, usage) CommandLine.VarP(newUintValue(value, p), name, shorthand, usage)
} }
@ -55,7 +69,7 @@ func (f *FlagSet) Uint(name string, value uint, usage string) *uint {
return p return p
} }
// Like Uint, but accepts a shorthand letter that can be used after a single dash. // UintP is like Uint, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) UintP(name, shorthand string, value uint, usage string) *uint { func (f *FlagSet) UintP(name, shorthand string, value uint, usage string) *uint {
p := new(uint) p := new(uint)
f.UintVarP(p, name, shorthand, value, usage) f.UintVarP(p, name, shorthand, value, usage)
@ -68,7 +82,7 @@ func Uint(name string, value uint, usage string) *uint {
return CommandLine.UintP(name, "", value, usage) return CommandLine.UintP(name, "", value, usage)
} }
// Like Uint, but accepts a shorthand letter that can be used after a single dash. // UintP is like Uint, but accepts a shorthand letter that can be used after a single dash.
func UintP(name, shorthand string, value uint, usage string) *uint { func UintP(name, shorthand string, value uint, usage string) *uint {
return CommandLine.UintP(name, shorthand, value, usage) return CommandLine.UintP(name, shorthand, value, usage)
} }

View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- uint16 value // -- uint16 value
type uint16Value uint16 type uint16Value uint16
@ -12,7 +9,7 @@ func newUint16Value(val uint16, p *uint16) *uint16Value {
*p = val *p = val
return (*uint16Value)(p) return (*uint16Value)(p)
} }
func (i *uint16Value) String() string { return fmt.Sprintf("%d", *i) }
func (i *uint16Value) Set(s string) error { func (i *uint16Value) Set(s string) error {
v, err := strconv.ParseUint(s, 0, 16) v, err := strconv.ParseUint(s, 0, 16)
*i = uint16Value(v) *i = uint16Value(v)
@ -23,13 +20,32 @@ func (i *uint16Value) Type() string {
return "uint16" return "uint16"
} }
func (i *uint16Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
func uint16Conv(sval string) (interface{}, error) {
v, err := strconv.ParseUint(sval, 0, 16)
if err != nil {
return 0, err
}
return uint16(v), nil
}
// GetUint16 return the uint16 value of a flag with the given name
func (f *FlagSet) GetUint16(name string) (uint16, error) {
val, err := f.getFlagType(name, "uint16", uint16Conv)
if err != nil {
return 0, err
}
return val.(uint16), nil
}
// Uint16Var defines a uint flag with specified name, default value, and usage string. // Uint16Var defines a uint flag with specified name, default value, and usage string.
// The argument p points to a uint variable in which to store the value of the flag. // The argument p points to a uint variable in which to store the value of the flag.
func (f *FlagSet) Uint16Var(p *uint16, name string, value uint16, usage string) { func (f *FlagSet) Uint16Var(p *uint16, name string, value uint16, usage string) {
f.VarP(newUint16Value(value, p), name, "", usage) f.VarP(newUint16Value(value, p), name, "", usage)
} }
// Like Uint16Var, but accepts a shorthand letter that can be used after a single dash. // Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { func (f *FlagSet) Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) {
f.VarP(newUint16Value(value, p), name, shorthand, usage) f.VarP(newUint16Value(value, p), name, shorthand, usage)
} }
@ -40,7 +56,7 @@ func Uint16Var(p *uint16, name string, value uint16, usage string) {
CommandLine.VarP(newUint16Value(value, p), name, "", usage) CommandLine.VarP(newUint16Value(value, p), name, "", usage)
} }
// Like Uint16Var, but accepts a shorthand letter that can be used after a single dash. // Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash.
func Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { func Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) {
CommandLine.VarP(newUint16Value(value, p), name, shorthand, usage) CommandLine.VarP(newUint16Value(value, p), name, shorthand, usage)
} }
@ -53,7 +69,7 @@ func (f *FlagSet) Uint16(name string, value uint16, usage string) *uint16 {
return p return p
} }
// Like Uint16, but accepts a shorthand letter that can be used after a single dash. // Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Uint16P(name, shorthand string, value uint16, usage string) *uint16 { func (f *FlagSet) Uint16P(name, shorthand string, value uint16, usage string) *uint16 {
p := new(uint16) p := new(uint16)
f.Uint16VarP(p, name, shorthand, value, usage) f.Uint16VarP(p, name, shorthand, value, usage)
@ -66,7 +82,7 @@ func Uint16(name string, value uint16, usage string) *uint16 {
return CommandLine.Uint16P(name, "", value, usage) return CommandLine.Uint16P(name, "", value, usage)
} }
// Like Uint16, but accepts a shorthand letter that can be used after a single dash. // Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash.
func Uint16P(name, shorthand string, value uint16, usage string) *uint16 { func Uint16P(name, shorthand string, value uint16, usage string) *uint16 {
return CommandLine.Uint16P(name, shorthand, value, usage) return CommandLine.Uint16P(name, shorthand, value, usage)
} }

View file

@ -1,18 +1,15 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- uint16 value // -- uint32 value
type uint32Value uint32 type uint32Value uint32
func newUint32Value(val uint32, p *uint32) *uint32Value { func newUint32Value(val uint32, p *uint32) *uint32Value {
*p = val *p = val
return (*uint32Value)(p) return (*uint32Value)(p)
} }
func (i *uint32Value) String() string { return fmt.Sprintf("%d", *i) }
func (i *uint32Value) Set(s string) error { func (i *uint32Value) Set(s string) error {
v, err := strconv.ParseUint(s, 0, 32) v, err := strconv.ParseUint(s, 0, 32)
*i = uint32Value(v) *i = uint32Value(v)
@ -23,13 +20,32 @@ func (i *uint32Value) Type() string {
return "uint32" return "uint32"
} }
func (i *uint32Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
func uint32Conv(sval string) (interface{}, error) {
v, err := strconv.ParseUint(sval, 0, 32)
if err != nil {
return 0, err
}
return uint32(v), nil
}
// GetUint32 return the uint32 value of a flag with the given name
func (f *FlagSet) GetUint32(name string) (uint32, error) {
val, err := f.getFlagType(name, "uint32", uint32Conv)
if err != nil {
return 0, err
}
return val.(uint32), nil
}
// Uint32Var defines a uint32 flag with specified name, default value, and usage string. // Uint32Var defines a uint32 flag with specified name, default value, and usage string.
// The argument p points to a uint32 variable in which to store the value of the flag. // The argument p points to a uint32 variable in which to store the value of the flag.
func (f *FlagSet) Uint32Var(p *uint32, name string, value uint32, usage string) { func (f *FlagSet) Uint32Var(p *uint32, name string, value uint32, usage string) {
f.VarP(newUint32Value(value, p), name, "", usage) f.VarP(newUint32Value(value, p), name, "", usage)
} }
// Like Uint32Var, but accepts a shorthand letter that can be used after a single dash. // Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { func (f *FlagSet) Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) {
f.VarP(newUint32Value(value, p), name, shorthand, usage) f.VarP(newUint32Value(value, p), name, shorthand, usage)
} }
@ -40,7 +56,7 @@ func Uint32Var(p *uint32, name string, value uint32, usage string) {
CommandLine.VarP(newUint32Value(value, p), name, "", usage) CommandLine.VarP(newUint32Value(value, p), name, "", usage)
} }
// Like Uint32Var, but accepts a shorthand letter that can be used after a single dash. // Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash.
func Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { func Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) {
CommandLine.VarP(newUint32Value(value, p), name, shorthand, usage) CommandLine.VarP(newUint32Value(value, p), name, shorthand, usage)
} }
@ -53,7 +69,7 @@ func (f *FlagSet) Uint32(name string, value uint32, usage string) *uint32 {
return p return p
} }
// Like Uint32, but accepts a shorthand letter that can be used after a single dash. // Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Uint32P(name, shorthand string, value uint32, usage string) *uint32 { func (f *FlagSet) Uint32P(name, shorthand string, value uint32, usage string) *uint32 {
p := new(uint32) p := new(uint32)
f.Uint32VarP(p, name, shorthand, value, usage) f.Uint32VarP(p, name, shorthand, value, usage)
@ -66,7 +82,7 @@ func Uint32(name string, value uint32, usage string) *uint32 {
return CommandLine.Uint32P(name, "", value, usage) return CommandLine.Uint32P(name, "", value, usage)
} }
// Like Uint32, but accepts a shorthand letter that can be used after a single dash. // Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash.
func Uint32P(name, shorthand string, value uint32, usage string) *uint32 { func Uint32P(name, shorthand string, value uint32, usage string) *uint32 {
return CommandLine.Uint32P(name, shorthand, value, usage) return CommandLine.Uint32P(name, shorthand, value, usage)
} }

View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- uint64 Value // -- uint64 Value
type uint64Value uint64 type uint64Value uint64
@ -23,7 +20,24 @@ func (i *uint64Value) Type() string {
return "uint64" return "uint64"
} }
func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) } func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
func uint64Conv(sval string) (interface{}, error) {
v, err := strconv.ParseUint(sval, 0, 64)
if err != nil {
return 0, err
}
return uint64(v), nil
}
// GetUint64 return the uint64 value of a flag with the given name
func (f *FlagSet) GetUint64(name string) (uint64, error) {
val, err := f.getFlagType(name, "uint64", uint64Conv)
if err != nil {
return 0, err
}
return val.(uint64), nil
}
// Uint64Var defines a uint64 flag with specified name, default value, and usage string. // Uint64Var defines a uint64 flag with specified name, default value, and usage string.
// The argument p points to a uint64 variable in which to store the value of the flag. // The argument p points to a uint64 variable in which to store the value of the flag.
@ -31,7 +45,7 @@ func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string)
f.VarP(newUint64Value(value, p), name, "", usage) f.VarP(newUint64Value(value, p), name, "", usage)
} }
// Like Uint64Var, but accepts a shorthand letter that can be used after a single dash. // Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { func (f *FlagSet) Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) {
f.VarP(newUint64Value(value, p), name, shorthand, usage) f.VarP(newUint64Value(value, p), name, shorthand, usage)
} }
@ -42,7 +56,7 @@ func Uint64Var(p *uint64, name string, value uint64, usage string) {
CommandLine.VarP(newUint64Value(value, p), name, "", usage) CommandLine.VarP(newUint64Value(value, p), name, "", usage)
} }
// Like Uint64Var, but accepts a shorthand letter that can be used after a single dash. // Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash.
func Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { func Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) {
CommandLine.VarP(newUint64Value(value, p), name, shorthand, usage) CommandLine.VarP(newUint64Value(value, p), name, shorthand, usage)
} }
@ -55,7 +69,7 @@ func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 {
return p return p
} }
// Like Uint64, but accepts a shorthand letter that can be used after a single dash. // Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Uint64P(name, shorthand string, value uint64, usage string) *uint64 { func (f *FlagSet) Uint64P(name, shorthand string, value uint64, usage string) *uint64 {
p := new(uint64) p := new(uint64)
f.Uint64VarP(p, name, shorthand, value, usage) f.Uint64VarP(p, name, shorthand, value, usage)
@ -68,7 +82,7 @@ func Uint64(name string, value uint64, usage string) *uint64 {
return CommandLine.Uint64P(name, "", value, usage) return CommandLine.Uint64P(name, "", value, usage)
} }
// Like Uint64, but accepts a shorthand letter that can be used after a single dash. // Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash.
func Uint64P(name, shorthand string, value uint64, usage string) *uint64 { func Uint64P(name, shorthand string, value uint64, usage string) *uint64 {
return CommandLine.Uint64P(name, shorthand, value, usage) return CommandLine.Uint64P(name, shorthand, value, usage)
} }

View file

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- uint8 Value // -- uint8 Value
type uint8Value uint8 type uint8Value uint8
@ -23,7 +20,24 @@ func (i *uint8Value) Type() string {
return "uint8" return "uint8"
} }
func (i *uint8Value) String() string { return fmt.Sprintf("%v", *i) } func (i *uint8Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
func uint8Conv(sval string) (interface{}, error) {
v, err := strconv.ParseUint(sval, 0, 8)
if err != nil {
return 0, err
}
return uint8(v), nil
}
// GetUint8 return the uint8 value of a flag with the given name
func (f *FlagSet) GetUint8(name string) (uint8, error) {
val, err := f.getFlagType(name, "uint8", uint8Conv)
if err != nil {
return 0, err
}
return val.(uint8), nil
}
// Uint8Var defines a uint8 flag with specified name, default value, and usage string. // Uint8Var defines a uint8 flag with specified name, default value, and usage string.
// The argument p points to a uint8 variable in which to store the value of the flag. // The argument p points to a uint8 variable in which to store the value of the flag.
@ -31,7 +45,7 @@ func (f *FlagSet) Uint8Var(p *uint8, name string, value uint8, usage string) {
f.VarP(newUint8Value(value, p), name, "", usage) f.VarP(newUint8Value(value, p), name, "", usage)
} }
// Like Uint8Var, but accepts a shorthand letter that can be used after a single dash. // Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { func (f *FlagSet) Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) {
f.VarP(newUint8Value(value, p), name, shorthand, usage) f.VarP(newUint8Value(value, p), name, shorthand, usage)
} }
@ -42,7 +56,7 @@ func Uint8Var(p *uint8, name string, value uint8, usage string) {
CommandLine.VarP(newUint8Value(value, p), name, "", usage) CommandLine.VarP(newUint8Value(value, p), name, "", usage)
} }
// Like Uint8Var, but accepts a shorthand letter that can be used after a single dash. // Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash.
func Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { func Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) {
CommandLine.VarP(newUint8Value(value, p), name, shorthand, usage) CommandLine.VarP(newUint8Value(value, p), name, shorthand, usage)
} }
@ -55,7 +69,7 @@ func (f *FlagSet) Uint8(name string, value uint8, usage string) *uint8 {
return p return p
} }
// Like Uint8, but accepts a shorthand letter that can be used after a single dash. // Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Uint8P(name, shorthand string, value uint8, usage string) *uint8 { func (f *FlagSet) Uint8P(name, shorthand string, value uint8, usage string) *uint8 {
p := new(uint8) p := new(uint8)
f.Uint8VarP(p, name, shorthand, value, usage) f.Uint8VarP(p, name, shorthand, value, usage)
@ -68,7 +82,7 @@ func Uint8(name string, value uint8, usage string) *uint8 {
return CommandLine.Uint8P(name, "", value, usage) return CommandLine.Uint8P(name, "", value, usage)
} }
// Like Uint8, but accepts a shorthand letter that can be used after a single dash. // Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash.
func Uint8P(name, shorthand string, value uint8, usage string) *uint8 { func Uint8P(name, shorthand string, value uint8, usage string) *uint8 {
return CommandLine.Uint8P(name, shorthand, value, usage) return CommandLine.Uint8P(name, shorthand, value, usage)
} }

View file

@ -0,0 +1,525 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package timeseries implements a time series structure for stats collection.
package timeseries // import "golang.org/x/net/internal/timeseries"
import (
"fmt"
"log"
"time"
)
const (
timeSeriesNumBuckets = 64
minuteHourSeriesNumBuckets = 60
)
var timeSeriesResolutions = []time.Duration{
1 * time.Second,
10 * time.Second,
1 * time.Minute,
10 * time.Minute,
1 * time.Hour,
6 * time.Hour,
24 * time.Hour, // 1 day
7 * 24 * time.Hour, // 1 week
4 * 7 * 24 * time.Hour, // 4 weeks
16 * 7 * 24 * time.Hour, // 16 weeks
}
var minuteHourSeriesResolutions = []time.Duration{
1 * time.Second,
1 * time.Minute,
}
// An Observable is a kind of data that can be aggregated in a time series.
type Observable interface {
Multiply(ratio float64) // Multiplies the data in self by a given ratio
Add(other Observable) // Adds the data from a different observation to self
Clear() // Clears the observation so it can be reused.
CopyFrom(other Observable) // Copies the contents of a given observation to self
}
// Float attaches the methods of Observable to a float64.
type Float float64
// NewFloat returns a Float.
func NewFloat() Observable {
f := Float(0)
return &f
}
// String returns the float as a string.
func (f *Float) String() string { return fmt.Sprintf("%g", f.Value()) }
// Value returns the float's value.
func (f *Float) Value() float64 { return float64(*f) }
func (f *Float) Multiply(ratio float64) { *f *= Float(ratio) }
func (f *Float) Add(other Observable) {
o := other.(*Float)
*f += *o
}
func (f *Float) Clear() { *f = 0 }
func (f *Float) CopyFrom(other Observable) {
o := other.(*Float)
*f = *o
}
// A Clock tells the current time.
type Clock interface {
Time() time.Time
}
type defaultClock int
var defaultClockInstance defaultClock
func (defaultClock) Time() time.Time { return time.Now() }
// Information kept per level. Each level consists of a circular list of
// observations. The start of the level may be derived from end and the
// len(buckets) * sizeInMillis.
type tsLevel struct {
oldest int // index to oldest bucketed Observable
newest int // index to newest bucketed Observable
end time.Time // end timestamp for this level
size time.Duration // duration of the bucketed Observable
buckets []Observable // collections of observations
provider func() Observable // used for creating new Observable
}
func (l *tsLevel) Clear() {
l.oldest = 0
l.newest = len(l.buckets) - 1
l.end = time.Time{}
for i := range l.buckets {
if l.buckets[i] != nil {
l.buckets[i].Clear()
l.buckets[i] = nil
}
}
}
func (l *tsLevel) InitLevel(size time.Duration, numBuckets int, f func() Observable) {
l.size = size
l.provider = f
l.buckets = make([]Observable, numBuckets)
}
// Keeps a sequence of levels. Each level is responsible for storing data at
// a given resolution. For example, the first level stores data at a one
// minute resolution while the second level stores data at a one hour
// resolution.
// Each level is represented by a sequence of buckets. Each bucket spans an
// interval equal to the resolution of the level. New observations are added
// to the last bucket.
type timeSeries struct {
provider func() Observable // make more Observable
numBuckets int // number of buckets in each level
levels []*tsLevel // levels of bucketed Observable
lastAdd time.Time // time of last Observable tracked
total Observable // convenient aggregation of all Observable
clock Clock // Clock for getting current time
pending Observable // observations not yet bucketed
pendingTime time.Time // what time are we keeping in pending
dirty bool // if there are pending observations
}
// init initializes a level according to the supplied criteria.
func (ts *timeSeries) init(resolutions []time.Duration, f func() Observable, numBuckets int, clock Clock) {
ts.provider = f
ts.numBuckets = numBuckets
ts.clock = clock
ts.levels = make([]*tsLevel, len(resolutions))
for i := range resolutions {
if i > 0 && resolutions[i-1] >= resolutions[i] {
log.Print("timeseries: resolutions must be monotonically increasing")
break
}
newLevel := new(tsLevel)
newLevel.InitLevel(resolutions[i], ts.numBuckets, ts.provider)
ts.levels[i] = newLevel
}
ts.Clear()
}
// Clear removes all observations from the time series.
func (ts *timeSeries) Clear() {
ts.lastAdd = time.Time{}
ts.total = ts.resetObservation(ts.total)
ts.pending = ts.resetObservation(ts.pending)
ts.pendingTime = time.Time{}
ts.dirty = false
for i := range ts.levels {
ts.levels[i].Clear()
}
}
// Add records an observation at the current time.
func (ts *timeSeries) Add(observation Observable) {
ts.AddWithTime(observation, ts.clock.Time())
}
// AddWithTime records an observation at the specified time.
func (ts *timeSeries) AddWithTime(observation Observable, t time.Time) {
smallBucketDuration := ts.levels[0].size
if t.After(ts.lastAdd) {
ts.lastAdd = t
}
if t.After(ts.pendingTime) {
ts.advance(t)
ts.mergePendingUpdates()
ts.pendingTime = ts.levels[0].end
ts.pending.CopyFrom(observation)
ts.dirty = true
} else if t.After(ts.pendingTime.Add(-1 * smallBucketDuration)) {
// The observation is close enough to go into the pending bucket.
// This compensates for clock skewing and small scheduling delays
// by letting the update stay in the fast path.
ts.pending.Add(observation)
ts.dirty = true
} else {
ts.mergeValue(observation, t)
}
}
// mergeValue inserts the observation at the specified time in the past into all levels.
func (ts *timeSeries) mergeValue(observation Observable, t time.Time) {
for _, level := range ts.levels {
index := (ts.numBuckets - 1) - int(level.end.Sub(t)/level.size)
if 0 <= index && index < ts.numBuckets {
bucketNumber := (level.oldest + index) % ts.numBuckets
if level.buckets[bucketNumber] == nil {
level.buckets[bucketNumber] = level.provider()
}
level.buckets[bucketNumber].Add(observation)
}
}
ts.total.Add(observation)
}
// mergePendingUpdates applies the pending updates into all levels.
func (ts *timeSeries) mergePendingUpdates() {
if ts.dirty {
ts.mergeValue(ts.pending, ts.pendingTime)
ts.pending = ts.resetObservation(ts.pending)
ts.dirty = false
}
}
// advance cycles the buckets at each level until the latest bucket in
// each level can hold the time specified.
func (ts *timeSeries) advance(t time.Time) {
if !t.After(ts.levels[0].end) {
return
}
for i := 0; i < len(ts.levels); i++ {
level := ts.levels[i]
if !level.end.Before(t) {
break
}
// If the time is sufficiently far, just clear the level and advance
// directly.
if !t.Before(level.end.Add(level.size * time.Duration(ts.numBuckets))) {
for _, b := range level.buckets {
ts.resetObservation(b)
}
level.end = time.Unix(0, (t.UnixNano()/level.size.Nanoseconds())*level.size.Nanoseconds())
}
for t.After(level.end) {
level.end = level.end.Add(level.size)
level.newest = level.oldest
level.oldest = (level.oldest + 1) % ts.numBuckets
ts.resetObservation(level.buckets[level.newest])
}
t = level.end
}
}
// Latest returns the sum of the num latest buckets from the level.
func (ts *timeSeries) Latest(level, num int) Observable {
now := ts.clock.Time()
if ts.levels[0].end.Before(now) {
ts.advance(now)
}
ts.mergePendingUpdates()
result := ts.provider()
l := ts.levels[level]
index := l.newest
for i := 0; i < num; i++ {
if l.buckets[index] != nil {
result.Add(l.buckets[index])
}
if index == 0 {
index = ts.numBuckets
}
index--
}
return result
}
// LatestBuckets returns a copy of the num latest buckets from level.
func (ts *timeSeries) LatestBuckets(level, num int) []Observable {
if level < 0 || level > len(ts.levels) {
log.Print("timeseries: bad level argument: ", level)
return nil
}
if num < 0 || num >= ts.numBuckets {
log.Print("timeseries: bad num argument: ", num)
return nil
}
results := make([]Observable, num)
now := ts.clock.Time()
if ts.levels[0].end.Before(now) {
ts.advance(now)
}
ts.mergePendingUpdates()
l := ts.levels[level]
index := l.newest
for i := 0; i < num; i++ {
result := ts.provider()
results[i] = result
if l.buckets[index] != nil {
result.CopyFrom(l.buckets[index])
}
if index == 0 {
index = ts.numBuckets
}
index -= 1
}
return results
}
// ScaleBy updates observations by scaling by factor.
func (ts *timeSeries) ScaleBy(factor float64) {
for _, l := range ts.levels {
for i := 0; i < ts.numBuckets; i++ {
l.buckets[i].Multiply(factor)
}
}
ts.total.Multiply(factor)
ts.pending.Multiply(factor)
}
// Range returns the sum of observations added over the specified time range.
// If start or finish times don't fall on bucket boundaries of the same
// level, then return values are approximate answers.
func (ts *timeSeries) Range(start, finish time.Time) Observable {
return ts.ComputeRange(start, finish, 1)[0]
}
// Recent returns the sum of observations from the last delta.
func (ts *timeSeries) Recent(delta time.Duration) Observable {
now := ts.clock.Time()
return ts.Range(now.Add(-delta), now)
}
// Total returns the total of all observations.
func (ts *timeSeries) Total() Observable {
ts.mergePendingUpdates()
return ts.total
}
// ComputeRange computes a specified number of values into a slice using
// the observations recorded over the specified time period. The return
// values are approximate if the start or finish times don't fall on the
// bucket boundaries at the same level or if the number of buckets spanning
// the range is not an integral multiple of num.
func (ts *timeSeries) ComputeRange(start, finish time.Time, num int) []Observable {
if start.After(finish) {
log.Printf("timeseries: start > finish, %v>%v", start, finish)
return nil
}
if num < 0 {
log.Printf("timeseries: num < 0, %v", num)
return nil
}
results := make([]Observable, num)
for _, l := range ts.levels {
if !start.Before(l.end.Add(-l.size * time.Duration(ts.numBuckets))) {
ts.extract(l, start, finish, num, results)
return results
}
}
// Failed to find a level that covers the desired range. So just
// extract from the last level, even if it doesn't cover the entire
// desired range.
ts.extract(ts.levels[len(ts.levels)-1], start, finish, num, results)
return results
}
// RecentList returns the specified number of values in slice over the most
// recent time period of the specified range.
func (ts *timeSeries) RecentList(delta time.Duration, num int) []Observable {
if delta < 0 {
return nil
}
now := ts.clock.Time()
return ts.ComputeRange(now.Add(-delta), now, num)
}
// extract returns a slice of specified number of observations from a given
// level over a given range.
func (ts *timeSeries) extract(l *tsLevel, start, finish time.Time, num int, results []Observable) {
ts.mergePendingUpdates()
srcInterval := l.size
dstInterval := finish.Sub(start) / time.Duration(num)
dstStart := start
srcStart := l.end.Add(-srcInterval * time.Duration(ts.numBuckets))
srcIndex := 0
// Where should scanning start?
if dstStart.After(srcStart) {
advance := dstStart.Sub(srcStart) / srcInterval
srcIndex += int(advance)
srcStart = srcStart.Add(advance * srcInterval)
}
// The i'th value is computed as show below.
// interval = (finish/start)/num
// i'th value = sum of observation in range
// [ start + i * interval,
// start + (i + 1) * interval )
for i := 0; i < num; i++ {
results[i] = ts.resetObservation(results[i])
dstEnd := dstStart.Add(dstInterval)
for srcIndex < ts.numBuckets && srcStart.Before(dstEnd) {
srcEnd := srcStart.Add(srcInterval)
if srcEnd.After(ts.lastAdd) {
srcEnd = ts.lastAdd
}
if !srcEnd.Before(dstStart) {
srcValue := l.buckets[(srcIndex+l.oldest)%ts.numBuckets]
if !srcStart.Before(dstStart) && !srcEnd.After(dstEnd) {
// dst completely contains src.
if srcValue != nil {
results[i].Add(srcValue)
}
} else {
// dst partially overlaps src.
overlapStart := maxTime(srcStart, dstStart)
overlapEnd := minTime(srcEnd, dstEnd)
base := srcEnd.Sub(srcStart)
fraction := overlapEnd.Sub(overlapStart).Seconds() / base.Seconds()
used := ts.provider()
if srcValue != nil {
used.CopyFrom(srcValue)
}
used.Multiply(fraction)
results[i].Add(used)
}
if srcEnd.After(dstEnd) {
break
}
}
srcIndex++
srcStart = srcStart.Add(srcInterval)
}
dstStart = dstStart.Add(dstInterval)
}
}
// resetObservation clears the content so the struct may be reused.
func (ts *timeSeries) resetObservation(observation Observable) Observable {
if observation == nil {
observation = ts.provider()
} else {
observation.Clear()
}
return observation
}
// TimeSeries tracks data at granularities from 1 second to 16 weeks.
type TimeSeries struct {
timeSeries
}
// NewTimeSeries creates a new TimeSeries using the function provided for creating new Observable.
func NewTimeSeries(f func() Observable) *TimeSeries {
return NewTimeSeriesWithClock(f, defaultClockInstance)
}
// NewTimeSeriesWithClock creates a new TimeSeries using the function provided for creating new Observable and the clock for
// assigning timestamps.
func NewTimeSeriesWithClock(f func() Observable, clock Clock) *TimeSeries {
ts := new(TimeSeries)
ts.timeSeries.init(timeSeriesResolutions, f, timeSeriesNumBuckets, clock)
return ts
}
// MinuteHourSeries tracks data at granularities of 1 minute and 1 hour.
type MinuteHourSeries struct {
timeSeries
}
// NewMinuteHourSeries creates a new MinuteHourSeries using the function provided for creating new Observable.
func NewMinuteHourSeries(f func() Observable) *MinuteHourSeries {
return NewMinuteHourSeriesWithClock(f, defaultClockInstance)
}
// NewMinuteHourSeriesWithClock creates a new MinuteHourSeries using the function provided for creating new Observable and the clock for
// assigning timestamps.
func NewMinuteHourSeriesWithClock(f func() Observable, clock Clock) *MinuteHourSeries {
ts := new(MinuteHourSeries)
ts.timeSeries.init(minuteHourSeriesResolutions, f,
minuteHourSeriesNumBuckets, clock)
return ts
}
func (ts *MinuteHourSeries) Minute() Observable {
return ts.timeSeries.Latest(0, 60)
}
func (ts *MinuteHourSeries) Hour() Observable {
return ts.timeSeries.Latest(1, 60)
}
func minTime(a, b time.Time) time.Time {
if a.Before(b) {
return a
}
return b
}
func maxTime(a, b time.Time) time.Time {
if a.After(b) {
return a
}
return b
}

524
vendor/golang.org/x/net/trace/events.go generated vendored Normal file
View file

@ -0,0 +1,524 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package trace
import (
"bytes"
"fmt"
"html/template"
"io"
"log"
"net/http"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"sync/atomic"
"text/tabwriter"
"time"
)
var eventsTmpl = template.Must(template.New("events").Funcs(template.FuncMap{
"elapsed": elapsed,
"trimSpace": strings.TrimSpace,
}).Parse(eventsHTML))
const maxEventsPerLog = 100
type bucket struct {
MaxErrAge time.Duration
String string
}
var buckets = []bucket{
{0, "total"},
{10 * time.Second, "errs<10s"},
{1 * time.Minute, "errs<1m"},
{10 * time.Minute, "errs<10m"},
{1 * time.Hour, "errs<1h"},
{10 * time.Hour, "errs<10h"},
{24000 * time.Hour, "errors"},
}
// RenderEvents renders the HTML page typically served at /debug/events.
// It does not do any auth checking; see AuthRequest for the default auth check
// used by the handler registered on http.DefaultServeMux.
// req may be nil.
func RenderEvents(w http.ResponseWriter, req *http.Request, sensitive bool) {
now := time.Now()
data := &struct {
Families []string // family names
Buckets []bucket
Counts [][]int // eventLog count per family/bucket
// Set when a bucket has been selected.
Family string
Bucket int
EventLogs eventLogs
Expanded bool
}{
Buckets: buckets,
}
data.Families = make([]string, 0, len(families))
famMu.RLock()
for name := range families {
data.Families = append(data.Families, name)
}
famMu.RUnlock()
sort.Strings(data.Families)
// Count the number of eventLogs in each family for each error age.
data.Counts = make([][]int, len(data.Families))
for i, name := range data.Families {
// TODO(sameer): move this loop under the family lock.
f := getEventFamily(name)
data.Counts[i] = make([]int, len(data.Buckets))
for j, b := range data.Buckets {
data.Counts[i][j] = f.Count(now, b.MaxErrAge)
}
}
if req != nil {
var ok bool
data.Family, data.Bucket, ok = parseEventsArgs(req)
if !ok {
// No-op
} else {
data.EventLogs = getEventFamily(data.Family).Copy(now, buckets[data.Bucket].MaxErrAge)
}
if data.EventLogs != nil {
defer data.EventLogs.Free()
sort.Sort(data.EventLogs)
}
if exp, err := strconv.ParseBool(req.FormValue("exp")); err == nil {
data.Expanded = exp
}
}
famMu.RLock()
defer famMu.RUnlock()
if err := eventsTmpl.Execute(w, data); err != nil {
log.Printf("net/trace: Failed executing template: %v", err)
}
}
func parseEventsArgs(req *http.Request) (fam string, b int, ok bool) {
fam, bStr := req.FormValue("fam"), req.FormValue("b")
if fam == "" || bStr == "" {
return "", 0, false
}
b, err := strconv.Atoi(bStr)
if err != nil || b < 0 || b >= len(buckets) {
return "", 0, false
}
return fam, b, true
}
// An EventLog provides a log of events associated with a specific object.
type EventLog interface {
// Printf formats its arguments with fmt.Sprintf and adds the
// result to the event log.
Printf(format string, a ...interface{})
// Errorf is like Printf, but it marks this event as an error.
Errorf(format string, a ...interface{})
// Finish declares that this event log is complete.
// The event log should not be used after calling this method.
Finish()
}
// NewEventLog returns a new EventLog with the specified family name
// and title.
func NewEventLog(family, title string) EventLog {
el := newEventLog()
el.ref()
el.Family, el.Title = family, title
el.Start = time.Now()
el.events = make([]logEntry, 0, maxEventsPerLog)
el.stack = make([]uintptr, 32)
n := runtime.Callers(2, el.stack)
el.stack = el.stack[:n]
getEventFamily(family).add(el)
return el
}
func (el *eventLog) Finish() {
getEventFamily(el.Family).remove(el)
el.unref() // matches ref in New
}
var (
famMu sync.RWMutex
families = make(map[string]*eventFamily) // family name => family
)
func getEventFamily(fam string) *eventFamily {
famMu.Lock()
defer famMu.Unlock()
f := families[fam]
if f == nil {
f = &eventFamily{}
families[fam] = f
}
return f
}
type eventFamily struct {
mu sync.RWMutex
eventLogs eventLogs
}
func (f *eventFamily) add(el *eventLog) {
f.mu.Lock()
f.eventLogs = append(f.eventLogs, el)
f.mu.Unlock()
}
func (f *eventFamily) remove(el *eventLog) {
f.mu.Lock()
defer f.mu.Unlock()
for i, el0 := range f.eventLogs {
if el == el0 {
copy(f.eventLogs[i:], f.eventLogs[i+1:])
f.eventLogs = f.eventLogs[:len(f.eventLogs)-1]
return
}
}
}
func (f *eventFamily) Count(now time.Time, maxErrAge time.Duration) (n int) {
f.mu.RLock()
defer f.mu.RUnlock()
for _, el := range f.eventLogs {
if el.hasRecentError(now, maxErrAge) {
n++
}
}
return
}
func (f *eventFamily) Copy(now time.Time, maxErrAge time.Duration) (els eventLogs) {
f.mu.RLock()
defer f.mu.RUnlock()
els = make(eventLogs, 0, len(f.eventLogs))
for _, el := range f.eventLogs {
if el.hasRecentError(now, maxErrAge) {
el.ref()
els = append(els, el)
}
}
return
}
type eventLogs []*eventLog
// Free calls unref on each element of the list.
func (els eventLogs) Free() {
for _, el := range els {
el.unref()
}
}
// eventLogs may be sorted in reverse chronological order.
func (els eventLogs) Len() int { return len(els) }
func (els eventLogs) Less(i, j int) bool { return els[i].Start.After(els[j].Start) }
func (els eventLogs) Swap(i, j int) { els[i], els[j] = els[j], els[i] }
// A logEntry is a timestamped log entry in an event log.
type logEntry struct {
When time.Time
Elapsed time.Duration // since previous event in log
NewDay bool // whether this event is on a different day to the previous event
What string
IsErr bool
}
// WhenString returns a string representation of the elapsed time of the event.
// It will include the date if midnight was crossed.
func (e logEntry) WhenString() string {
if e.NewDay {
return e.When.Format("2006/01/02 15:04:05.000000")
}
return e.When.Format("15:04:05.000000")
}
// An eventLog represents an active event log.
type eventLog struct {
// Family is the top-level grouping of event logs to which this belongs.
Family string
// Title is the title of this event log.
Title string
// Timing information.
Start time.Time
// Call stack where this event log was created.
stack []uintptr
// Append-only sequence of events.
//
// TODO(sameer): change this to a ring buffer to avoid the array copy
// when we hit maxEventsPerLog.
mu sync.RWMutex
events []logEntry
LastErrorTime time.Time
discarded int
refs int32 // how many buckets this is in
}
func (el *eventLog) reset() {
// Clear all but the mutex. Mutexes may not be copied, even when unlocked.
el.Family = ""
el.Title = ""
el.Start = time.Time{}
el.stack = nil
el.events = nil
el.LastErrorTime = time.Time{}
el.discarded = 0
el.refs = 0
}
func (el *eventLog) hasRecentError(now time.Time, maxErrAge time.Duration) bool {
if maxErrAge == 0 {
return true
}
el.mu.RLock()
defer el.mu.RUnlock()
return now.Sub(el.LastErrorTime) < maxErrAge
}
// delta returns the elapsed time since the last event or the log start,
// and whether it spans midnight.
// L >= el.mu
func (el *eventLog) delta(t time.Time) (time.Duration, bool) {
if len(el.events) == 0 {
return t.Sub(el.Start), false
}
prev := el.events[len(el.events)-1].When
return t.Sub(prev), prev.Day() != t.Day()
}
func (el *eventLog) Printf(format string, a ...interface{}) {
el.printf(false, format, a...)
}
func (el *eventLog) Errorf(format string, a ...interface{}) {
el.printf(true, format, a...)
}
func (el *eventLog) printf(isErr bool, format string, a ...interface{}) {
e := logEntry{When: time.Now(), IsErr: isErr, What: fmt.Sprintf(format, a...)}
el.mu.Lock()
e.Elapsed, e.NewDay = el.delta(e.When)
if len(el.events) < maxEventsPerLog {
el.events = append(el.events, e)
} else {
// Discard the oldest event.
if el.discarded == 0 {
// el.discarded starts at two to count for the event it
// is replacing, plus the next one that we are about to
// drop.
el.discarded = 2
} else {
el.discarded++
}
// TODO(sameer): if this causes allocations on a critical path,
// change eventLog.What to be a fmt.Stringer, as in trace.go.
el.events[0].What = fmt.Sprintf("(%d events discarded)", el.discarded)
// The timestamp of the discarded meta-event should be
// the time of the last event it is representing.
el.events[0].When = el.events[1].When
copy(el.events[1:], el.events[2:])
el.events[maxEventsPerLog-1] = e
}
if e.IsErr {
el.LastErrorTime = e.When
}
el.mu.Unlock()
}
func (el *eventLog) ref() {
atomic.AddInt32(&el.refs, 1)
}
func (el *eventLog) unref() {
if atomic.AddInt32(&el.refs, -1) == 0 {
freeEventLog(el)
}
}
func (el *eventLog) When() string {
return el.Start.Format("2006/01/02 15:04:05.000000")
}
func (el *eventLog) ElapsedTime() string {
elapsed := time.Since(el.Start)
return fmt.Sprintf("%.6f", elapsed.Seconds())
}
func (el *eventLog) Stack() string {
buf := new(bytes.Buffer)
tw := tabwriter.NewWriter(buf, 1, 8, 1, '\t', 0)
printStackRecord(tw, el.stack)
tw.Flush()
return buf.String()
}
// printStackRecord prints the function + source line information
// for a single stack trace.
// Adapted from runtime/pprof/pprof.go.
func printStackRecord(w io.Writer, stk []uintptr) {
for _, pc := range stk {
f := runtime.FuncForPC(pc)
if f == nil {
continue
}
file, line := f.FileLine(pc)
name := f.Name()
// Hide runtime.goexit and any runtime functions at the beginning.
if strings.HasPrefix(name, "runtime.") {
continue
}
fmt.Fprintf(w, "# %s\t%s:%d\n", name, file, line)
}
}
func (el *eventLog) Events() []logEntry {
el.mu.RLock()
defer el.mu.RUnlock()
return el.events
}
// freeEventLogs is a freelist of *eventLog
var freeEventLogs = make(chan *eventLog, 1000)
// newEventLog returns a event log ready to use.
func newEventLog() *eventLog {
select {
case el := <-freeEventLogs:
return el
default:
return new(eventLog)
}
}
// freeEventLog adds el to freeEventLogs if there's room.
// This is non-blocking.
func freeEventLog(el *eventLog) {
el.reset()
select {
case freeEventLogs <- el:
default:
}
}
const eventsHTML = `
<html>
<head>
<title>events</title>
</head>
<style type="text/css">
body {
font-family: sans-serif;
}
table#req-status td.family {
padding-right: 2em;
}
table#req-status td.active {
padding-right: 1em;
}
table#req-status td.empty {
color: #aaa;
}
table#reqs {
margin-top: 1em;
}
table#reqs tr.first {
{{if $.Expanded}}font-weight: bold;{{end}}
}
table#reqs td {
font-family: monospace;
}
table#reqs td.when {
text-align: right;
white-space: nowrap;
}
table#reqs td.elapsed {
padding: 0 0.5em;
text-align: right;
white-space: pre;
width: 10em;
}
address {
font-size: smaller;
margin-top: 5em;
}
</style>
<body>
<h1>/debug/events</h1>
<table id="req-status">
{{range $i, $fam := .Families}}
<tr>
<td class="family">{{$fam}}</td>
{{range $j, $bucket := $.Buckets}}
{{$n := index $.Counts $i $j}}
<td class="{{if not $bucket.MaxErrAge}}active{{end}}{{if not $n}}empty{{end}}">
{{if $n}}<a href="?fam={{$fam}}&b={{$j}}{{if $.Expanded}}&exp=1{{end}}">{{end}}
[{{$n}} {{$bucket.String}}]
{{if $n}}</a>{{end}}
</td>
{{end}}
</tr>{{end}}
</table>
{{if $.EventLogs}}
<hr />
<h3>Family: {{$.Family}}</h3>
{{if $.Expanded}}<a href="?fam={{$.Family}}&b={{$.Bucket}}">{{end}}
[Summary]{{if $.Expanded}}</a>{{end}}
{{if not $.Expanded}}<a href="?fam={{$.Family}}&b={{$.Bucket}}&exp=1">{{end}}
[Expanded]{{if not $.Expanded}}</a>{{end}}
<table id="reqs">
<tr><th>When</th><th>Elapsed</th></tr>
{{range $el := $.EventLogs}}
<tr class="first">
<td class="when">{{$el.When}}</td>
<td class="elapsed">{{$el.ElapsedTime}}</td>
<td>{{$el.Title}}
</tr>
{{if $.Expanded}}
<tr>
<td class="when"></td>
<td class="elapsed"></td>
<td><pre>{{$el.Stack|trimSpace}}</pre></td>
</tr>
{{range $el.Events}}
<tr>
<td class="when">{{.WhenString}}</td>
<td class="elapsed">{{elapsed .Elapsed}}</td>
<td>.{{if .IsErr}}E{{else}}.{{end}}. {{.What}}</td>
</tr>
{{end}}
{{end}}
{{end}}
</table>
{{end}}
</body>
</html>
`

356
vendor/golang.org/x/net/trace/histogram.go generated vendored Normal file
View file

@ -0,0 +1,356 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package trace
// This file implements histogramming for RPC statistics collection.
import (
"bytes"
"fmt"
"html/template"
"log"
"math"
"golang.org/x/net/internal/timeseries"
)
const (
bucketCount = 38
)
// histogram keeps counts of values in buckets that are spaced
// out in powers of 2: 0-1, 2-3, 4-7...
// histogram implements timeseries.Observable
type histogram struct {
sum int64 // running total of measurements
sumOfSquares float64 // square of running total
buckets []int64 // bucketed values for histogram
value int // holds a single value as an optimization
valueCount int64 // number of values recorded for single value
}
// AddMeasurement records a value measurement observation to the histogram.
func (h *histogram) addMeasurement(value int64) {
// TODO: assert invariant
h.sum += value
h.sumOfSquares += float64(value) * float64(value)
bucketIndex := getBucket(value)
if h.valueCount == 0 || (h.valueCount > 0 && h.value == bucketIndex) {
h.value = bucketIndex
h.valueCount++
} else {
h.allocateBuckets()
h.buckets[bucketIndex]++
}
}
func (h *histogram) allocateBuckets() {
if h.buckets == nil {
h.buckets = make([]int64, bucketCount)
h.buckets[h.value] = h.valueCount
h.value = 0
h.valueCount = -1
}
}
func log2(i int64) int {
n := 0
for ; i >= 0x100; i >>= 8 {
n += 8
}
for ; i > 0; i >>= 1 {
n += 1
}
return n
}
func getBucket(i int64) (index int) {
index = log2(i) - 1
if index < 0 {
index = 0
}
if index >= bucketCount {
index = bucketCount - 1
}
return
}
// Total returns the number of recorded observations.
func (h *histogram) total() (total int64) {
if h.valueCount >= 0 {
total = h.valueCount
}
for _, val := range h.buckets {
total += int64(val)
}
return
}
// Average returns the average value of recorded observations.
func (h *histogram) average() float64 {
t := h.total()
if t == 0 {
return 0
}
return float64(h.sum) / float64(t)
}
// Variance returns the variance of recorded observations.
func (h *histogram) variance() float64 {
t := float64(h.total())
if t == 0 {
return 0
}
s := float64(h.sum) / t
return h.sumOfSquares/t - s*s
}
// StandardDeviation returns the standard deviation of recorded observations.
func (h *histogram) standardDeviation() float64 {
return math.Sqrt(h.variance())
}
// PercentileBoundary estimates the value that the given fraction of recorded
// observations are less than.
func (h *histogram) percentileBoundary(percentile float64) int64 {
total := h.total()
// Corner cases (make sure result is strictly less than Total())
if total == 0 {
return 0
} else if total == 1 {
return int64(h.average())
}
percentOfTotal := round(float64(total) * percentile)
var runningTotal int64
for i := range h.buckets {
value := h.buckets[i]
runningTotal += value
if runningTotal == percentOfTotal {
// We hit an exact bucket boundary. If the next bucket has data, it is a
// good estimate of the value. If the bucket is empty, we interpolate the
// midpoint between the next bucket's boundary and the next non-zero
// bucket. If the remaining buckets are all empty, then we use the
// boundary for the next bucket as the estimate.
j := uint8(i + 1)
min := bucketBoundary(j)
if runningTotal < total {
for h.buckets[j] == 0 {
j++
}
}
max := bucketBoundary(j)
return min + round(float64(max-min)/2)
} else if runningTotal > percentOfTotal {
// The value is in this bucket. Interpolate the value.
delta := runningTotal - percentOfTotal
percentBucket := float64(value-delta) / float64(value)
bucketMin := bucketBoundary(uint8(i))
nextBucketMin := bucketBoundary(uint8(i + 1))
bucketSize := nextBucketMin - bucketMin
return bucketMin + round(percentBucket*float64(bucketSize))
}
}
return bucketBoundary(bucketCount - 1)
}
// Median returns the estimated median of the observed values.
func (h *histogram) median() int64 {
return h.percentileBoundary(0.5)
}
// Add adds other to h.
func (h *histogram) Add(other timeseries.Observable) {
o := other.(*histogram)
if o.valueCount == 0 {
// Other histogram is empty
} else if h.valueCount >= 0 && o.valueCount > 0 && h.value == o.value {
// Both have a single bucketed value, aggregate them
h.valueCount += o.valueCount
} else {
// Two different values necessitate buckets in this histogram
h.allocateBuckets()
if o.valueCount >= 0 {
h.buckets[o.value] += o.valueCount
} else {
for i := range h.buckets {
h.buckets[i] += o.buckets[i]
}
}
}
h.sumOfSquares += o.sumOfSquares
h.sum += o.sum
}
// Clear resets the histogram to an empty state, removing all observed values.
func (h *histogram) Clear() {
h.buckets = nil
h.value = 0
h.valueCount = 0
h.sum = 0
h.sumOfSquares = 0
}
// CopyFrom copies from other, which must be a *histogram, into h.
func (h *histogram) CopyFrom(other timeseries.Observable) {
o := other.(*histogram)
if o.valueCount == -1 {
h.allocateBuckets()
copy(h.buckets, o.buckets)
}
h.sum = o.sum
h.sumOfSquares = o.sumOfSquares
h.value = o.value
h.valueCount = o.valueCount
}
// Multiply scales the histogram by the specified ratio.
func (h *histogram) Multiply(ratio float64) {
if h.valueCount == -1 {
for i := range h.buckets {
h.buckets[i] = int64(float64(h.buckets[i]) * ratio)
}
} else {
h.valueCount = int64(float64(h.valueCount) * ratio)
}
h.sum = int64(float64(h.sum) * ratio)
h.sumOfSquares = h.sumOfSquares * ratio
}
// New creates a new histogram.
func (h *histogram) New() timeseries.Observable {
r := new(histogram)
r.Clear()
return r
}
func (h *histogram) String() string {
return fmt.Sprintf("%d, %f, %d, %d, %v",
h.sum, h.sumOfSquares, h.value, h.valueCount, h.buckets)
}
// round returns the closest int64 to the argument
func round(in float64) int64 {
return int64(math.Floor(in + 0.5))
}
// bucketBoundary returns the first value in the bucket.
func bucketBoundary(bucket uint8) int64 {
if bucket == 0 {
return 0
}
return 1 << bucket
}
// bucketData holds data about a specific bucket for use in distTmpl.
type bucketData struct {
Lower, Upper int64
N int64
Pct, CumulativePct float64
GraphWidth int
}
// data holds data about a Distribution for use in distTmpl.
type data struct {
Buckets []*bucketData
Count, Median int64
Mean, StandardDeviation float64
}
// maxHTMLBarWidth is the maximum width of the HTML bar for visualizing buckets.
const maxHTMLBarWidth = 350.0
// newData returns data representing h for use in distTmpl.
func (h *histogram) newData() *data {
// Force the allocation of buckets to simplify the rendering implementation
h.allocateBuckets()
// We scale the bars on the right so that the largest bar is
// maxHTMLBarWidth pixels in width.
maxBucket := int64(0)
for _, n := range h.buckets {
if n > maxBucket {
maxBucket = n
}
}
total := h.total()
barsizeMult := maxHTMLBarWidth / float64(maxBucket)
var pctMult float64
if total == 0 {
pctMult = 1.0
} else {
pctMult = 100.0 / float64(total)
}
buckets := make([]*bucketData, len(h.buckets))
runningTotal := int64(0)
for i, n := range h.buckets {
if n == 0 {
continue
}
runningTotal += n
var upperBound int64
if i < bucketCount-1 {
upperBound = bucketBoundary(uint8(i + 1))
} else {
upperBound = math.MaxInt64
}
buckets[i] = &bucketData{
Lower: bucketBoundary(uint8(i)),
Upper: upperBound,
N: n,
Pct: float64(n) * pctMult,
CumulativePct: float64(runningTotal) * pctMult,
GraphWidth: int(float64(n) * barsizeMult),
}
}
return &data{
Buckets: buckets,
Count: total,
Median: h.median(),
Mean: h.average(),
StandardDeviation: h.standardDeviation(),
}
}
func (h *histogram) html() template.HTML {
buf := new(bytes.Buffer)
if err := distTmpl.Execute(buf, h.newData()); err != nil {
buf.Reset()
log.Printf("net/trace: couldn't execute template: %v", err)
}
return template.HTML(buf.String())
}
// Input: data
var distTmpl = template.Must(template.New("distTmpl").Parse(`
<table>
<tr>
<td style="padding:0.25em">Count: {{.Count}}</td>
<td style="padding:0.25em">Mean: {{printf "%.0f" .Mean}}</td>
<td style="padding:0.25em">StdDev: {{printf "%.0f" .StandardDeviation}}</td>
<td style="padding:0.25em">Median: {{.Median}}</td>
</tr>
</table>
<hr>
<table>
{{range $b := .Buckets}}
{{if $b}}
<tr>
<td style="padding:0 0 0 0.25em">[</td>
<td style="text-align:right;padding:0 0.25em">{{.Lower}},</td>
<td style="text-align:right;padding:0 0.25em">{{.Upper}})</td>
<td style="text-align:right;padding:0 0.25em">{{.N}}</td>
<td style="text-align:right;padding:0 0.25em">{{printf "%#.3f" .Pct}}%</td>
<td style="text-align:right;padding:0 0.25em">{{printf "%#.3f" .CumulativePct}}%</td>
<td><div style="background-color: blue; height: 1em; width: {{.GraphWidth}};"></div></td>
</tr>
{{end}}
{{end}}
</table>
`))

1071
vendor/golang.org/x/net/trace/trace.go generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build appengine appenginevm // +build appengine
// App Engine hooks. // App Engine hooks.
@ -12,11 +12,12 @@ import (
"net/http" "net/http"
"golang.org/x/net/context" "golang.org/x/net/context"
"golang.org/x/oauth2/internal"
"google.golang.org/appengine/urlfetch" "google.golang.org/appengine/urlfetch"
) )
func init() { func init() {
registerContextClientFunc(contextClientAppEngine) internal.RegisterContextClientFunc(contextClientAppEngine)
} }
func contextClientAppEngine(ctx context.Context) (*http.Client, error) { func contextClientAppEngine(ctx context.Context) (*http.Client, error) {

View file

@ -1,4 +1,4 @@
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -14,9 +14,15 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
// appengineFlex is set at init time by appengineflex_hook.go. If true, we are on App Engine Flex.
var appengineFlex bool
// Set at init time by appengine_hook.go. If nil, we're not on App Engine. // Set at init time by appengine_hook.go. If nil, we're not on App Engine.
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error) var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
var appengineAppIDFunc func(c context.Context) string
// AppEngineTokenSource returns a token source that fetches tokens // AppEngineTokenSource returns a token source that fetches tokens
// issued to the current App Engine application's service account. // issued to the current App Engine application's service account.
// If you are implementing a 3-legged OAuth 2.0 flow on App Engine // If you are implementing a 3-legged OAuth 2.0 flow on App Engine

View file

@ -1,4 +1,4 @@
// Copyright 2015 The oauth2 Authors. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -10,4 +10,5 @@ import "google.golang.org/appengine"
func init() { func init() {
appengineTokenFunc = appengine.AccessToken appengineTokenFunc = appengine.AccessToken
appengineAppIDFunc = appengine.AppID
} }

View file

@ -0,0 +1,11 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appenginevm
package google
func init() {
appengineFlex = true // Flex doesn't support appengine.AccessToken; depend on metadata server.
}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The oauth2 Authors. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -6,7 +6,6 @@ package google
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@ -14,22 +13,21 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"cloud.google.com/go/compute/metadata"
"golang.org/x/net/context" "golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/jwt"
"google.golang.org/cloud/compute/metadata"
) )
// DefaultCredentials holds "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type DefaultCredentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
}
// DefaultClient returns an HTTP Client that uses the // DefaultClient returns an HTTP Client that uses the
// DefaultTokenSource to obtain authentication credentials. // DefaultTokenSource to obtain authentication credentials.
//
// This client should be used when developing services
// that run on Google App Engine or Google Compute Engine
// and use "Application Default Credentials."
//
// For more details, see:
// https://developers.google.com/accounts/application-default-credentials
//
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) { func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
ts, err := DefaultTokenSource(ctx, scope...) ts, err := DefaultTokenSource(ctx, scope...)
if err != nil { if err != nil {
@ -38,8 +36,18 @@ func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
return oauth2.NewClient(ctx, ts), nil return oauth2.NewClient(ctx, ts), nil
} }
// DefaultTokenSource is a token source that uses // DefaultTokenSource returns the token source for
// "Application Default Credentials". // "Application Default Credentials".
// It is a shortcut for FindDefaultCredentials(ctx, scope).TokenSource.
func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
creds, err := FindDefaultCredentials(ctx, scope...)
if err != nil {
return nil, err
}
return creds.TokenSource, nil
}
// FindDefaultCredentials searches for "Application Default Credentials".
// //
// It looks for credentials in the following places, // It looks for credentials in the following places,
// preferring the first location found: // preferring the first location found:
@ -50,51 +58,47 @@ func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json. // On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
// On other systems, $HOME/.config/gcloud/application_default_credentials.json. // On other systems, $HOME/.config/gcloud/application_default_credentials.json.
// 3. On Google App Engine it uses the appengine.AccessToken function. // 3. On Google App Engine it uses the appengine.AccessToken function.
// 4. On Google Compute Engine, it fetches credentials from the metadata server. // 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.) // (In this final case any provided scopes are ignored.)
// func FindDefaultCredentials(ctx context.Context, scope ...string) (*DefaultCredentials, error) {
// For more details, see:
// https://developers.google.com/accounts/application-default-credentials
//
func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
// First, try the environment variable. // First, try the environment variable.
const envVar = "GOOGLE_APPLICATION_CREDENTIALS" const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
if filename := os.Getenv(envVar); filename != "" { if filename := os.Getenv(envVar); filename != "" {
ts, err := tokenSourceFromFile(ctx, filename, scope) creds, err := readCredentialsFile(ctx, filename, scope)
if err != nil { if err != nil {
return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err) return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err)
} }
return ts, nil return creds, nil
} }
// Second, try a well-known file. // Second, try a well-known file.
filename := wellKnownFile() filename := wellKnownFile()
_, err := os.Stat(filename) if creds, err := readCredentialsFile(ctx, filename, scope); err == nil {
if err == nil { return creds, nil
ts, err2 := tokenSourceFromFile(ctx, filename, scope) } else if !os.IsNotExist(err) {
if err2 == nil {
return ts, nil
}
err = err2
} else if os.IsNotExist(err) {
err = nil // ignore this error
}
if err != nil {
return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err) return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err)
} }
// Third, if we're on Google App Engine use those credentials. // Third, if we're on Google App Engine use those credentials.
if appengineTokenFunc != nil { if appengineTokenFunc != nil && !appengineFlex {
return AppEngineTokenSource(ctx, scope...), nil return &DefaultCredentials{
ProjectID: appengineAppIDFunc(ctx),
TokenSource: AppEngineTokenSource(ctx, scope...),
}, nil
} }
// Fourth, if we're on Google Compute Engine use the metadata server. // Fourth, if we're on Google Compute Engine use the metadata server.
if metadata.OnGCE() { if metadata.OnGCE() {
return ComputeTokenSource(""), nil id, _ := metadata.ProjectID()
return &DefaultCredentials{
ProjectID: id,
TokenSource: ComputeTokenSource(""),
}, nil
} }
// None are found; return helpful error. // None are found; return helpful error.
const url = "https://developers.google.com/accounts/application-default-credentials" const url = "https://developers.google.com/accounts/docs/application-default-credentials"
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url) return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
} }
@ -106,49 +110,21 @@ func wellKnownFile() string {
return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", f) return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", f)
} }
func tokenSourceFromFile(ctx context.Context, filename string, scopes []string) (oauth2.TokenSource, error) { func readCredentialsFile(ctx context.Context, filename string, scopes []string) (*DefaultCredentials, error) {
b, err := ioutil.ReadFile(filename) b, err := ioutil.ReadFile(filename)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var d struct { var f credentialsFile
// Common fields if err := json.Unmarshal(b, &f); err != nil {
Type string
ClientID string `json:"client_id"`
// User Credential fields
ClientSecret string `json:"client_secret"`
RefreshToken string `json:"refresh_token"`
// Service Account fields
ClientEmail string `json:"client_email"`
PrivateKeyID string `json:"private_key_id"`
PrivateKey string `json:"private_key"`
}
if err := json.Unmarshal(b, &d); err != nil {
return nil, err return nil, err
} }
switch d.Type { ts, err := f.tokenSource(ctx, append([]string(nil), scopes...))
case "authorized_user": if err != nil {
cfg := &oauth2.Config{ return nil, err
ClientID: d.ClientID,
ClientSecret: d.ClientSecret,
Scopes: append([]string{}, scopes...), // copy
Endpoint: Endpoint,
}
tok := &oauth2.Token{RefreshToken: d.RefreshToken}
return cfg.TokenSource(ctx, tok), nil
case "service_account":
cfg := &jwt.Config{
Email: d.ClientEmail,
PrivateKey: []byte(d.PrivateKey),
Scopes: append([]string{}, scopes...), // copy
TokenURL: JWTTokenURL,
}
return cfg.TokenSource(ctx), nil
case "":
return nil, errors.New("missing 'type' field in credentials")
default:
return nil, fmt.Errorf("unknown credential type: %q", d.Type)
} }
return &DefaultCredentials{
ProjectID: f.ProjectID,
TokenSource: ts,
}, nil
} }

View file

@ -1,4 +1,4 @@
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -11,7 +11,7 @@
// For more information, please read // For more information, please read
// https://developers.google.com/accounts/docs/OAuth2 // https://developers.google.com/accounts/docs/OAuth2
// and // and
// https://developers.google.com/accounts/application-default-credentials. // https://developers.google.com/accounts/docs/application-default-credentials.
package google // import "golang.org/x/oauth2/google" package google // import "golang.org/x/oauth2/google"
import ( import (
@ -21,9 +21,10 @@ import (
"strings" "strings"
"time" "time"
"cloud.google.com/go/compute/metadata"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/jwt" "golang.org/x/oauth2/jwt"
"google.golang.org/cloud/compute/metadata"
) )
// Endpoint is Google's OAuth 2.0 endpoint. // Endpoint is Google's OAuth 2.0 endpoint.
@ -37,9 +38,10 @@ const JWTTokenURL = "https://accounts.google.com/o/oauth2/token"
// ConfigFromJSON uses a Google Developers Console client_credentials.json // ConfigFromJSON uses a Google Developers Console client_credentials.json
// file to construct a config. // file to construct a config.
// client_credentials.json can be downloadable from https://console.developers.google.com, // client_credentials.json can be downloaded from
// under "APIs & Auth" > "Credentials". Download the Web application credentials in the // https://console.developers.google.com, under "Credentials". Download the Web
// JSON format and provide the contents of the file as jsonKey. // application credentials in the JSON format and provide the contents of the
// file as jsonKey.
func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) { func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
type cred struct { type cred struct {
ClientID string `json:"client_id"` ClientID string `json:"client_id"`
@ -81,22 +83,77 @@ func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
// JWTConfigFromJSON uses a Google Developers service account JSON key file to read // JWTConfigFromJSON uses a Google Developers service account JSON key file to read
// the credentials that authorize and authenticate the requests. // the credentials that authorize and authenticate the requests.
// Create a service account on "Credentials" page under "APIs & Auth" for your // Create a service account on "Credentials" for your project at
// project at https://console.developers.google.com to download a JSON key file. // https://console.developers.google.com to download a JSON key file.
func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) { func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
var key struct { var f credentialsFile
Email string `json:"client_email"` if err := json.Unmarshal(jsonKey, &f); err != nil {
PrivateKey string `json:"private_key"`
}
if err := json.Unmarshal(jsonKey, &key); err != nil {
return nil, err return nil, err
} }
return &jwt.Config{ if f.Type != serviceAccountKey {
Email: key.Email, return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey)
PrivateKey: []byte(key.PrivateKey), }
Scopes: scope, scope = append([]string(nil), scope...) // copy
TokenURL: JWTTokenURL, return f.jwtConfig(scope), nil
}, nil }
// JSON key file types.
const (
serviceAccountKey = "service_account"
userCredentialsKey = "authorized_user"
)
// credentialsFile is the unmarshalled representation of a credentials file.
type credentialsFile struct {
Type string `json:"type"` // serviceAccountKey or userCredentialsKey
// Service Account fields
ClientEmail string `json:"client_email"`
PrivateKeyID string `json:"private_key_id"`
PrivateKey string `json:"private_key"`
TokenURL string `json:"token_uri"`
ProjectID string `json:"project_id"`
// User Credential fields
// (These typically come from gcloud auth.)
ClientSecret string `json:"client_secret"`
ClientID string `json:"client_id"`
RefreshToken string `json:"refresh_token"`
}
func (f *credentialsFile) jwtConfig(scopes []string) *jwt.Config {
cfg := &jwt.Config{
Email: f.ClientEmail,
PrivateKey: []byte(f.PrivateKey),
PrivateKeyID: f.PrivateKeyID,
Scopes: scopes,
TokenURL: f.TokenURL,
}
if cfg.TokenURL == "" {
cfg.TokenURL = JWTTokenURL
}
return cfg
}
func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oauth2.TokenSource, error) {
switch f.Type {
case serviceAccountKey:
cfg := f.jwtConfig(scopes)
return cfg.TokenSource(ctx), nil
case userCredentialsKey:
cfg := &oauth2.Config{
ClientID: f.ClientID,
ClientSecret: f.ClientSecret,
Scopes: scopes,
Endpoint: Endpoint,
}
tok := &oauth2.Token{RefreshToken: f.RefreshToken}
return cfg.TokenSource(ctx, tok), nil
case "":
return nil, errors.New("missing 'type' field in credentials")
default:
return nil, fmt.Errorf("unknown credential type: %q", f.Type)
}
} }
// ComputeTokenSource returns a token source that fetches access tokens // ComputeTokenSource returns a token source that fetches access tokens

74
vendor/golang.org/x/oauth2/google/jwt.go generated vendored Normal file
View file

@ -0,0 +1,74 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package google
import (
"crypto/rsa"
"fmt"
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/internal"
"golang.org/x/oauth2/jws"
)
// JWTAccessTokenSourceFromJSON uses a Google Developers service account JSON
// key file to read the credentials that authorize and authenticate the
// requests, and returns a TokenSource that does not use any OAuth2 flow but
// instead creates a JWT and sends that as the access token.
// The audience is typically a URL that specifies the scope of the credentials.
//
// Note that this is not a standard OAuth flow, but rather an
// optimization supported by a few Google services.
// Unless you know otherwise, you should use JWTConfigFromJSON instead.
func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.TokenSource, error) {
cfg, err := JWTConfigFromJSON(jsonKey)
if err != nil {
return nil, fmt.Errorf("google: could not parse JSON key: %v", err)
}
pk, err := internal.ParseKey(cfg.PrivateKey)
if err != nil {
return nil, fmt.Errorf("google: could not parse key: %v", err)
}
ts := &jwtAccessTokenSource{
email: cfg.Email,
audience: audience,
pk: pk,
pkID: cfg.PrivateKeyID,
}
tok, err := ts.Token()
if err != nil {
return nil, err
}
return oauth2.ReuseTokenSource(tok, ts), nil
}
type jwtAccessTokenSource struct {
email, audience string
pk *rsa.PrivateKey
pkID string
}
func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
iat := time.Now()
exp := iat.Add(time.Hour)
cs := &jws.ClaimSet{
Iss: ts.email,
Sub: ts.email,
Aud: ts.audience,
Iat: iat.Unix(),
Exp: exp.Unix(),
}
hdr := &jws.Header{
Algorithm: "RS256",
Typ: "JWT",
KeyID: string(ts.pkID),
}
msg, err := jws.Encode(hdr, cs, ts.pk)
if err != nil {
return nil, fmt.Errorf("google: could not encode JWT: %v", err)
}
return &oauth2.Token{AccessToken: msg, TokenType: "Bearer", Expiry: exp}, nil
}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The oauth2 Authors. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -160,9 +160,13 @@ var sdkConfigPath = func() (string, error) {
} }
func guessUnixHomeDir() string { func guessUnixHomeDir() string {
usr, err := user.Current() // Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
if err == nil { if v := os.Getenv("HOME"); v != "" {
return usr.HomeDir return v
} }
return os.Getenv("HOME") // Else, fall back to user.Current:
if u, err := user.Current(); err == nil {
return u.HomeDir
}
return ""
} }

View file

@ -1,4 +1,4 @@
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -42,7 +42,7 @@ func ParseKey(key []byte) (*rsa.PrivateKey, error) {
func ParseINI(ini io.Reader) (map[string]map[string]string, error) { func ParseINI(ini io.Reader) (map[string]map[string]string, error) {
result := map[string]map[string]string{ result := map[string]map[string]string{
"": map[string]string{}, // root section "": {}, // root section
} }
scanner := bufio.NewScanner(ini) scanner := bufio.NewScanner(ini)
currentSection := "" currentSection := ""
@ -67,3 +67,10 @@ func ParseINI(ini io.Reader) (map[string]map[string]string, error) {
} }
return result, nil return result, nil
} }
func CondVal(v string) []string {
if v == "" {
return nil
}
return []string{v}
}

247
vendor/golang.org/x/oauth2/internal/token.go generated vendored Normal file
View file

@ -0,0 +1,247 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package internal contains support packages for oauth2 package.
package internal
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"mime"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"golang.org/x/net/context"
)
// Token represents the crendentials used to authorize
// the requests to access protected resources on the OAuth 2.0
// provider's backend.
//
// This type is a mirror of oauth2.Token and exists to break
// an otherwise-circular dependency. Other internal packages
// should convert this Token into an oauth2.Token before use.
type Token struct {
// AccessToken is the token that authorizes and authenticates
// the requests.
AccessToken string
// TokenType is the type of token.
// The Type method returns either this or "Bearer", the default.
TokenType string
// RefreshToken is a token that's used by the application
// (as opposed to the user) to refresh the access token
// if it expires.
RefreshToken string
// Expiry is the optional expiration time of the access token.
//
// If zero, TokenSource implementations will reuse the same
// token forever and RefreshToken or equivalent
// mechanisms for that TokenSource will not be used.
Expiry time.Time
// Raw optionally contains extra metadata from the server
// when updating a token.
Raw interface{}
}
// tokenJSON is the struct representing the HTTP response from OAuth2
// providers returning a token in JSON form.
type tokenJSON struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
RefreshToken string `json:"refresh_token"`
ExpiresIn expirationTime `json:"expires_in"` // at least PayPal returns string, while most return number
Expires expirationTime `json:"expires"` // broken Facebook spelling of expires_in
}
func (e *tokenJSON) expiry() (t time.Time) {
if v := e.ExpiresIn; v != 0 {
return time.Now().Add(time.Duration(v) * time.Second)
}
if v := e.Expires; v != 0 {
return time.Now().Add(time.Duration(v) * time.Second)
}
return
}
type expirationTime int32
func (e *expirationTime) UnmarshalJSON(b []byte) error {
var n json.Number
err := json.Unmarshal(b, &n)
if err != nil {
return err
}
i, err := n.Int64()
if err != nil {
return err
}
*e = expirationTime(i)
return nil
}
var brokenAuthHeaderProviders = []string{
"https://accounts.google.com/",
"https://api.codeswholesale.com/oauth/token",
"https://api.dropbox.com/",
"https://api.dropboxapi.com/",
"https://api.instagram.com/",
"https://api.netatmo.net/",
"https://api.odnoklassniki.ru/",
"https://api.pushbullet.com/",
"https://api.soundcloud.com/",
"https://api.twitch.tv/",
"https://app.box.com/",
"https://connect.stripe.com/",
"https://graph.facebook.com", // see https://github.com/golang/oauth2/issues/214
"https://login.microsoftonline.com/",
"https://login.salesforce.com/",
"https://oauth.sandbox.trainingpeaks.com/",
"https://oauth.trainingpeaks.com/",
"https://oauth.vk.com/",
"https://openapi.baidu.com/",
"https://slack.com/",
"https://test-sandbox.auth.corp.google.com",
"https://test.salesforce.com/",
"https://user.gini.net/",
"https://www.douban.com/",
"https://www.googleapis.com/",
"https://www.linkedin.com/",
"https://www.strava.com/oauth/",
"https://www.wunderlist.com/oauth/",
"https://api.patreon.com/",
"https://sandbox.codeswholesale.com/oauth/token",
}
// brokenAuthHeaderDomains lists broken providers that issue dynamic endpoints.
var brokenAuthHeaderDomains = []string{
".force.com",
".okta.com",
".oktapreview.com",
}
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL)
}
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
// implements the OAuth2 spec correctly
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
// In summary:
// - Reddit only accepts client secret in the Authorization header
// - Dropbox accepts either it in URL param or Auth header, but not both.
// - Google only accepts URL param (not spec compliant?), not Auth header
// - Stripe only accepts client secret in Auth header with Bearer method, not Basic
func providerAuthHeaderWorks(tokenURL string) bool {
for _, s := range brokenAuthHeaderProviders {
if strings.HasPrefix(tokenURL, s) {
// Some sites fail to implement the OAuth2 spec fully.
return false
}
}
if u, err := url.Parse(tokenURL); err == nil {
for _, s := range brokenAuthHeaderDomains {
if strings.HasSuffix(u.Host, s) {
return false
}
}
}
// Assume the provider implements the spec properly
// otherwise. We can add more exceptions as they're
// discovered. We will _not_ be adding configurable hooks
// to this package to let users select server bugs.
return true
}
func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) {
hc, err := ContextClient(ctx)
if err != nil {
return nil, err
}
bustedAuth := !providerAuthHeaderWorks(tokenURL)
if bustedAuth {
if clientID != "" {
v.Set("client_id", clientID)
}
if clientSecret != "" {
v.Set("client_secret", clientSecret)
}
}
req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode()))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if !bustedAuth {
req.SetBasicAuth(clientID, clientSecret)
}
r, err := hc.Do(req)
if err != nil {
return nil, err
}
defer r.Body.Close()
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
if err != nil {
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
}
if code := r.StatusCode; code < 200 || code > 299 {
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
}
var token *Token
content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
switch content {
case "application/x-www-form-urlencoded", "text/plain":
vals, err := url.ParseQuery(string(body))
if err != nil {
return nil, err
}
token = &Token{
AccessToken: vals.Get("access_token"),
TokenType: vals.Get("token_type"),
RefreshToken: vals.Get("refresh_token"),
Raw: vals,
}
e := vals.Get("expires_in")
if e == "" {
// TODO(jbd): Facebook's OAuth2 implementation is broken and
// returns expires_in field in expires. Remove the fallback to expires,
// when Facebook fixes their implementation.
e = vals.Get("expires")
}
expires, _ := strconv.Atoi(e)
if expires != 0 {
token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
}
default:
var tj tokenJSON
if err = json.Unmarshal(body, &tj); err != nil {
return nil, err
}
token = &Token{
AccessToken: tj.AccessToken,
TokenType: tj.TokenType,
RefreshToken: tj.RefreshToken,
Expiry: tj.expiry(),
Raw: make(map[string]interface{}),
}
json.Unmarshal(body, &token.Raw) // no error checks for optional fields
}
// Don't overwrite `RefreshToken` with an empty value
// if this was a token refreshing request.
if token.RefreshToken == "" {
token.RefreshToken = v.Get("refresh_token")
}
return token, nil
}

69
vendor/golang.org/x/oauth2/internal/transport.go generated vendored Normal file
View file

@ -0,0 +1,69 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package internal contains support packages for oauth2 package.
package internal
import (
"net/http"
"golang.org/x/net/context"
)
// HTTPClient is the context key to use with golang.org/x/net/context's
// WithValue function to associate an *http.Client value with a context.
var HTTPClient ContextKey
// ContextKey is just an empty struct. It exists so HTTPClient can be
// an immutable public variable with a unique type. It's immutable
// because nobody else can create a ContextKey, being unexported.
type ContextKey struct{}
// ContextClientFunc is a func which tries to return an *http.Client
// given a Context value. If it returns an error, the search stops
// with that error. If it returns (nil, nil), the search continues
// down the list of registered funcs.
type ContextClientFunc func(context.Context) (*http.Client, error)
var contextClientFuncs []ContextClientFunc
func RegisterContextClientFunc(fn ContextClientFunc) {
contextClientFuncs = append(contextClientFuncs, fn)
}
func ContextClient(ctx context.Context) (*http.Client, error) {
if ctx != nil {
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
return hc, nil
}
}
for _, fn := range contextClientFuncs {
c, err := fn(ctx)
if err != nil {
return nil, err
}
if c != nil {
return c, nil
}
}
return http.DefaultClient, nil
}
func ContextTransport(ctx context.Context) http.RoundTripper {
hc, err := ContextClient(ctx)
// This is a rare error case (somebody using nil on App Engine).
if err != nil {
return ErrorTransport{err}
}
return hc.Transport
}
// ErrorTransport returns the specified error on RoundTrip.
// This RoundTripper should be used in rare error cases where
// error handling can be postponed to response handling time.
type ErrorTransport struct{ Err error }
func (t ErrorTransport) RoundTrip(*http.Request) (*http.Response, error) {
return nil, t.Err
}

110
vendor/golang.org/x/oauth2/jws/jws.go generated vendored
View file

@ -1,9 +1,17 @@
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package jws provides encoding and decoding utilities for // Package jws provides a partial implementation
// signed JWS messages. // of JSON Web Signature encoding and decoding.
// It exists to support the golang.org/x/oauth2 package.
//
// See RFC 7515.
//
// Deprecated: this package is not intended for public use and might be
// removed in the future. It exists for internal use only.
// Please switch to another JWS package or copy this package into your own
// source tree.
package jws // import "golang.org/x/oauth2/jws" package jws // import "golang.org/x/oauth2/jws"
import ( import (
@ -27,8 +35,8 @@ type ClaimSet struct {
Iss string `json:"iss"` // email address of the client_id of the application making the access token request Iss string `json:"iss"` // email address of the client_id of the application making the access token request
Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests
Aud string `json:"aud"` // descriptor of the intended target of the assertion (Optional). Aud string `json:"aud"` // descriptor of the intended target of the assertion (Optional).
Exp int64 `json:"exp"` // the expiration time of the assertion Exp int64 `json:"exp"` // the expiration time of the assertion (seconds since Unix epoch)
Iat int64 `json:"iat"` // the time the assertion was issued. Iat int64 `json:"iat"` // the time the assertion was issued (seconds since Unix epoch)
Typ string `json:"typ,omitempty"` // token type (Optional). Typ string `json:"typ,omitempty"` // token type (Optional).
// Email for which the application is requesting delegated access (Optional). // Email for which the application is requesting delegated access (Optional).
@ -41,23 +49,22 @@ type ClaimSet struct {
// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3 // See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
// This array is marshalled using custom code (see (c *ClaimSet) encode()). // This array is marshalled using custom code (see (c *ClaimSet) encode()).
PrivateClaims map[string]interface{} `json:"-"` PrivateClaims map[string]interface{} `json:"-"`
exp time.Time
iat time.Time
} }
func (c *ClaimSet) encode() (string, error) { func (c *ClaimSet) encode() (string, error) {
if c.exp.IsZero() || c.iat.IsZero() { // Reverting time back for machines whose time is not perfectly in sync.
// Reverting time back for machines whose time is not perfectly in sync. // If client machine's time is in the future according
// If client machine's time is in the future according // to Google servers, an access token will not be issued.
// to Google servers, an access token will not be issued. now := time.Now().Add(-10 * time.Second)
now := time.Now().Add(-10 * time.Second) if c.Iat == 0 {
c.iat = now c.Iat = now.Unix()
c.exp = now.Add(time.Hour) }
if c.Exp == 0 {
c.Exp = now.Add(time.Hour).Unix()
}
if c.Exp < c.Iat {
return "", fmt.Errorf("jws: invalid Exp = %v; must be later than Iat = %v", c.Exp, c.Iat)
} }
c.Exp = c.exp.Unix()
c.Iat = c.iat.Unix()
b, err := json.Marshal(c) b, err := json.Marshal(c)
if err != nil { if err != nil {
@ -65,7 +72,7 @@ func (c *ClaimSet) encode() (string, error) {
} }
if len(c.PrivateClaims) == 0 { if len(c.PrivateClaims) == 0 {
return base64Encode(b), nil return base64.RawURLEncoding.EncodeToString(b), nil
} }
// Marshal private claim set and then append it to b. // Marshal private claim set and then append it to b.
@ -83,7 +90,7 @@ func (c *ClaimSet) encode() (string, error) {
} }
b[len(b)-1] = ',' // Replace closing curly brace with a comma. b[len(b)-1] = ',' // Replace closing curly brace with a comma.
b = append(b, prv[1:]...) // Append private claims. b = append(b, prv[1:]...) // Append private claims.
return base64Encode(b), nil return base64.RawURLEncoding.EncodeToString(b), nil
} }
// Header represents the header for the signed JWS payloads. // Header represents the header for the signed JWS payloads.
@ -93,6 +100,9 @@ type Header struct {
// Represents the token type. // Represents the token type.
Typ string `json:"typ"` Typ string `json:"typ"`
// The optional hint of which key is being used.
KeyID string `json:"kid,omitempty"`
} }
func (h *Header) encode() (string, error) { func (h *Header) encode() (string, error) {
@ -100,7 +110,7 @@ func (h *Header) encode() (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return base64Encode(b), nil return base64.RawURLEncoding.EncodeToString(b), nil
} }
// Decode decodes a claim set from a JWS payload. // Decode decodes a claim set from a JWS payload.
@ -111,7 +121,7 @@ func Decode(payload string) (*ClaimSet, error) {
// TODO(jbd): Provide more context about the error. // TODO(jbd): Provide more context about the error.
return nil, errors.New("jws: invalid token received") return nil, errors.New("jws: invalid token received")
} }
decoded, err := base64Decode(s[1]) decoded, err := base64.RawURLEncoding.DecodeString(s[1])
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -120,8 +130,11 @@ func Decode(payload string) (*ClaimSet, error) {
return c, err return c, err
} }
// Encode encodes a signed JWS with provided header and claim set. // Signer returns a signature for the given data.
func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, error) { type Signer func(data []byte) (sig []byte, err error)
// EncodeWithSigner encodes a header and claim set with the provided signer.
func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
head, err := header.encode() head, err := header.encode()
if err != nil { if err != nil {
return "", err return "", err
@ -131,30 +144,39 @@ func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, err
return "", err return "", err
} }
ss := fmt.Sprintf("%s.%s", head, cs) ss := fmt.Sprintf("%s.%s", head, cs)
h := sha256.New() sig, err := sg([]byte(ss))
h.Write([]byte(ss))
b, err := rsa.SignPKCS1v15(rand.Reader, signature, crypto.SHA256, h.Sum(nil))
if err != nil { if err != nil {
return "", err return "", err
} }
sig := base64Encode(b) return fmt.Sprintf("%s.%s", ss, base64.RawURLEncoding.EncodeToString(sig)), nil
return fmt.Sprintf("%s.%s", ss, sig), nil
} }
// base64Encode returns and Base64url encoded version of the input string with any // Encode encodes a signed JWS with provided header and claim set.
// trailing "=" stripped. // This invokes EncodeWithSigner using crypto/rsa.SignPKCS1v15 with the given RSA private key.
func base64Encode(b []byte) string { func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=") sg := func(data []byte) (sig []byte, err error) {
} h := sha256.New()
h.Write(data)
// base64Decode decodes the Base64url encoded string return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
func base64Decode(s string) ([]byte, error) {
// add back missing padding
switch len(s) % 4 {
case 2:
s += "=="
case 3:
s += "="
} }
return base64.URLEncoding.DecodeString(s) return EncodeWithSigner(header, c, sg)
}
// Verify tests whether the provided JWT token's signature was produced by the private key
// associated with the supplied public key.
func Verify(token string, key *rsa.PublicKey) error {
parts := strings.Split(token, ".")
if len(parts) != 3 {
return errors.New("jws: invalid token received, token must have 3 parts")
}
signedContent := parts[0] + "." + parts[1]
signatureString, err := base64.RawURLEncoding.DecodeString(parts[2])
if err != nil {
return err
}
h := sha256.New()
h.Write([]byte(signedContent))
return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), []byte(signatureString))
} }

View file

@ -1,4 +1,4 @@
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -46,6 +46,10 @@ type Config struct {
// //
PrivateKey []byte PrivateKey []byte
// PrivateKeyID contains an optional hint indicating which key is being
// used.
PrivateKeyID string
// Subject is the optional user to impersonate. // Subject is the optional user to impersonate.
Subject string Subject string
@ -54,6 +58,9 @@ type Config struct {
// TokenURL is the endpoint required to complete the 2-legged JWT flow. // TokenURL is the endpoint required to complete the 2-legged JWT flow.
TokenURL string TokenURL string
// Expires optionally specifies how long the token is valid for.
Expires time.Duration
} }
// TokenSource returns a JWT TokenSource using the configuration // TokenSource returns a JWT TokenSource using the configuration
@ -95,7 +102,12 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
// to be compatible with legacy OAuth 2.0 providers. // to be compatible with legacy OAuth 2.0 providers.
claimSet.Prn = subject claimSet.Prn = subject
} }
payload, err := jws.Encode(defaultHeader, claimSet, pk) if t := js.conf.Expires; t > 0 {
claimSet.Exp = time.Now().Add(t).Unix()
}
h := *defaultHeader
h.KeyID = js.conf.PrivateKeyID
payload, err := jws.Encode(&h, claimSet, pk)
if err != nil { if err != nil {
return nil, err return nil, err
} }

267
vendor/golang.org/x/oauth2/oauth2.go generated vendored
View file

@ -1,4 +1,4 @@
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -9,28 +9,38 @@ package oauth2 // import "golang.org/x/oauth2"
import ( import (
"bytes" "bytes"
"encoding/json"
"errors" "errors"
"fmt"
"io"
"io/ioutil"
"mime"
"net/http" "net/http"
"net/url" "net/url"
"strconv"
"strings" "strings"
"sync" "sync"
"time"
"golang.org/x/net/context" "golang.org/x/net/context"
"golang.org/x/oauth2/internal"
) )
// NoContext is the default context you should supply if not using // NoContext is the default context you should supply if not using
// your own context.Context (see https://golang.org/x/net/context). // your own context.Context (see https://golang.org/x/net/context).
//
// Deprecated: Use context.Background() or context.TODO() instead.
var NoContext = context.TODO() var NoContext = context.TODO()
// RegisterBrokenAuthHeaderProvider registers an OAuth2 server
// identified by the tokenURL prefix as an OAuth2 implementation
// which doesn't support the HTTP Basic authentication
// scheme to authenticate with the authorization server.
// Once a server is registered, credentials (client_id and client_secret)
// will be passed as query parameters rather than being present
// in the Authorization header.
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
internal.RegisterBrokenAuthHeaderProvider(tokenURL)
}
// Config describes a typical 3-legged OAuth2 flow, with both the // Config describes a typical 3-legged OAuth2 flow, with both the
// client application information and the server's endpoint URLs. // client application information and the server's endpoint URLs.
// For the client credentials 2-legged OAuth2 flow, see the clientcredentials
// package (https://golang.org/x/oauth2/clientcredentials).
type Config struct { type Config struct {
// ClientID is the application's ID. // ClientID is the application's ID.
ClientID string ClientID string
@ -79,13 +89,13 @@ var (
// result in your application obtaining a refresh token the // result in your application obtaining a refresh token the
// first time your application exchanges an authorization // first time your application exchanges an authorization
// code for a user. // code for a user.
AccessTypeOnline AuthCodeOption = SetParam("access_type", "online") AccessTypeOnline AuthCodeOption = SetAuthURLParam("access_type", "online")
AccessTypeOffline AuthCodeOption = SetParam("access_type", "offline") AccessTypeOffline AuthCodeOption = SetAuthURLParam("access_type", "offline")
// ApprovalForce forces the users to view the consent dialog // ApprovalForce forces the users to view the consent dialog
// and confirm the permissions request at the URL returned // and confirm the permissions request at the URL returned
// from AuthCodeURL, even if they've already done so. // from AuthCodeURL, even if they've already done so.
ApprovalForce AuthCodeOption = SetParam("approval_prompt", "force") ApprovalForce AuthCodeOption = SetAuthURLParam("approval_prompt", "force")
) )
// An AuthCodeOption is passed to Config.AuthCodeURL. // An AuthCodeOption is passed to Config.AuthCodeURL.
@ -97,9 +107,9 @@ type setParam struct{ k, v string }
func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) } func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) }
// SetParam builds an AuthCodeOption which passes key/value parameters // SetAuthURLParam builds an AuthCodeOption which passes key/value parameters
// to a provider's authorization endpoint. // to a provider's authorization endpoint.
func SetParam(key, value string) AuthCodeOption { func SetAuthURLParam(key, value string) AuthCodeOption {
return setParam{key, value} return setParam{key, value}
} }
@ -119,9 +129,9 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
v := url.Values{ v := url.Values{
"response_type": {"code"}, "response_type": {"code"},
"client_id": {c.ClientID}, "client_id": {c.ClientID},
"redirect_uri": condVal(c.RedirectURL), "redirect_uri": internal.CondVal(c.RedirectURL),
"scope": condVal(strings.Join(c.Scopes, " ")), "scope": internal.CondVal(strings.Join(c.Scopes, " ")),
"state": condVal(state), "state": internal.CondVal(state),
} }
for _, opt := range opts { for _, opt := range opts {
opt.setValue(v) opt.setValue(v)
@ -151,7 +161,7 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor
"grant_type": {"password"}, "grant_type": {"password"},
"username": {username}, "username": {username},
"password": {password}, "password": {password},
"scope": condVal(strings.Join(c.Scopes, " ")), "scope": internal.CondVal(strings.Join(c.Scopes, " ")),
}) })
} }
@ -169,51 +179,10 @@ func (c *Config) Exchange(ctx context.Context, code string) (*Token, error) {
return retrieveToken(ctx, c, url.Values{ return retrieveToken(ctx, c, url.Values{
"grant_type": {"authorization_code"}, "grant_type": {"authorization_code"},
"code": {code}, "code": {code},
"redirect_uri": condVal(c.RedirectURL), "redirect_uri": internal.CondVal(c.RedirectURL),
"scope": condVal(strings.Join(c.Scopes, " ")),
}) })
} }
// contextClientFunc is a func which tries to return an *http.Client
// given a Context value. If it returns an error, the search stops
// with that error. If it returns (nil, nil), the search continues
// down the list of registered funcs.
type contextClientFunc func(context.Context) (*http.Client, error)
var contextClientFuncs []contextClientFunc
func registerContextClientFunc(fn contextClientFunc) {
contextClientFuncs = append(contextClientFuncs, fn)
}
func contextClient(ctx context.Context) (*http.Client, error) {
for _, fn := range contextClientFuncs {
c, err := fn(ctx)
if err != nil {
return nil, err
}
if c != nil {
return c, nil
}
}
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
return hc, nil
}
return http.DefaultClient, nil
}
func contextTransport(ctx context.Context) http.RoundTripper {
hc, err := contextClient(ctx)
if err != nil {
// This is a rare error case (somebody using nil on App Engine),
// so I'd rather not everybody do an error check on this Client
// method. They can get the error that they're doing it wrong
// later, at client.Get/PostForm time.
return errorTransport{err}
}
return hc.Transport
}
// Client returns an HTTP client using the provided token. // Client returns an HTTP client using the provided token.
// The token will auto-refresh as necessary. The underlying // The token will auto-refresh as necessary. The underlying
// HTTP transport will be obtained using the provided context. // HTTP transport will be obtained using the provided context.
@ -299,177 +268,25 @@ func (s *reuseTokenSource) Token() (*Token, error) {
return t, nil return t, nil
} }
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) { // StaticTokenSource returns a TokenSource that always returns the same token.
hc, err := contextClient(ctx) // Because the provided token t is never refreshed, StaticTokenSource is only
if err != nil { // useful for tokens that never expire.
return nil, err func StaticTokenSource(t *Token) TokenSource {
} return staticTokenSource{t}
v.Set("client_id", c.ClientID)
bustedAuth := !providerAuthHeaderWorks(c.Endpoint.TokenURL)
if bustedAuth && c.ClientSecret != "" {
v.Set("client_secret", c.ClientSecret)
}
req, err := http.NewRequest("POST", c.Endpoint.TokenURL, strings.NewReader(v.Encode()))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if !bustedAuth {
req.SetBasicAuth(c.ClientID, c.ClientSecret)
}
r, err := hc.Do(req)
if err != nil {
return nil, err
}
defer r.Body.Close()
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
if err != nil {
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
}
if code := r.StatusCode; code < 200 || code > 299 {
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
}
var token *Token
content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
switch content {
case "application/x-www-form-urlencoded", "text/plain":
vals, err := url.ParseQuery(string(body))
if err != nil {
return nil, err
}
token = &Token{
AccessToken: vals.Get("access_token"),
TokenType: vals.Get("token_type"),
RefreshToken: vals.Get("refresh_token"),
raw: vals,
}
e := vals.Get("expires_in")
if e == "" {
// TODO(jbd): Facebook's OAuth2 implementation is broken and
// returns expires_in field in expires. Remove the fallback to expires,
// when Facebook fixes their implementation.
e = vals.Get("expires")
}
expires, _ := strconv.Atoi(e)
if expires != 0 {
token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
}
default:
var tj tokenJSON
if err = json.Unmarshal(body, &tj); err != nil {
return nil, err
}
token = &Token{
AccessToken: tj.AccessToken,
TokenType: tj.TokenType,
RefreshToken: tj.RefreshToken,
Expiry: tj.expiry(),
raw: make(map[string]interface{}),
}
json.Unmarshal(body, &token.raw) // no error checks for optional fields
}
// Don't overwrite `RefreshToken` with an empty value
// if this was a token refreshing request.
if token.RefreshToken == "" {
token.RefreshToken = v.Get("refresh_token")
}
return token, nil
} }
// tokenJSON is the struct representing the HTTP response from OAuth2 // staticTokenSource is a TokenSource that always returns the same Token.
// providers returning a token in JSON form. type staticTokenSource struct {
type tokenJSON struct { t *Token
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
RefreshToken string `json:"refresh_token"`
ExpiresIn expirationTime `json:"expires_in"` // at least PayPal returns string, while most return number
Expires expirationTime `json:"expires"` // broken Facebook spelling of expires_in
} }
func (e *tokenJSON) expiry() (t time.Time) { func (s staticTokenSource) Token() (*Token, error) {
if v := e.ExpiresIn; v != 0 { return s.t, nil
return time.Now().Add(time.Duration(v) * time.Second)
}
if v := e.Expires; v != 0 {
return time.Now().Add(time.Duration(v) * time.Second)
}
return
}
type expirationTime int32
func (e *expirationTime) UnmarshalJSON(b []byte) error {
var n json.Number
err := json.Unmarshal(b, &n)
if err != nil {
return err
}
i, err := n.Int64()
if err != nil {
return err
}
*e = expirationTime(i)
return nil
}
func condVal(v string) []string {
if v == "" {
return nil
}
return []string{v}
}
var brokenAuthHeaderProviders = []string{
"https://accounts.google.com/",
"https://www.googleapis.com/",
"https://github.com/",
"https://api.instagram.com/",
"https://www.douban.com/",
"https://api.dropbox.com/",
"https://api.soundcloud.com/",
"https://www.linkedin.com/",
"https://api.twitch.tv/",
"https://oauth.vk.com/",
"https://api.odnoklassniki.ru/",
"https://connect.stripe.com/",
"https://api.pushbullet.com/",
"https://oauth.sandbox.trainingpeaks.com/",
"https://oauth.trainingpeaks.com/",
"https://www.strava.com/oauth/",
}
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
// implements the OAuth2 spec correctly
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
// In summary:
// - Reddit only accepts client secret in the Authorization header
// - Dropbox accepts either it in URL param or Auth header, but not both.
// - Google only accepts URL param (not spec compliant?), not Auth header
// - Stripe only accepts client secret in Auth header with Bearer method, not Basic
func providerAuthHeaderWorks(tokenURL string) bool {
for _, s := range brokenAuthHeaderProviders {
if strings.HasPrefix(tokenURL, s) {
// Some sites fail to implement the OAuth2 spec fully.
return false
}
}
// Assume the provider implements the spec properly
// otherwise. We can add more exceptions as they're
// discovered. We will _not_ be adding configurable hooks
// to this package to let users select server bugs.
return true
} }
// HTTPClient is the context key to use with golang.org/x/net/context's // HTTPClient is the context key to use with golang.org/x/net/context's
// WithValue function to associate an *http.Client value with a context. // WithValue function to associate an *http.Client value with a context.
var HTTPClient contextKey var HTTPClient internal.ContextKey
// contextKey is just an empty struct. It exists so HTTPClient can be
// an immutable public variable with a unique type. It's immutable
// because nobody else can create a contextKey, being unexported.
type contextKey struct{}
// NewClient creates an *http.Client from a Context and TokenSource. // NewClient creates an *http.Client from a Context and TokenSource.
// The returned client is not valid beyond the lifetime of the context. // The returned client is not valid beyond the lifetime of the context.
@ -479,15 +296,15 @@ type contextKey struct{}
// packages. // packages.
func NewClient(ctx context.Context, src TokenSource) *http.Client { func NewClient(ctx context.Context, src TokenSource) *http.Client {
if src == nil { if src == nil {
c, err := contextClient(ctx) c, err := internal.ContextClient(ctx)
if err != nil { if err != nil {
return &http.Client{Transport: errorTransport{err}} return &http.Client{Transport: internal.ErrorTransport{Err: err}}
} }
return c return c
} }
return &http.Client{ return &http.Client{
Transport: &Transport{ Transport: &Transport{
Base: contextTransport(ctx), Base: internal.ContextTransport(ctx),
Source: ReuseTokenSource(nil, src), Source: ReuseTokenSource(nil, src),
}, },
} }

66
vendor/golang.org/x/oauth2/token.go generated vendored
View file

@ -1,4 +1,4 @@
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -7,7 +7,12 @@ package oauth2
import ( import (
"net/http" "net/http"
"net/url" "net/url"
"strconv"
"strings"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/oauth2/internal"
) )
// expiryDelta determines how earlier a token should be considered // expiryDelta determines how earlier a token should be considered
@ -50,6 +55,15 @@ type Token struct {
// Type returns t.TokenType if non-empty, else "Bearer". // Type returns t.TokenType if non-empty, else "Bearer".
func (t *Token) Type() string { func (t *Token) Type() string {
if strings.EqualFold(t.TokenType, "bearer") {
return "Bearer"
}
if strings.EqualFold(t.TokenType, "mac") {
return "MAC"
}
if strings.EqualFold(t.TokenType, "basic") {
return "Basic"
}
if t.TokenType != "" { if t.TokenType != "" {
return t.TokenType return t.TokenType
} }
@ -79,14 +93,28 @@ func (t *Token) WithExtra(extra interface{}) *Token {
// Extra fields are key-value pairs returned by the server as a // Extra fields are key-value pairs returned by the server as a
// part of the token retrieval response. // part of the token retrieval response.
func (t *Token) Extra(key string) interface{} { func (t *Token) Extra(key string) interface{} {
if vals, ok := t.raw.(url.Values); ok {
// TODO(jbd): Cast numeric values to int64 or float64.
return vals.Get(key)
}
if raw, ok := t.raw.(map[string]interface{}); ok { if raw, ok := t.raw.(map[string]interface{}); ok {
return raw[key] return raw[key]
} }
return nil
vals, ok := t.raw.(url.Values)
if !ok {
return nil
}
v := vals.Get(key)
switch s := strings.TrimSpace(v); strings.Count(s, ".") {
case 0: // Contains no "."; try to parse as int
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
return i
}
case 1: // Contains a single "."; try to parse as float
if f, err := strconv.ParseFloat(s, 64); err == nil {
return f
}
}
return v
} }
// expired reports whether the token is expired. // expired reports whether the token is expired.
@ -102,3 +130,29 @@ func (t *Token) expired() bool {
func (t *Token) Valid() bool { func (t *Token) Valid() bool {
return t != nil && t.AccessToken != "" && !t.expired() return t != nil && t.AccessToken != "" && !t.expired()
} }
// tokenFromInternal maps an *internal.Token struct into
// a *Token struct.
func tokenFromInternal(t *internal.Token) *Token {
if t == nil {
return nil
}
return &Token{
AccessToken: t.AccessToken,
TokenType: t.TokenType,
RefreshToken: t.RefreshToken,
Expiry: t.Expiry,
raw: t.Raw,
}
}
// retrieveToken takes a *Config and uses that to retrieve an *internal.Token.
// This token is then mapped from *internal.Token into an *oauth2.Token which is returned along
// with an error..
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v)
if err != nil {
return nil, err
}
return tokenFromInternal(tk), nil
}

View file

@ -1,4 +1,4 @@
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -130,9 +130,3 @@ func (r *onEOFReader) runFunc() {
r.fn = nil r.fn = nil
} }
} }
type errorTransport struct{ err error }
func (t errorTransport) RoundTrip(*http.Request) (*http.Response, error) {
return nil, t.err
}

View file

@ -35,7 +35,7 @@ import (
// A Caser may be stateful and should therefore not be shared between // A Caser may be stateful and should therefore not be shared between
// goroutines. // goroutines.
type Caser struct { type Caser struct {
t transform.SpanningTransformer t transform.Transformer
} }
// Bytes returns a new byte slice with the result of converting b to the case // Bytes returns a new byte slice with the result of converting b to the case
@ -56,17 +56,12 @@ func (c Caser) String(s string) string {
// Transform. // Transform.
func (c Caser) Reset() { c.t.Reset() } func (c Caser) Reset() { c.t.Reset() }
// Transform implements the transform.Transformer interface and transforms the // Transform implements the Transformer interface and transforms the given input
// given input to the case form implemented by c. // to the case form implemented by c.
func (c Caser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (c Caser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
return c.t.Transform(dst, src, atEOF) return c.t.Transform(dst, src, atEOF)
} }
// Span implements the transform.SpanningTransformer interface.
func (c Caser) Span(src []byte, atEOF bool) (n int, err error) {
return c.t.Span(src, atEOF)
}
// Upper returns a Caser for language-specific uppercasing. // Upper returns a Caser for language-specific uppercasing.
func Upper(t language.Tag, opts ...Option) Caser { func Upper(t language.Tag, opts ...Option) Caser {
return Caser{makeUpper(t, getOpts(opts...))} return Caser{makeUpper(t, getOpts(opts...))}
@ -95,13 +90,7 @@ func Fold(opts ...Option) Caser {
} }
// An Option is used to modify the behavior of a Caser. // An Option is used to modify the behavior of a Caser.
type Option func(o options) options type Option func(o *options)
// TODO: consider these options to take a boolean as well, like FinalSigma.
// The advantage of using this approach is that other providers of a lower-case
// algorithm could set different defaults by prefixing a user-provided slice
// of options with their own. This is handy, for instance, for the precis
// package which would override the default to not handle the Greek final sigma.
var ( var (
// NoLower disables the lowercasing of non-leading letters for a title // NoLower disables the lowercasing of non-leading letters for a title
@ -121,42 +110,20 @@ type options struct {
// TODO: segmenter, max ignorable, alternative versions, etc. // TODO: segmenter, max ignorable, alternative versions, etc.
ignoreFinalSigma bool noFinalSigma bool // Only used for testing.
} }
func getOpts(o ...Option) (res options) { func getOpts(o ...Option) (res options) {
for _, f := range o { for _, f := range o {
res = f(res) f(&res)
} }
return return
} }
func noLower(o options) options { func noLower(o *options) {
o.noLower = true o.noLower = true
return o
} }
func compact(o options) options { func compact(o *options) {
o.simple = true o.simple = true
return o
}
// HandleFinalSigma specifies whether the special handling of Greek final sigma
// should be enabled. Unicode prescribes handling the Greek final sigma for all
// locales, but standards like IDNA and PRECIS override this default.
func HandleFinalSigma(enable bool) Option {
if enable {
return handleFinalSigma
}
return ignoreFinalSigma
}
func ignoreFinalSigma(o options) options {
o.ignoreFinalSigma = true
return o
}
func handleFinalSigma(o options) options {
o.ignoreFinalSigma = false
return o
} }

View file

@ -4,7 +4,9 @@
package cases package cases
import "golang.org/x/text/transform" import (
"golang.org/x/text/transform"
)
// A context is used for iterating over source bytes, fetching case info and // A context is used for iterating over source bytes, fetching case info and
// writing to a destination buffer. // writing to a destination buffer.
@ -54,14 +56,6 @@ func (c *context) ret() (nDst, nSrc int, err error) {
return c.nDst, c.nSrc, transform.ErrShortSrc return c.nDst, c.nSrc, transform.ErrShortSrc
} }
// retSpan returns the return values for the Span method. It checks whether
// there were insufficient bytes in src to complete and introduces an error
// accordingly, if necessary.
func (c *context) retSpan() (n int, err error) {
_, nSrc, err := c.ret()
return nSrc, err
}
// checkpoint sets the return value buffer points for Transform to the current // checkpoint sets the return value buffer points for Transform to the current
// positions. // positions.
func (c *context) checkpoint() { func (c *context) checkpoint() {
@ -206,23 +200,6 @@ func lower(c *context) bool {
return c.copy() return c.copy()
} }
func isLower(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cLower {
return true
}
if c.info&exceptionBit == 0 {
c.err = transform.ErrEndOfSpan
return false
}
e := exceptions[c.info>>exceptionShift:]
if nLower := (e[1] >> lengthBits) & lengthMask; nLower != noChange {
c.err = transform.ErrEndOfSpan
return false
}
return true
}
// upper writes the uppercase version of the current rune to dst. // upper writes the uppercase version of the current rune to dst.
func upper(c *context) bool { func upper(c *context) bool {
ct := c.caseType() ct := c.caseType()
@ -249,29 +226,6 @@ func upper(c *context) bool {
return c.copy() return c.copy()
} }
// isUpper writes the isUppercase version of the current rune to dst.
func isUpper(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cUpper {
return true
}
if c.info&exceptionBit == 0 {
c.err = transform.ErrEndOfSpan
return false
}
e := exceptions[c.info>>exceptionShift:]
// Get length of first special case mapping.
n := (e[1] >> lengthBits) & lengthMask
if ct == cTitle {
n = e[1] & lengthMask
}
if n != noChange {
c.err = transform.ErrEndOfSpan
return false
}
return true
}
// title writes the title case version of the current rune to dst. // title writes the title case version of the current rune to dst.
func title(c *context) bool { func title(c *context) bool {
ct := c.caseType() ct := c.caseType()
@ -303,33 +257,6 @@ func title(c *context) bool {
return c.copy() return c.copy()
} }
// isTitle reports whether the current rune is in title case.
func isTitle(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cTitle {
return true
}
if c.info&exceptionBit == 0 {
if ct == cLower {
c.err = transform.ErrEndOfSpan
return false
}
return true
}
// Get the exception data.
e := exceptions[c.info>>exceptionShift:]
if nTitle := e[1] & lengthMask; nTitle != noChange {
c.err = transform.ErrEndOfSpan
return false
}
nFirst := (e[1] >> lengthBits) & lengthMask
if ct == cLower && nFirst != noChange {
c.err = transform.ErrEndOfSpan
return false
}
return true
}
// foldFull writes the foldFull version of the current rune to dst. // foldFull writes the foldFull version of the current rune to dst.
func foldFull(c *context) bool { func foldFull(c *context) bool {
if c.info&hasMappingMask == 0 { if c.info&hasMappingMask == 0 {
@ -352,25 +279,3 @@ func foldFull(c *context) bool {
} }
return c.writeString(e[2 : 2+n]) return c.writeString(e[2 : 2+n])
} }
// isFoldFull reports whether the current run is mapped to foldFull
func isFoldFull(c *context) bool {
if c.info&hasMappingMask == 0 {
return true
}
ct := c.caseType()
if c.info&exceptionBit == 0 {
if ct != cLower || c.info&inverseFoldBit != 0 {
c.err = transform.ErrEndOfSpan
return false
}
return true
}
e := exceptions[c.info>>exceptionShift:]
n := e[0] & lengthMask
if n == 0 && ct == cLower {
return true
}
c.err = transform.ErrEndOfSpan
return false
}

View file

@ -18,15 +18,7 @@ func (t *caseFolder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err
return c.ret() return c.ret()
} }
func (t *caseFolder) Span(src []byte, atEOF bool) (n int, err error) { func makeFold(o options) transform.Transformer {
c := context{src: src, atEOF: atEOF}
for c.next() && isFoldFull(&c) {
c.checkpoint()
}
return c.retSpan()
}
func makeFold(o options) transform.SpanningTransformer {
// TODO: Special case folding, through option Language, Special/Turkic, or // TODO: Special case folding, through option Language, Special/Turkic, or
// both. // both.
// TODO: Implement Compact options. // TODO: Implement Compact options.

View file

@ -76,7 +76,7 @@ type breakCategory int
const ( const (
breakBreak breakCategory = iota breakBreak breakCategory = iota
breakLetter breakLetter
breakMid breakIgnored
) )
// mapping returns the case mapping for the given case type. // mapping returns the case mapping for the given case type.
@ -162,14 +162,9 @@ func parseUCD() []runeInfo {
// We collapse the word breaking properties onto the categories we need. // We collapse the word breaking properties onto the categories we need.
switch p.String(1) { // TODO: officially we need to canonicalize. switch p.String(1) { // TODO: officially we need to canonicalize.
case "MidLetter", "MidNumLet", "Single_Quote": case "Format", "MidLetter", "MidNumLet", "Single_Quote":
ri.BreakCat = breakMid ri.BreakCat = breakIgnored
if !ri.CaseIgnorable { case "ALetter", "Hebrew_Letter", "Numeric", "Extend", "ExtendNumLet":
// finalSigma relies on the fact that all breakMid runes are
// also a Case_Ignorable. Revisit this code when this changes.
log.Fatalf("Rune %U, which has a break category mid, is not a case ignorable", ri)
}
case "ALetter", "Hebrew_Letter", "Numeric", "Extend", "ExtendNumLet", "Format", "ZWJ":
ri.BreakCat = breakLetter ri.BreakCat = breakLetter
} }
}) })
@ -245,11 +240,8 @@ func makeEntry(ri *runeInfo) {
case above: // Above case above: // Above
ccc = cccAbove ccc = cccAbove
} }
switch ri.BreakCat { if ri.BreakCat == breakBreak {
case breakBreak:
ccc = cccBreak ccc = cccBreak
case breakMid:
ri.entry |= isMidBit
} }
ri.entry |= ccc ri.entry |= ccc
@ -698,7 +690,7 @@ func genTablesTest() {
parse("auxiliary/WordBreakProperty.txt", func(p *ucd.Parser) { parse("auxiliary/WordBreakProperty.txt", func(p *ucd.Parser) {
switch p.String(1) { switch p.String(1) {
case "Extend", "Format", "MidLetter", "MidNumLet", "Single_Quote", case "Extend", "Format", "MidLetter", "MidNumLet", "Single_Quote",
"ALetter", "Hebrew_Letter", "Numeric", "ExtendNumLet", "ZWJ": "ALetter", "Hebrew_Letter", "Numeric", "ExtendNumLet":
notBreak[p.Rune(0)] = true notBreak[p.Rune(0)] = true
} }
}) })

View file

@ -26,7 +26,6 @@ package main
// Only 13..8 are used for XOR patterns. // Only 13..8 are used for XOR patterns.
// 7 inverseFold (fold to upper, not to lower) // 7 inverseFold (fold to upper, not to lower)
// 6 index: interpret the XOR pattern as an index // 6 index: interpret the XOR pattern as an index
// or isMid if case mode is cIgnorableUncased.
// 5..4 CCC: zero (normal or break), above or other // 5..4 CCC: zero (normal or break), above or other
// } // }
// 3 exception: interpret this value as an exception index // 3 exception: interpret this value as an exception index
@ -49,7 +48,6 @@ const (
ignorableValue = 0x0004 ignorableValue = 0x0004
inverseFoldBit = 1 << 7 inverseFoldBit = 1 << 7
isMidBit = 1 << 6
exceptionBit = 1 << 3 exceptionBit = 1 << 3
exceptionShift = 5 exceptionShift = 5
@ -59,7 +57,7 @@ const (
xorShift = 8 xorShift = 8
// There is no mapping if all xor bits and the exception bit are zero. // There is no mapping if all xor bits and the exception bit are zero.
hasMappingMask = 0xff80 | exceptionBit hasMappingMask = 0xffc0 | exceptionBit
) )
// The case mode bits encodes the case type of a rune. This includes uncased, // The case mode bits encodes the case type of a rune. This includes uncased,
@ -97,6 +95,10 @@ func (c info) isCaseIgnorable() bool {
return c&ignorableMask == ignorableValue return c&ignorableMask == ignorableValue
} }
func (c info) isCaseIgnorableAndNonBreakStarter() bool {
return c&(fullCasedMask|cccMask) == (ignorableValue | cccZero)
}
func (c info) isNotCasedAndNotCaseIgnorable() bool { func (c info) isNotCasedAndNotCaseIgnorable() bool {
return c&fullCasedMask == 0 return c&fullCasedMask == 0
} }
@ -105,10 +107,6 @@ func (c info) isCaseIgnorableAndNotCased() bool {
return c&fullCasedMask == cIgnorableUncased return c&fullCasedMask == cIgnorableUncased
} }
func (c info) isMid() bool {
return c&(fullCasedMask|isMidBit) == isMidBit|cIgnorableUncased
}
// The case mapping implementation will need to know about various Canonical // The case mapping implementation will need to know about various Canonical
// Combining Class (CCC) values. We encode two of these in the trie value: // Combining Class (CCC) values. We encode two of these in the trie value:
// cccZero (0) and cccAbove (230). If the value is cccOther, it means that // cccZero (0) and cccAbove (230). If the value is cccOther, it means that

View file

@ -1,61 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build icu
package cases
// Ideally these functions would be defined in a test file, but go test doesn't
// allow CGO in tests. The build tag should ensure either way that these
// functions will not end up in the package.
// TODO: Ensure that the correct ICU version is set.
/*
#cgo LDFLAGS: -licui18n.57 -licuuc.57
#include <stdlib.h>
#include <unicode/ustring.h>
#include <unicode/utypes.h>
#include <unicode/localpointer.h>
#include <unicode/ucasemap.h>
*/
import "C"
import "unsafe"
func doICU(tag, caser, input string) string {
err := C.UErrorCode(0)
loc := C.CString(tag)
cm := C.ucasemap_open(loc, C.uint32_t(0), &err)
buf := make([]byte, len(input)*4)
dst := (*C.char)(unsafe.Pointer(&buf[0]))
src := C.CString(input)
cn := C.int32_t(0)
switch caser {
case "fold":
cn = C.ucasemap_utf8FoldCase(cm,
dst, C.int32_t(len(buf)),
src, C.int32_t(len(input)),
&err)
case "lower":
cn = C.ucasemap_utf8ToLower(cm,
dst, C.int32_t(len(buf)),
src, C.int32_t(len(input)),
&err)
case "upper":
cn = C.ucasemap_utf8ToUpper(cm,
dst, C.int32_t(len(buf)),
src, C.int32_t(len(input)),
&err)
case "title":
cn = C.ucasemap_utf8ToTitle(cm,
dst, C.int32_t(len(buf)),
src, C.int32_t(len(input)),
&err)
}
return string(buf[:cn])
}

View file

@ -28,6 +28,9 @@ func (c info) cccType() info {
// only makes sense, though, if the performance and/or space penalty of using // only makes sense, though, if the performance and/or space penalty of using
// the generic breaker is big. Extra data will only be needed for non-cased // the generic breaker is big. Extra data will only be needed for non-cased
// runes, which means there are sufficient bits left in the caseType. // runes, which means there are sufficient bits left in the caseType.
// Also note that the standard breaking algorithm doesn't always make sense
// for title casing. For example, a4a -> A4a, but a"4a -> A"4A (where " stands
// for modifier \u0308).
// ICU prohibits breaking in such cases as well. // ICU prohibits breaking in such cases as well.
// For the purpose of title casing we use an approximation of the Unicode Word // For the purpose of title casing we use an approximation of the Unicode Word
@ -38,19 +41,17 @@ func (c info) cccType() info {
// categories, with associated rules: // categories, with associated rules:
// //
// 1) Letter: // 1) Letter:
// ALetter, Hebrew_Letter, Numeric, ExtendNumLet, Extend, Format_FE, ZWJ. // ALetter, Hebrew_Letter, Numeric, ExtendNumLet, Extend.
// Rule: Never break between consecutive runes of this category. // Rule: Never break between consecutive runes of this category.
// //
// 2) Mid: // 2) Mid:
// MidLetter, MidNumLet, Single_Quote. // Format, MidLetter, MidNumLet, Single_Quote.
// (Cf. case-ignorable: MidLetter, MidNumLet, Single_Quote or cat is Mn, // (Cf. case-ignorable: MidLetter, MidNumLet or cat is Mn, Me, Cf, Lm or Sk).
// Me, Cf, Lm or Sk).
// Rule: Don't break between Letter and Mid, but break between two Mids. // Rule: Don't break between Letter and Mid, but break between two Mids.
// //
// 3) Break: // 3) Break:
// Any other category: NewLine, MidNum, CR, LF, Double_Quote, Katakana, and // Any other category, including NewLine, CR, LF and Double_Quote. These
// Other. // categories should always result in a break between two cased letters.
// These categories should always result in a break between two cased letters.
// Rule: Always break. // Rule: Always break.
// //
// Note 1: the Katakana and MidNum categories can, in esoteric cases, result in // Note 1: the Katakana and MidNum categories can, in esoteric cases, result in

383
vendor/golang.org/x/text/cases/map.go generated vendored
View file

@ -13,7 +13,6 @@ import (
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
"golang.org/x/text/internal"
"golang.org/x/text/language" "golang.org/x/text/language"
"golang.org/x/text/transform" "golang.org/x/text/transform"
"golang.org/x/text/unicode/norm" "golang.org/x/text/unicode/norm"
@ -25,11 +24,6 @@ import (
// dst so far won't need changing as we see more source bytes. // dst so far won't need changing as we see more source bytes.
type mapFunc func(*context) bool type mapFunc func(*context) bool
// A spanFunc takes a context set to the current rune and returns whether this
// rune would be altered when written to the output. It may advance the context
// to the next rune. It returns whether a checkpoint is possible.
type spanFunc func(*context) bool
// maxIgnorable defines the maximum number of ignorables to consider for // maxIgnorable defines the maximum number of ignorables to consider for
// lookahead operations. // lookahead operations.
const maxIgnorable = 30 const maxIgnorable = 30
@ -42,12 +36,12 @@ func init() {
for _, s := range strings.Split(supported, " ") { for _, s := range strings.Split(supported, " ") {
tags = append(tags, language.MustParse(s)) tags = append(tags, language.MustParse(s))
} }
matcher = internal.NewInheritanceMatcher(tags) matcher = language.NewMatcher(tags)
Supported = language.NewCoverage(tags) Supported = language.NewCoverage(tags)
} }
var ( var (
matcher *internal.InheritanceMatcher matcher language.Matcher
Supported language.Coverage Supported language.Coverage
@ -56,69 +50,56 @@ var (
// Some uppercase mappers are stateless, so we can precompute the // Some uppercase mappers are stateless, so we can precompute the
// Transformers and save a bit on runtime allocations. // Transformers and save a bit on runtime allocations.
upperFunc = []struct { upperFunc = []mapFunc{
upper mapFunc nil, // und
span spanFunc nil, // af
}{ aztrUpper(upper), // az
{nil, nil}, // und elUpper, // el
{nil, nil}, // af ltUpper(upper), // lt
{aztrUpper(upper), isUpper}, // az nil, // nl
{elUpper, noSpan}, // el aztrUpper(upper), // tr
{ltUpper(upper), noSpan}, // lt
{nil, nil}, // nl
{aztrUpper(upper), isUpper}, // tr
} }
undUpper transform.SpanningTransformer = &undUpperCaser{} undUpper transform.Transformer = &undUpperCaser{}
undLower transform.SpanningTransformer = &undLowerCaser{}
undLowerIgnoreSigma transform.SpanningTransformer = &undLowerIgnoreSigmaCaser{}
lowerFunc = []mapFunc{ lowerFunc = []mapFunc{
nil, // und lower, // und
nil, // af lower, // af
aztrLower, // az aztrLower, // az
nil, // el lower, // el
ltLower, // lt ltLower, // lt
nil, // nl lower, // nl
aztrLower, // tr aztrLower, // tr
} }
titleInfos = []struct { titleInfos = []struct {
title mapFunc title, lower mapFunc
lower mapFunc rewrite func(*context)
titleSpan spanFunc
rewrite func(*context)
}{ }{
{title, lower, isTitle, nil}, // und {title, lower, nil}, // und
{title, lower, isTitle, afnlRewrite}, // af {title, lower, afnlRewrite}, // af
{aztrUpper(title), aztrLower, isTitle, nil}, // az {aztrUpper(title), aztrLower, nil}, // az
{title, lower, isTitle, nil}, // el {title, lower, nil}, // el
{ltUpper(title), ltLower, noSpan, nil}, // lt {ltUpper(title), ltLower, nil}, // lt
{nlTitle, lower, nlTitleSpan, afnlRewrite}, // nl {nlTitle, lower, afnlRewrite}, // nl
{aztrUpper(title), aztrLower, isTitle, nil}, // tr {aztrUpper(title), aztrLower, nil}, // tr
} }
) )
func makeUpper(t language.Tag, o options) transform.SpanningTransformer { func makeUpper(t language.Tag, o options) transform.Transformer {
_, i, _ := matcher.Match(t) _, i, _ := matcher.Match(t)
f := upperFunc[i].upper f := upperFunc[i]
if f == nil { if f == nil {
return undUpper return undUpper
} }
return &simpleCaser{f: f, span: upperFunc[i].span} return &simpleCaser{f: f}
} }
func makeLower(t language.Tag, o options) transform.SpanningTransformer { func makeLower(t language.Tag, o options) transform.Transformer {
_, i, _ := matcher.Match(t) _, i, _ := matcher.Match(t)
f := lowerFunc[i] f := lowerFunc[i]
if f == nil { if o.noFinalSigma {
if o.ignoreFinalSigma { return &simpleCaser{f: f}
return undLowerIgnoreSigma
}
return undLower
}
if o.ignoreFinalSigma {
return &simpleCaser{f: f, span: isLower}
} }
return &lowerCaser{ return &lowerCaser{
first: f, first: f,
@ -126,28 +107,22 @@ func makeLower(t language.Tag, o options) transform.SpanningTransformer {
} }
} }
func makeTitle(t language.Tag, o options) transform.SpanningTransformer { func makeTitle(t language.Tag, o options) transform.Transformer {
_, i, _ := matcher.Match(t) _, i, _ := matcher.Match(t)
x := &titleInfos[i] x := &titleInfos[i]
lower := x.lower lower := x.lower
if o.noLower { if o.noLower {
lower = (*context).copy lower = (*context).copy
} else if !o.ignoreFinalSigma { } else if !o.noFinalSigma {
lower = finalSigma(lower) lower = finalSigma(lower)
} }
return &titleCaser{ return &titleCaser{
title: x.title, title: x.title,
lower: lower, lower: lower,
titleSpan: x.titleSpan, rewrite: x.rewrite,
rewrite: x.rewrite,
} }
} }
func noSpan(c *context) bool {
c.err = transform.ErrEndOfSpan
return false
}
// TODO: consider a similar special case for the fast majority lower case. This // TODO: consider a similar special case for the fast majority lower case. This
// is a bit more involved so will require some more precise benchmarking to // is a bit more involved so will require some more precise benchmarking to
// justify it. // justify it.
@ -157,7 +132,7 @@ type undUpperCaser struct{ transform.NopResetter }
// undUpperCaser implements the Transformer interface for doing an upper case // undUpperCaser implements the Transformer interface for doing an upper case
// mapping for the root locale (und). It eliminates the need for an allocation // mapping for the root locale (und). It eliminates the need for an allocation
// as it prevents escaping by not using function pointers. // as it prevents escaping by not using function pointers.
func (t undUpperCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (t *undUpperCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
c := context{dst: dst, src: src, atEOF: atEOF} c := context{dst: dst, src: src, atEOF: atEOF}
for c.next() { for c.next() {
upper(&c) upper(&c)
@ -166,117 +141,26 @@ func (t undUpperCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, e
return c.ret() return c.ret()
} }
func (t undUpperCaser) Span(src []byte, atEOF bool) (n int, err error) {
c := context{src: src, atEOF: atEOF}
for c.next() && isUpper(&c) {
c.checkpoint()
}
return c.retSpan()
}
// undLowerIgnoreSigmaCaser implements the Transformer interface for doing
// a lower case mapping for the root locale (und) ignoring final sigma
// handling. This casing algorithm is used in some performance-critical packages
// like secure/precis and x/net/http/idna, which warrants its special-casing.
type undLowerIgnoreSigmaCaser struct{ transform.NopResetter }
func (t undLowerIgnoreSigmaCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
c := context{dst: dst, src: src, atEOF: atEOF}
for c.next() && lower(&c) {
c.checkpoint()
}
return c.ret()
}
// Span implements a generic lower-casing. This is possible as isLower works
// for all lowercasing variants. All lowercase variants only vary in how they
// transform a non-lowercase letter. They will never change an already lowercase
// letter. In addition, there is no state.
func (t undLowerIgnoreSigmaCaser) Span(src []byte, atEOF bool) (n int, err error) {
c := context{src: src, atEOF: atEOF}
for c.next() && isLower(&c) {
c.checkpoint()
}
return c.retSpan()
}
type simpleCaser struct { type simpleCaser struct {
context context
f mapFunc f mapFunc
span spanFunc
} }
// simpleCaser implements the Transformer interface for doing a case operation // simpleCaser implements the Transformer interface for doing a case operation
// on a rune-by-rune basis. // on a rune-by-rune basis.
func (t *simpleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (t *simpleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
c := context{dst: dst, src: src, atEOF: atEOF} t.context = context{dst: dst, src: src, atEOF: atEOF}
for c.next() && t.f(&c) { c := &t.context
for c.next() && t.f(c) {
c.checkpoint() c.checkpoint()
} }
return c.ret() return c.ret()
} }
func (t *simpleCaser) Span(src []byte, atEOF bool) (n int, err error) {
c := context{src: src, atEOF: atEOF}
for c.next() && t.span(&c) {
c.checkpoint()
}
return c.retSpan()
}
// undLowerCaser implements the Transformer interface for doing a lower case
// mapping for the root locale (und) ignoring final sigma handling. This casing
// algorithm is used in some performance-critical packages like secure/precis
// and x/net/http/idna, which warrants its special-casing.
type undLowerCaser struct{ transform.NopResetter }
func (t undLowerCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
c := context{dst: dst, src: src, atEOF: atEOF}
for isInterWord := true; c.next(); {
if isInterWord {
if c.info.isCased() {
if !lower(&c) {
break
}
isInterWord = false
} else if !c.copy() {
break
}
} else {
if c.info.isNotCasedAndNotCaseIgnorable() {
if !c.copy() {
break
}
isInterWord = true
} else if !c.hasPrefix("Σ") {
if !lower(&c) {
break
}
} else if !finalSigmaBody(&c) {
break
}
}
c.checkpoint()
}
return c.ret()
}
func (t undLowerCaser) Span(src []byte, atEOF bool) (n int, err error) {
c := context{src: src, atEOF: atEOF}
for c.next() && isLower(&c) {
c.checkpoint()
}
return c.retSpan()
}
// lowerCaser implements the Transformer interface. The default Unicode lower // lowerCaser implements the Transformer interface. The default Unicode lower
// casing requires different treatment for the first and subsequent characters // casing requires different treatment for the first and subsequent characters
// of a word, most notably to handle the Greek final Sigma. // of a word, most notably to handle the Greek final Sigma.
type lowerCaser struct { type lowerCaser struct {
undLowerIgnoreSigmaCaser
context context
first, midWord mapFunc first, midWord mapFunc
@ -318,9 +202,7 @@ type titleCaser struct {
context context
// rune mappings used by the actual casing algorithms. // rune mappings used by the actual casing algorithms.
title mapFunc title, lower mapFunc
lower mapFunc
titleSpan spanFunc
rewrite func(*context) rewrite func(*context)
} }
@ -346,10 +228,10 @@ func (t *titleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err
t.rewrite(c) t.rewrite(c)
} }
wasMid := p.isMid() wasMid := p.isCaseIgnorableAndNonBreakStarter()
// Break out of this loop on failure to ensure we do not modify the // Break out of this loop on failure to ensure we do not modify the
// state incorrectly. // state incorrectly.
if p.isCased() { if p.isCased() && !p.isCaseIgnorableAndNotCased() {
if !c.isMidWord { if !c.isMidWord {
if !t.title(c) { if !t.title(c) {
break break
@ -360,139 +242,71 @@ func (t *titleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err
} }
} else if !c.copy() { } else if !c.copy() {
break break
} else if p.isBreak() { }
// TODO: make this an "else if" if we can prove that no rune that does
// not match the first condition of the if statement can be a break.
if p.isBreak() {
c.isMidWord = false c.isMidWord = false
} }
// As we save the state of the transformer, it is safe to call // As we save the state of the transformer, it is safe to call
// checkpoint after any successful write. // checkpoint after any successful write.
if !(c.isMidWord && wasMid) { c.checkpoint()
c.checkpoint()
}
if !c.next() { if !c.next() {
break break
} }
if wasMid && c.info.isMid() { if wasMid && c.info.isCaseIgnorableAndNonBreakStarter() {
c.isMidWord = false c.isMidWord = false
} }
} }
return c.ret() return c.ret()
} }
func (t *titleCaser) Span(src []byte, atEOF bool) (n int, err error) {
t.context = context{src: src, atEOF: atEOF, isMidWord: t.isMidWord}
c := &t.context
if !c.next() {
return c.retSpan()
}
for {
p := c.info
if t.rewrite != nil {
t.rewrite(c)
}
wasMid := p.isMid()
// Break out of this loop on failure to ensure we do not modify the
// state incorrectly.
if p.isCased() {
if !c.isMidWord {
if !t.titleSpan(c) {
break
}
c.isMidWord = true
} else if !isLower(c) {
break
}
} else if p.isBreak() {
c.isMidWord = false
}
// As we save the state of the transformer, it is safe to call
// checkpoint after any successful write.
if !(c.isMidWord && wasMid) {
c.checkpoint()
}
if !c.next() {
break
}
if wasMid && c.info.isMid() {
c.isMidWord = false
}
}
return c.retSpan()
}
// finalSigma adds Greek final Sigma handing to another casing function. It // finalSigma adds Greek final Sigma handing to another casing function. It
// determines whether a lowercased sigma should be σ or ς, by looking ahead for // determines whether a lowercased sigma should be σ or ς, by looking ahead for
// case-ignorables and a cased letters. // case-ignorables and a cased letters.
func finalSigma(f mapFunc) mapFunc { func finalSigma(f mapFunc) mapFunc {
return func(c *context) bool { return func(c *context) bool {
// ::NFD();
// # 03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA
// Σ } [:case-ignorable:]* [:cased:] → σ;
// [:cased:] [:case-ignorable:]* { Σ → ς;
// ::Any-Lower;
// ::NFC();
if !c.hasPrefix("Σ") { if !c.hasPrefix("Σ") {
return f(c) return f(c)
} }
return finalSigmaBody(c)
}
}
func finalSigmaBody(c *context) bool { p := c.pDst
// Current rune must be ∑. c.writeString("ς")
// We need to do one more iteration after maxIgnorable, as a cased
// ::NFD(); // letter is not an ignorable and may modify the result.
// # 03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA for i := 0; i < maxIgnorable+1; i++ {
// Σ } [:case-ignorable:]* [:cased:] → σ; if !c.next() {
// [:cased:] [:case-ignorable:]* { Σ → ς; return false
// ::Any-Lower;
// ::NFC();
p := c.pDst
c.writeString("ς")
// TODO: we should do this here, but right now this will never have an
// effect as this is called when the prefix is Sigma, whereas Dutch and
// Afrikaans only test for an apostrophe.
//
// if t.rewrite != nil {
// t.rewrite(c)
// }
// We need to do one more iteration after maxIgnorable, as a cased
// letter is not an ignorable and may modify the result.
wasMid := false
for i := 0; i < maxIgnorable+1; i++ {
if !c.next() {
return false
}
if !c.info.isCaseIgnorable() {
// All Midword runes are also case ignorable, so we are
// guaranteed to have a letter or word break here. As we are
// unreading the run, there is no need to unset c.isMidWord;
// the title caser will handle this.
if c.info.isCased() {
// p+1 is guaranteed to be in bounds: if writing ς was
// successful, p+1 will contain the second byte of ς. If not,
// this function will have returned after c.next returned false.
c.dst[p+1]++ // ς → σ
} }
c.unreadRune() if !c.info.isCaseIgnorable() {
return true if c.info.isCased() {
// p+1 is guaranteed to be in bounds: if writing ς was
// successful, p+1 will contain the second byte of ς. If not,
// this function will have returned after c.next returned false.
c.dst[p+1]++ // ς → σ
}
c.unreadRune()
return true
}
// A case ignorable may also introduce a word break, so we may need
// to continue searching even after detecting a break.
c.isMidWord = c.isMidWord && !c.info.isBreak()
c.copy()
} }
// A case ignorable may also introduce a word break, so we may need return true
// to continue searching even after detecting a break.
isMid := c.info.isMid()
if (wasMid && isMid) || c.info.isBreak() {
c.isMidWord = false
}
wasMid = isMid
c.copy()
} }
return true
} }
// finalSigmaSpan would be the same as isLower.
// elUpper implements Greek upper casing, which entails removing a predefined // elUpper implements Greek upper casing, which entails removing a predefined
// set of non-blocked modifiers. Note that these accents should not be removed // set of non-blocked modifiers. Note that these accents should not be removed
// for title casing! // for title casing!
@ -562,8 +376,6 @@ func elUpper(c *context) bool {
return i == maxIgnorable return i == maxIgnorable
} }
// TODO: implement elUpperSpan (low-priority: complex and infrequent).
func ltLower(c *context) bool { func ltLower(c *context) bool {
// From CLDR: // From CLDR:
// # Introduce an explicit dot above when lowercasing capital I's and J's // # Introduce an explicit dot above when lowercasing capital I's and J's
@ -578,10 +390,10 @@ func ltLower(c *context) bool {
// ::NFD(); // ::NFD();
// I } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → i \u0307; // I } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → i \u0307;
// J } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → j \u0307; // J } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → j \u0307;
// I \u0328 (Į) } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → i \u0328 \u0307; // Į } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → į \u0307;
// I \u0300 (Ì) → i \u0307 \u0300; // Ì → i \u0307 \u0300;
// I \u0301 (Í) → i \u0307 \u0301; // Í → i \u0307 \u0301;
// I \u0303 (Ĩ) → i \u0307 \u0303; // Ĩ → i \u0307 \u0303;
// ::Any-Lower(); // ::Any-Lower();
// ::NFC(); // ::NFC();
@ -633,16 +445,9 @@ func ltLower(c *context) bool {
return i == maxIgnorable return i == maxIgnorable
} }
// ltLowerSpan would be the same as isLower.
func ltUpper(f mapFunc) mapFunc { func ltUpper(f mapFunc) mapFunc {
return func(c *context) bool { return func(c *context) bool {
// Unicode:
// 0307; 0307; ; ; lt After_Soft_Dotted; # COMBINING DOT ABOVE
//
// From CLDR: // From CLDR:
// # Remove \u0307 following soft-dotteds (i, j, and the like), with possible
// # intervening non-230 marks.
// ::NFD(); // ::NFD();
// [:Soft_Dotted:] [^[:ccc=Not_Reordered:][:ccc=Above:]]* { \u0307 → ; // [:Soft_Dotted:] [^[:ccc=Not_Reordered:][:ccc=Above:]]* { \u0307 → ;
// ::Any-Upper(); // ::Any-Upper();
@ -706,8 +511,6 @@ func ltUpper(f mapFunc) mapFunc {
} }
} }
// TODO: implement ltUpperSpan (low priority: complex and infrequent).
func aztrUpper(f mapFunc) mapFunc { func aztrUpper(f mapFunc) mapFunc {
return func(c *context) bool { return func(c *context) bool {
// i→İ; // i→İ;
@ -768,8 +571,6 @@ Loop:
return c.writeString("ı") && c.writeBytes(c.src[start:c.pSrc+c.sz]) && done return c.writeString("ı") && c.writeBytes(c.src[start:c.pSrc+c.sz]) && done
} }
// aztrLowerSpan would be the same as isLower.
func nlTitle(c *context) bool { func nlTitle(c *context) bool {
// From CLDR: // From CLDR:
// # Special titlecasing for Dutch initial "ij". // # Special titlecasing for Dutch initial "ij".
@ -790,24 +591,6 @@ func nlTitle(c *context) bool {
return true return true
} }
func nlTitleSpan(c *context) bool {
// From CLDR:
// # Special titlecasing for Dutch initial "ij".
// ::Any-Title();
// # Fix up Ij at the beginning of a "word" (per Any-Title, notUAX #29)
// [:^WB=ALetter:] [:WB=Extend:]* [[:WB=MidLetter:][:WB=MidNumLet:]]? { Ij } → IJ ;
if c.src[c.pSrc] != 'I' {
return isTitle(c)
}
if !c.next() || c.src[c.pSrc] == 'j' {
return false
}
if c.src[c.pSrc] != 'J' {
c.unreadRune()
}
return true
}
// Not part of CLDR, but see http://unicode.org/cldr/trac/ticket/7078. // Not part of CLDR, but see http://unicode.org/cldr/trac/ticket/7078.
func afnlRewrite(c *context) { func afnlRewrite(c *context) {
if c.hasPrefix("'") || c.hasPrefix("") { if c.hasPrefix("'") || c.hasPrefix("") {

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,6 @@ package cases
// Only 13..8 are used for XOR patterns. // Only 13..8 are used for XOR patterns.
// 7 inverseFold (fold to upper, not to lower) // 7 inverseFold (fold to upper, not to lower)
// 6 index: interpret the XOR pattern as an index // 6 index: interpret the XOR pattern as an index
// or isMid if case mode is cIgnorableUncased.
// 5..4 CCC: zero (normal or break), above or other // 5..4 CCC: zero (normal or break), above or other
// } // }
// 3 exception: interpret this value as an exception index // 3 exception: interpret this value as an exception index
@ -45,7 +44,6 @@ const (
ignorableValue = 0x0004 ignorableValue = 0x0004
inverseFoldBit = 1 << 7 inverseFoldBit = 1 << 7
isMidBit = 1 << 6
exceptionBit = 1 << 3 exceptionBit = 1 << 3
exceptionShift = 5 exceptionShift = 5
@ -55,7 +53,7 @@ const (
xorShift = 8 xorShift = 8
// There is no mapping if all xor bits and the exception bit are zero. // There is no mapping if all xor bits and the exception bit are zero.
hasMappingMask = 0xff80 | exceptionBit hasMappingMask = 0xffc0 | exceptionBit
) )
// The case mode bits encodes the case type of a rune. This includes uncased, // The case mode bits encodes the case type of a rune. This includes uncased,
@ -93,6 +91,10 @@ func (c info) isCaseIgnorable() bool {
return c&ignorableMask == ignorableValue return c&ignorableMask == ignorableValue
} }
func (c info) isCaseIgnorableAndNonBreakStarter() bool {
return c&(fullCasedMask|cccMask) == (ignorableValue | cccZero)
}
func (c info) isNotCasedAndNotCaseIgnorable() bool { func (c info) isNotCasedAndNotCaseIgnorable() bool {
return c&fullCasedMask == 0 return c&fullCasedMask == 0
} }
@ -101,10 +103,6 @@ func (c info) isCaseIgnorableAndNotCased() bool {
return c&fullCasedMask == cIgnorableUncased return c&fullCasedMask == cIgnorableUncased
} }
func (c info) isMid() bool {
return c&(fullCasedMask|isMidBit) == isMidBit|cIgnorableUncased
}
// The case mapping implementation will need to know about various Canonical // The case mapping implementation will need to know about various Canonical
// Combining Class (CCC) values. We encode two of these in the trie value: // Combining Class (CCC) values. We encode two of these in the trie value:
// cccZero (0) and cccAbove (230). If the value is cccOther, it means that // cccZero (0) and cccAbove (230). If the value is cccOther, it means that

77
vendor/golang.org/x/text/gen.go generated vendored
View file

@ -12,8 +12,6 @@ import (
"bytes" "bytes"
"flag" "flag"
"fmt" "fmt"
"go/build"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -28,7 +26,6 @@ import (
var ( var (
verbose = flag.Bool("v", false, "verbose output") verbose = flag.Bool("v", false, "verbose output")
force = flag.Bool("force", false, "ignore failing dependencies") force = flag.Bool("force", false, "ignore failing dependencies")
doCore = flag.Bool("core", false, "force an update to core")
excludeList = flag.String("exclude", "", excludeList = flag.String("exclude", "",
"comma-separated list of packages to exclude") "comma-separated list of packages to exclude")
@ -64,7 +61,6 @@ func main() {
// variable. This will prevent duplicate downloads and also will enable long // variable. This will prevent duplicate downloads and also will enable long
// tests, which really need to be run after each generated package. // tests, which really need to be run after each generated package.
updateCore := *doCore
if gen.UnicodeVersion() != unicode.Version { if gen.UnicodeVersion() != unicode.Version {
fmt.Printf("Requested Unicode version %s; core unicode version is %s.\n", fmt.Printf("Requested Unicode version %s; core unicode version is %s.\n",
gen.UnicodeVersion(), gen.UnicodeVersion(),
@ -76,44 +72,24 @@ func main() {
if gen.UnicodeVersion() < unicode.Version && !*force { if gen.UnicodeVersion() < unicode.Version && !*force {
os.Exit(2) os.Exit(2)
} }
updateCore = true
} }
var unicode = &dependency{}
if updateCore {
fmt.Printf("Updating core to version %s...\n", gen.UnicodeVersion())
unicode = generate("unicode")
// Test some users of the unicode packages, especially the ones that
// keep a mirrored table. These may need to be corrected by hand.
generate("regexp", unicode)
generate("strconv", unicode) // mimics Unicode table
generate("strings", unicode)
generate("testing", unicode) // mimics Unicode table
}
var ( var (
cldr = generate("./unicode/cldr", unicode) cldr = generate("unicode/cldr")
language = generate("./language", cldr) language = generate("language", cldr)
internal = generate("./internal", unicode, language) internal = generate("internal", language)
norm = generate("./unicode/norm", unicode) norm = generate("unicode/norm")
rangetable = generate("./unicode/rangetable", unicode) rangetable = generate("unicode/rangetable")
cases = generate("./cases", unicode, norm, language, rangetable) cases = generate("cases", norm, language, rangetable)
width = generate("./width", unicode) width = generate("width")
bidi = generate("./unicode/bidi", unicode, norm, rangetable) bidi = generate("unicode/bidi", norm, rangetable)
_ = generate("./secure/precis", unicode, norm, rangetable, cases, width, bidi) _ = generate("secure/precis", norm, rangetable, cases, width, bidi)
_ = generate("./encoding/htmlindex", unicode, language) _ = generate("encoding/htmlindex", language)
_ = generate("./currency", unicode, cldr, language, internal) _ = generate("currency", cldr, language, internal)
_ = generate("./internal/number", unicode, cldr, language, internal) _ = generate("internal/number", cldr, language, internal)
_ = generate("./language/display", unicode, cldr, language, internal) _ = generate("language/display", cldr, language)
_ = generate("./collate", unicode, norm, cldr, language, rangetable) _ = generate("collate", norm, cldr, language, rangetable)
_ = generate("./search", unicode, norm, cldr, language, rangetable) _ = generate("search", norm, cldr, language, rangetable)
) )
if updateCore {
copyVendored()
generate("vendor/golang_org/x/net/idna", unicode, norm, width, cases)
}
all.Wait() all.Wait()
if hasErrors { if hasErrors {
@ -157,7 +133,7 @@ func generate(pkg string, deps ...*dependency) *dependency {
if *verbose { if *verbose {
args = append(args, "-v") args = append(args, "-v")
} }
args = append(args, pkg) args = append(args, "./"+pkg)
cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...) cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
w := &bytes.Buffer{} w := &bytes.Buffer{}
cmd.Stderr = w cmd.Stderr = w
@ -187,27 +163,6 @@ func generate(pkg string, deps ...*dependency) *dependency {
return &wg return &wg
} }
func copyVendored() {
// Copy the vendored files. Some more may need to be copied in by hand.
dir := filepath.Join(build.Default.GOROOT, "src/vendor/golang_org/x/text")
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
b, err := ioutil.ReadFile(path[len(dir)+1:])
if err != nil {
return err
}
vprintf("=== COPY %s\n", path)
b = bytes.Replace(b, []byte("golang.org"), []byte("golang_org"), -1)
return ioutil.WriteFile(path, b, 0666)
})
if err != nil {
fmt.Println("Copying vendored files failed:", err)
os.Exit(1)
}
}
func contains(a []string, s string) bool { func contains(a []string, s string) bool {
for _, e := range a { for _, e := range a {
if s == e { if s == e {

View file

@ -1,52 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
import (
"log"
"golang.org/x/text/internal/gen"
"golang.org/x/text/language"
"golang.org/x/text/unicode/cldr"
)
func main() {
r := gen.OpenCLDRCoreZip()
defer r.Close()
d := &cldr.Decoder{}
data, err := d.DecodeZip(r)
if err != nil {
log.Fatalf("DecodeZip: %v", err)
}
w := gen.NewCodeWriter()
defer w.WriteGoFile("tables.go", "internal")
// Create parents table.
parents := make([]uint16, language.NumCompactTags)
for _, loc := range data.Locales() {
tag := language.MustParse(loc)
index, ok := language.CompactIndex(tag)
if !ok {
continue
}
parentIndex := 0 // und
for p := tag.Parent(); p != language.Und; p = p.Parent() {
if x, ok := language.CompactIndex(p); ok {
parentIndex = x
break
}
}
parents[index] = uint16(parentIndex)
}
w.WriteComment(`
Parent maps a compact index of a tag to the compact index of the parent of
this tag.`)
w.WriteVar("Parent", parents)
}

View file

@ -1,51 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run gen.go
// Package internal contains non-exported functionality that are used by
// packages in the text repository.
package internal // import "golang.org/x/text/internal"
import (
"sort"
"golang.org/x/text/language"
)
// SortTags sorts tags in place.
func SortTags(tags []language.Tag) {
sort.Sort(sorter(tags))
}
type sorter []language.Tag
func (s sorter) Len() int {
return len(s)
}
func (s sorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s sorter) Less(i, j int) bool {
return s[i].String() < s[j].String()
}
// UniqueTags sorts and filters duplicate tags in place and returns a slice with
// only unique tags.
func UniqueTags(tags []language.Tag) []language.Tag {
if len(tags) <= 1 {
return tags
}
SortTags(tags)
k := 0
for i := 1; i < len(tags); i++ {
if tags[k].String() < tags[i].String() {
k++
tags[k] = tags[i]
}
}
return tags[:k+1]
}

View file

@ -1,67 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package internal
// This file contains matchers that implement CLDR inheritance.
//
// See http://unicode.org/reports/tr35/#Locale_Inheritance.
//
// Some of the inheritance described in this document is already handled by
// the cldr package.
import (
"golang.org/x/text/language"
)
// TODO: consider if (some of the) matching algorithm needs to be public after
// getting some feel about what is generic and what is specific.
// NewInheritanceMatcher returns a matcher that matches based on the inheritance
// chain.
//
// The matcher uses canonicalization and the parent relationship to find a
// match. The resulting match will always be either Und or a language with the
// same language and script as the requested language. It will not match
// languages for which there is understood to be mutual or one-directional
// intelligibility.
//
// A Match will indicate an Exact match if the language matches after
// canonicalization and High if the matched tag is a parent.
func NewInheritanceMatcher(t []language.Tag) *InheritanceMatcher {
tags := &InheritanceMatcher{make(map[language.Tag]int)}
for i, tag := range t {
ct, err := language.All.Canonicalize(tag)
if err != nil {
ct = tag
}
tags.index[ct] = i
}
return tags
}
type InheritanceMatcher struct {
index map[language.Tag]int
}
func (m InheritanceMatcher) Match(want ...language.Tag) (language.Tag, int, language.Confidence) {
for _, t := range want {
ct, err := language.All.Canonicalize(t)
if err != nil {
ct = t
}
conf := language.Exact
for {
if index, ok := m.index[ct]; ok {
return ct, index, conf
}
if ct == language.Und {
break
}
ct = ct.Parent()
conf = language.High
}
}
return language.Und, 0, language.No
}

View file

@ -1,116 +0,0 @@
// This file was generated by go generate; DO NOT EDIT
package internal
// Parent maps a compact index of a tag to the compact index of the parent of
// this tag.
var Parent = []uint16{ // 752 elements
// Entry 0 - 3F
0x0000, 0x0053, 0x00e5, 0x0000, 0x0003, 0x0003, 0x0000, 0x0006,
0x0000, 0x0008, 0x0000, 0x000a, 0x0000, 0x000c, 0x000c, 0x000c,
0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c,
0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c,
0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c,
0x000c, 0x0000, 0x0000, 0x002a, 0x0000, 0x002c, 0x0000, 0x002e,
0x0000, 0x0000, 0x0031, 0x0030, 0x0030, 0x0000, 0x0035, 0x0000,
0x0037, 0x0000, 0x0039, 0x0000, 0x003b, 0x0000, 0x003d, 0x0000,
// Entry 40 - 7F
0x0000, 0x0040, 0x0000, 0x0042, 0x0042, 0x0000, 0x0045, 0x0045,
0x0000, 0x0048, 0x0000, 0x004a, 0x0000, 0x0000, 0x004d, 0x004c,
0x004c, 0x0000, 0x0051, 0x0051, 0x0051, 0x0051, 0x0000, 0x0056,
0x0000, 0x0058, 0x0000, 0x005a, 0x0000, 0x005c, 0x005c, 0x0000,
0x005f, 0x0000, 0x0061, 0x0000, 0x0063, 0x0000, 0x0065, 0x0065,
0x0000, 0x0068, 0x0000, 0x006a, 0x006a, 0x006a, 0x006a, 0x006a,
0x006a, 0x006a, 0x0000, 0x0072, 0x0000, 0x0074, 0x0000, 0x0076,
0x0000, 0x0000, 0x0079, 0x0000, 0x007b, 0x0000, 0x007d, 0x0000,
// Entry 80 - BF
0x007f, 0x007f, 0x0000, 0x0082, 0x0082, 0x0000, 0x0085, 0x0086,
0x0086, 0x0086, 0x0085, 0x0087, 0x0086, 0x0086, 0x0086, 0x0085,
0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0087, 0x0086,
0x0086, 0x0086, 0x0086, 0x0087, 0x0086, 0x0087, 0x0086, 0x0086,
0x0087, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086,
0x0086, 0x0086, 0x0085, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086,
0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086,
0x0086, 0x0086, 0x0086, 0x0086, 0x0085, 0x0086, 0x0085, 0x0086,
// Entry C0 - FF
0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0087,
0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0085,
0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0087, 0x0086, 0x0086,
0x0087, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086,
0x0086, 0x0086, 0x0086, 0x0086, 0x0085, 0x0085, 0x0086, 0x0086,
0x0085, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0000, 0x00ee,
0x0000, 0x00f0, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f1,
0x00f1, 0x00f1, 0x00f0, 0x00f1, 0x00f0, 0x00f0, 0x00f1, 0x00f1,
// Entry 100 - 13F
0x00f0, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f0, 0x00f1, 0x00f1,
0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x0000, 0x010c, 0x0000, 0x010e,
0x0000, 0x0110, 0x0000, 0x0112, 0x0112, 0x0000, 0x0115, 0x0115,
0x0115, 0x0115, 0x0000, 0x011a, 0x0000, 0x011c, 0x0000, 0x011e,
0x011e, 0x0000, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
// Entry 140 - 17F
0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
0x0000, 0x0150, 0x0000, 0x0152, 0x0000, 0x0154, 0x0000, 0x0156,
0x0000, 0x0158, 0x0000, 0x015a, 0x015a, 0x015a, 0x0000, 0x015e,
0x0000, 0x0000, 0x0161, 0x0000, 0x0163, 0x0000, 0x0165, 0x0165,
0x0165, 0x0000, 0x0169, 0x0000, 0x016b, 0x0000, 0x016d, 0x0000,
0x016f, 0x016f, 0x0000, 0x0172, 0x0000, 0x0174, 0x0000, 0x0176,
0x0000, 0x0178, 0x0000, 0x017a, 0x0000, 0x017c, 0x0000, 0x017e,
// Entry 180 - 1BF
0x0000, 0x0180, 0x0180, 0x0180, 0x0000, 0x0000, 0x0185, 0x0000,
0x0000, 0x0188, 0x0000, 0x018a, 0x0000, 0x0000, 0x018d, 0x0000,
0x018f, 0x0000, 0x0000, 0x0192, 0x0000, 0x0000, 0x0195, 0x0000,
0x0197, 0x0000, 0x0199, 0x0000, 0x019b, 0x0000, 0x019d, 0x0000,
0x019f, 0x0000, 0x01a1, 0x0000, 0x01a3, 0x0000, 0x01a5, 0x0000,
0x01a7, 0x0000, 0x01a9, 0x01a9, 0x0000, 0x01ac, 0x0000, 0x01ae,
0x0000, 0x01b0, 0x0000, 0x01b2, 0x0000, 0x01b4, 0x0000, 0x0000,
0x01b7, 0x0000, 0x01b9, 0x0000, 0x01bb, 0x0000, 0x01bd, 0x0000,
// Entry 1C0 - 1FF
0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x01c3, 0x01c3, 0x01c3,
0x0000, 0x01c8, 0x0000, 0x01ca, 0x01ca, 0x0000, 0x01cd, 0x0000,
0x01cf, 0x0000, 0x01d1, 0x0000, 0x01d3, 0x0000, 0x01d5, 0x0000,
0x01d7, 0x01d7, 0x0000, 0x01da, 0x0000, 0x01dc, 0x0000, 0x01de,
0x0000, 0x01e0, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6,
0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x01ec, 0x01ec,
0x0000, 0x01f0, 0x0000, 0x01f2, 0x0000, 0x01f4, 0x0000, 0x01f6,
0x0000, 0x0000, 0x01f9, 0x0000, 0x01fb, 0x01fb, 0x0000, 0x01fe,
// Entry 200 - 23F
0x0000, 0x0200, 0x0200, 0x0000, 0x0203, 0x0203, 0x0000, 0x0206,
0x0206, 0x0206, 0x0206, 0x0206, 0x0206, 0x0206, 0x0000, 0x020e,
0x0000, 0x0210, 0x0000, 0x0212, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0218, 0x0000, 0x0000, 0x021b, 0x0000, 0x021d, 0x021d,
0x0000, 0x0220, 0x0000, 0x0222, 0x0222, 0x0000, 0x0000, 0x0226,
0x0225, 0x0225, 0x0000, 0x0000, 0x022b, 0x0000, 0x022d, 0x0000,
0x022f, 0x0000, 0x023b, 0x0231, 0x023b, 0x023b, 0x023b, 0x023b,
0x023b, 0x023b, 0x023b, 0x0231, 0x023b, 0x023b, 0x0000, 0x023e,
// Entry 240 - 27F
0x023e, 0x023e, 0x0000, 0x0242, 0x0000, 0x0244, 0x0000, 0x0246,
0x0246, 0x0000, 0x0249, 0x0000, 0x024b, 0x024b, 0x024b, 0x024b,
0x024b, 0x024b, 0x0000, 0x0252, 0x0000, 0x0254, 0x0000, 0x0256,
0x0000, 0x0258, 0x0000, 0x025a, 0x0000, 0x0000, 0x025d, 0x025d,
0x025d, 0x0000, 0x0261, 0x0000, 0x0263, 0x0000, 0x0265, 0x0000,
0x0000, 0x0268, 0x0267, 0x0267, 0x0000, 0x026c, 0x0000, 0x026e,
0x0000, 0x0270, 0x0000, 0x0000, 0x0000, 0x0000, 0x0275, 0x0000,
0x0000, 0x0278, 0x0000, 0x027a, 0x027a, 0x027a, 0x027a, 0x0000,
// Entry 280 - 2BF
0x027f, 0x027f, 0x027f, 0x0000, 0x0283, 0x0283, 0x0283, 0x0283,
0x0283, 0x0000, 0x0289, 0x0289, 0x0289, 0x0289, 0x0000, 0x0000,
0x0000, 0x0000, 0x0291, 0x0291, 0x0291, 0x0000, 0x0295, 0x0295,
0x0295, 0x0295, 0x0000, 0x0000, 0x029b, 0x029b, 0x029b, 0x029b,
0x0000, 0x02a0, 0x0000, 0x02a2, 0x02a2, 0x0000, 0x02a5, 0x0000,
0x02a7, 0x02a7, 0x0000, 0x0000, 0x02ab, 0x0000, 0x0000, 0x02ae,
0x0000, 0x02b0, 0x02b0, 0x0000, 0x0000, 0x02b4, 0x0000, 0x02b6,
0x0000, 0x02b8, 0x0000, 0x02ba, 0x0000, 0x02bc, 0x02bc, 0x0000,
// Entry 2C0 - 2FF
0x0000, 0x02c0, 0x0000, 0x02c2, 0x02bf, 0x02bf, 0x0000, 0x0000,
0x02c7, 0x02c6, 0x02c6, 0x0000, 0x0000, 0x02cc, 0x0000, 0x02ce,
0x0000, 0x02d0, 0x0000, 0x0000, 0x02d3, 0x0000, 0x0000, 0x0000,
0x02d7, 0x0000, 0x02d9, 0x0000, 0x02db, 0x0000, 0x02dd, 0x02dd,
0x0000, 0x02e0, 0x0000, 0x02e2, 0x0000, 0x02e4, 0x02e4, 0x02e4,
0x02e4, 0x02e4, 0x0000, 0x02ea, 0x02eb, 0x02ea, 0x0000, 0x02ee,
} // Size: 1528 bytes
// Total table size 1528 bytes (1KiB); checksum: B99CF952

File diff suppressed because it is too large Load diff

View file

@ -593,7 +593,7 @@ func (t Tag) Extension(x byte) (ext Extension, ok bool) {
return Extension{ext}, true return Extension{ext}, true
} }
} }
return Extension{}, false return Extension{string(x)}, false
} }
// Extensions returns all extensions of t. // Extensions returns all extensions of t.

View file

@ -678,8 +678,6 @@ func (b *builder) parseIndices() {
b.locale.parse(meta.DefaultContent.Locales) b.locale.parse(meta.DefaultContent.Locales)
} }
// TODO: region inclusion data will probably not be use used in future matchers.
func (b *builder) computeRegionGroups() { func (b *builder) computeRegionGroups() {
b.groups = make(map[int]index) b.groups = make(map[int]index)
@ -688,11 +686,6 @@ func (b *builder) computeRegionGroups() {
b.groups[i] = index(len(b.groups)) b.groups[i] = index(len(b.groups))
} }
for _, g := range b.supp.TerritoryContainment.Group { for _, g := range b.supp.TerritoryContainment.Group {
// Skip UN and EURO zone as they are flattening the containment
// relationship.
if g.Type == "EZ" || g.Type == "UN" {
continue
}
group := b.region.index(g.Type) group := b.region.index(g.Type)
if _, ok := b.groups[group]; !ok { if _, ok := b.groups[group]; !ok {
b.groups[group] = index(len(b.groups)) b.groups[group] = index(len(b.groups))
@ -789,7 +782,6 @@ func (b *builder) writeLanguage() {
lang.updateLater("tw", "twi") lang.updateLater("tw", "twi")
lang.updateLater("nb", "nob") lang.updateLater("nb", "nob")
lang.updateLater("ak", "aka") lang.updateLater("ak", "aka")
lang.updateLater("bh", "bih")
// Ensure that each 2-letter code is matched with a 3-letter code. // Ensure that each 2-letter code is matched with a 3-letter code.
for _, v := range lang.s[1:] { for _, v := range lang.s[1:] {
@ -1490,11 +1482,6 @@ func (b *builder) writeRegionInclusionData() {
containment = make(map[index][]index) containment = make(map[index][]index)
) )
for _, g := range b.supp.TerritoryContainment.Group { for _, g := range b.supp.TerritoryContainment.Group {
// Skip UN and EURO zone as they are flattening the containment
// relationship.
if g.Type == "EZ" || g.Type == "UN" {
continue
}
group := b.region.index(g.Type) group := b.region.index(g.Type)
groupIdx := b.groups[group] groupIdx := b.groups[group]
for _, mem := range strings.Split(g.Contains, " ") { for _, mem := range strings.Split(g.Contains, " ") {

View file

@ -396,8 +396,8 @@ type matcher struct {
// matchHeader has the lists of tags for exact matches and matches based on // matchHeader has the lists of tags for exact matches and matches based on
// maximized and canonicalized tags for a given language. // maximized and canonicalized tags for a given language.
type matchHeader struct { type matchHeader struct {
exact []*haveTag exact []haveTag
max []*haveTag max []haveTag
} }
// haveTag holds a supported Tag and its maximized script and region. The maximized // haveTag holds a supported Tag and its maximized script and region. The maximized
@ -457,7 +457,7 @@ func (h *matchHeader) addIfNew(n haveTag, exact bool) {
} }
} }
if exact { if exact {
h.exact = append(h.exact, &n) h.exact = append(h.exact, n)
} }
// Allow duplicate maximized tags, but create a linked list to allow quickly // Allow duplicate maximized tags, but create a linked list to allow quickly
// comparing the equivalents and bail out. // comparing the equivalents and bail out.
@ -472,7 +472,7 @@ func (h *matchHeader) addIfNew(n haveTag, exact bool) {
break break
} }
} }
h.max = append(h.max, &n) h.max = append(h.max, n)
} }
// header returns the matchHeader for the given language. It creates one if // header returns the matchHeader for the given language. It creates one if
@ -503,7 +503,7 @@ func newMatcher(supported []Tag) *matcher {
pair, _ := makeHaveTag(tag, i) pair, _ := makeHaveTag(tag, i)
m.header(tag.lang).addIfNew(pair, true) m.header(tag.lang).addIfNew(pair, true)
} }
m.default_ = m.header(supported[0].lang).exact[0] m.default_ = &m.header(supported[0].lang).exact[0]
for i, tag := range supported { for i, tag := range supported {
pair, max := makeHaveTag(tag, i) pair, max := makeHaveTag(tag, i)
if max != tag.lang { if max != tag.lang {
@ -520,8 +520,7 @@ func newMatcher(supported []Tag) *matcher {
return return
} }
hw := m.header(langID(want)) hw := m.header(langID(want))
for _, ht := range hh.max { for _, v := range hh.max {
v := *ht
if conf < v.conf { if conf < v.conf {
v.conf = conf v.conf = conf
} }
@ -581,7 +580,7 @@ func (m *matcher) getBest(want ...Tag) (got *haveTag, orig Tag, c Confidence) {
continue continue
} }
for i := range h.exact { for i := range h.exact {
have := h.exact[i] have := &h.exact[i]
if have.tag.equalsRest(w) { if have.tag.equalsRest(w) {
return have, w, Exact return have, w, Exact
} }
@ -592,7 +591,7 @@ func (m *matcher) getBest(want ...Tag) (got *haveTag, orig Tag, c Confidence) {
// Base language is not defined. // Base language is not defined.
if h != nil { if h != nil {
for i := range h.exact { for i := range h.exact {
have := h.exact[i] have := &h.exact[i]
if have.tag.equalsRest(w) { if have.tag.equalsRest(w) {
return have, w, Exact return have, w, Exact
} }
@ -610,11 +609,11 @@ func (m *matcher) getBest(want ...Tag) (got *haveTag, orig Tag, c Confidence) {
} }
// Check for match based on maximized tag. // Check for match based on maximized tag.
for i := range h.max { for i := range h.max {
have := h.max[i] have := &h.max[i]
best.update(have, w, max.script, max.region) best.update(have, w, max.script, max.region)
if best.conf == Exact { if best.conf == Exact {
for have.nextMax != 0 { for have.nextMax != 0 {
have = h.max[have.nextMax] have = &h.max[have.nextMax]
best.update(have, w, max.script, max.region) best.update(have, w, max.script, max.region)
} }
return best.have, best.want, High return best.have, best.want, High

File diff suppressed because it is too large Load diff

View file

@ -41,35 +41,20 @@ func If(s Set, tIn, tNotIn transform.Transformer) Transformer {
if tNotIn == nil { if tNotIn == nil {
tNotIn = transform.Nop tNotIn = transform.Nop
} }
sIn, ok := tIn.(transform.SpanningTransformer)
if !ok {
sIn = dummySpan{tIn}
}
sNotIn, ok := tNotIn.(transform.SpanningTransformer)
if !ok {
sNotIn = dummySpan{tNotIn}
}
a := &cond{ a := &cond{
tIn: sIn, tIn: tIn,
tNotIn: sNotIn, tNotIn: tNotIn,
f: s.Contains, f: s.Contains,
} }
a.Reset() a.Reset()
return Transformer{a} return Transformer{a}
} }
type dummySpan struct{ transform.Transformer }
func (d dummySpan) Span(src []byte, atEOF bool) (n int, err error) {
return 0, transform.ErrEndOfSpan
}
type cond struct { type cond struct {
tIn, tNotIn transform.SpanningTransformer tIn, tNotIn transform.Transformer
f func(rune) bool f func(rune) bool
check func(rune) bool // current check to perform check func(rune) bool // current check to perform
t transform.SpanningTransformer // current transformer to use t transform.Transformer // current transformer to use
} }
// Reset implements transform.Transformer. // Reset implements transform.Transformer.
@ -99,51 +84,6 @@ func (t *cond) isNot(r rune) bool {
return false return false
} }
// This implementation of Span doesn't help all too much, but it needs to be
// there to satisfy this package's Transformer interface.
// TODO: there are certainly room for improvements, though. For example, if
// t.t == transform.Nop (which will a common occurrence) it will save a bundle
// to special-case that loop.
func (t *cond) Span(src []byte, atEOF bool) (n int, err error) {
p := 0
for n < len(src) && err == nil {
// Don't process too much at a time as the Spanner that will be
// called on this block may terminate early.
const maxChunk = 4096
max := len(src)
if v := n + maxChunk; v < max {
max = v
}
atEnd := false
size := 0
current := t.t
for ; p < max; p += size {
r := rune(src[p])
if r < utf8.RuneSelf {
size = 1
} else if r, size = utf8.DecodeRune(src[p:]); size == 1 {
if !atEOF && !utf8.FullRune(src[p:]) {
err = transform.ErrShortSrc
break
}
}
if !t.check(r) {
// The next rune will be the start of a new run.
atEnd = true
break
}
}
n2, err2 := current.Span(src[n:p], atEnd || (atEOF && p == len(src)))
n += n2
if err2 != nil {
return n, err2
}
// At this point either err != nil or t.check will pass for the rune at p.
p = n + size
}
return n, err
}
func (t *cond) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (t *cond) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
p := 0 p := 0
for nSrc < len(src) && err == nil { for nSrc < len(src) && err == nil {
@ -159,10 +99,9 @@ func (t *cond) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error
size := 0 size := 0
current := t.t current := t.t
for ; p < max; p += size { for ; p < max; p += size {
r := rune(src[p]) var r rune
if r < utf8.RuneSelf { r, size = utf8.DecodeRune(src[p:])
size = 1 if r == utf8.RuneError && size == 1 {
} else if r, size = utf8.DecodeRune(src[p:]); size == 1 {
if !atEOF && !utf8.FullRune(src[p:]) { if !atEOF && !utf8.FullRune(src[p:]) {
err = transform.ErrShortSrc err = transform.ErrShortSrc
break break

View file

@ -46,19 +46,9 @@ func Predicate(f func(rune) bool) Set {
// Transformer implements the transform.Transformer interface. // Transformer implements the transform.Transformer interface.
type Transformer struct { type Transformer struct {
t transform.SpanningTransformer transform.Transformer
} }
func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
return t.t.Transform(dst, src, atEOF)
}
func (t Transformer) Span(b []byte, atEOF bool) (n int, err error) {
return t.t.Span(b, atEOF)
}
func (t Transformer) Reset() { t.t.Reset() }
// Bytes returns a new byte slice with the result of converting b using t. It // Bytes returns a new byte slice with the result of converting b using t. It
// calls Reset on t. It returns nil if any error was found. This can only happen // calls Reset on t. It returns nil if any error was found. This can only happen
// if an error-producing Transformer is passed to If. // if an error-producing Transformer is passed to If.
@ -106,57 +96,39 @@ type remove func(r rune) bool
func (remove) Reset() {} func (remove) Reset() {}
// Span implements transform.Spanner.
func (t remove) Span(src []byte, atEOF bool) (n int, err error) {
for r, size := rune(0), 0; n < len(src); {
if r = rune(src[n]); r < utf8.RuneSelf {
size = 1
} else if r, size = utf8.DecodeRune(src[n:]); size == 1 {
// Invalid rune.
if !atEOF && !utf8.FullRune(src[n:]) {
err = transform.ErrShortSrc
} else {
err = transform.ErrEndOfSpan
}
break
}
if t(r) {
err = transform.ErrEndOfSpan
break
}
n += size
}
return
}
// Transform implements transform.Transformer. // Transform implements transform.Transformer.
func (t remove) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (t remove) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for r, size := rune(0), 0; nSrc < len(src); { for r, size := rune(0), 0; nSrc < len(src); {
if r = rune(src[nSrc]); r < utf8.RuneSelf { if r = rune(src[nSrc]); r < utf8.RuneSelf {
size = 1 size = 1
} else if r, size = utf8.DecodeRune(src[nSrc:]); size == 1 { } else {
// Invalid rune. r, size = utf8.DecodeRune(src[nSrc:])
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc if size == 1 {
break // Invalid rune.
} if !atEOF && !utf8.FullRune(src[nSrc:]) {
// We replace illegal bytes with RuneError. Not doing so might err = transform.ErrShortSrc
// otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
// The resulting byte sequence may subsequently contain runes
// for which t(r) is true that were passed unnoticed.
if !t(utf8.RuneError) {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
break break
} }
dst[nDst+0] = runeErrorString[0] // We replace illegal bytes with RuneError. Not doing so might
dst[nDst+1] = runeErrorString[1] // otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
dst[nDst+2] = runeErrorString[2] // The resulting byte sequence may subsequently contain runes
nDst += 3 // for which t(r) is true that were passed unnoticed.
if !t(utf8.RuneError) {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = runeErrorString[0]
dst[nDst+1] = runeErrorString[1]
dst[nDst+2] = runeErrorString[2]
nDst += 3
}
nSrc++
continue
} }
nSrc++
continue
} }
if t(r) { if t(r) {
nSrc += size nSrc += size
continue continue
@ -185,28 +157,6 @@ type mapper func(rune) rune
func (mapper) Reset() {} func (mapper) Reset() {}
// Span implements transform.Spanner.
func (t mapper) Span(src []byte, atEOF bool) (n int, err error) {
for r, size := rune(0), 0; n < len(src); n += size {
if r = rune(src[n]); r < utf8.RuneSelf {
size = 1
} else if r, size = utf8.DecodeRune(src[n:]); size == 1 {
// Invalid rune.
if !atEOF && !utf8.FullRune(src[n:]) {
err = transform.ErrShortSrc
} else {
err = transform.ErrEndOfSpan
}
break
}
if t(r) != r {
err = transform.ErrEndOfSpan
break
}
}
return n, err
}
// Transform implements transform.Transformer. // Transform implements transform.Transformer.
func (t mapper) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (t mapper) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
var replacement rune var replacement rune
@ -280,51 +230,24 @@ func ReplaceIllFormed() Transformer {
type replaceIllFormed struct{ transform.NopResetter } type replaceIllFormed struct{ transform.NopResetter }
func (t replaceIllFormed) Span(src []byte, atEOF bool) (n int, err error) {
for n < len(src) {
// ASCII fast path.
if src[n] < utf8.RuneSelf {
n++
continue
}
r, size := utf8.DecodeRune(src[n:])
// Look for a valid non-ASCII rune.
if r != utf8.RuneError || size != 1 {
n += size
continue
}
// Look for short source data.
if !atEOF && !utf8.FullRune(src[n:]) {
err = transform.ErrShortSrc
break
}
// We have an invalid rune.
err = transform.ErrEndOfSpan
break
}
return n, err
}
func (t replaceIllFormed) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (t replaceIllFormed) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for nSrc < len(src) { for nSrc < len(src) {
// ASCII fast path. r, size := utf8.DecodeRune(src[nSrc:])
if r := src[nSrc]; r < utf8.RuneSelf {
// Look for an ASCII rune.
if r < utf8.RuneSelf {
if nDst == len(dst) { if nDst == len(dst) {
err = transform.ErrShortDst err = transform.ErrShortDst
break break
} }
dst[nDst] = r dst[nDst] = byte(r)
nDst++ nDst++
nSrc++ nSrc++
continue continue
} }
// Look for a valid non-ASCII rune. // Look for a valid non-ASCII rune.
if _, size := utf8.DecodeRune(src[nSrc:]); size != 1 { if r != utf8.RuneError || size != 1 {
if size != copy(dst[nDst:], src[nSrc:nSrc+size]) { if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
err = transform.ErrShortDst err = transform.ErrShortDst
break break

View file

@ -123,64 +123,34 @@ var transitions = [...][2]ruleTransition{
// vice versa. // vice versa.
const exclusiveRTL = uint16(1<<bidi.EN | 1<<bidi.AN) const exclusiveRTL = uint16(1<<bidi.EN | 1<<bidi.AN)
// From RFC 5893 // Direction reports the direction of the given label as defined by RFC 5893 or
// An RTL label is a label that contains at least one character of type // an error if b is not a valid label according to the Bidi Rule.
// R, AL, or AN. func Direction(b []byte) (bidi.Direction, error) {
// t := Transformer{}
// An LTR label is any label that is not an RTL label. if n, ok := t.advance(b); ok && n == len(b) {
switch t.state {
// Direction reports the direction of the given label as defined by RFC 5893. case ruleLTRFinal, ruleInitial:
// The Bidi Rule does not have to be applied to labels of the category return bidi.LeftToRight, nil
// LeftToRight. case ruleRTLFinal:
func Direction(b []byte) bidi.Direction { return bidi.RightToLeft, nil
for i := 0; i < len(b); {
e, sz := bidi.Lookup(b[i:])
if sz == 0 {
i++
} }
c := e.Class()
if c == bidi.R || c == bidi.AL || c == bidi.AN {
return bidi.RightToLeft
}
i += sz
} }
return bidi.LeftToRight return bidi.Neutral, ErrInvalid
} }
// DirectionString reports the direction of the given label as defined by RFC // DirectionString reports the direction of the given label as defined by RFC
// 5893. The Bidi Rule does not have to be applied to labels of the category // 5893 or an error if s is not a valid label according to the Bidi Rule.
// LeftToRight. func DirectionString(s string) (bidi.Direction, error) {
func DirectionString(s string) bidi.Direction { t := Transformer{}
for i := 0; i < len(s); { if n, ok := t.advanceString(s); ok && n == len(s) {
e, sz := bidi.LookupString(s[i:]) switch t.state {
if sz == 0 { case ruleLTRFinal, ruleInitial:
i++ return bidi.LeftToRight, nil
case ruleRTLFinal:
return bidi.RightToLeft, nil
} }
c := e.Class()
if c == bidi.R || c == bidi.AL || c == bidi.AN {
return bidi.RightToLeft
}
i += sz
} }
return bidi.LeftToRight return bidi.Neutral, ErrInvalid
}
// Valid reports whether b conforms to the BiDi rule.
func Valid(b []byte) bool {
var t Transformer
if n, ok := t.advance(b); !ok || n < len(b) {
return false
}
return t.isFinal()
}
// ValidString reports whether s conforms to the BiDi rule.
func ValidString(s string) bool {
var t Transformer
if n, ok := t.advanceString(s); !ok || n < len(s) {
return false
}
return t.isFinal()
} }
// New returns a Transformer that verifies that input adheres to the Bidi Rule. // New returns a Transformer that verifies that input adheres to the Bidi Rule.
@ -190,23 +160,8 @@ func New() *Transformer {
// Transformer implements transform.Transform. // Transformer implements transform.Transform.
type Transformer struct { type Transformer struct {
state ruleState state ruleState
hasRTL bool seen uint16
seen uint16
}
// A rule can only be violated for "Bidi Domain names", meaning if one of the
// following categories has been observed.
func (t *Transformer) isRTL() bool {
const isRTL = 1<<bidi.R | 1<<bidi.AL | 1<<bidi.AN
return t.seen&isRTL != 0
}
func (t *Transformer) isFinal() bool {
if !t.isRTL() {
return true
}
return t.state == ruleLTRFinal || t.state == ruleRTLFinal || t.state == ruleInitial
} }
// Reset implements transform.Transformer. // Reset implements transform.Transformer.
@ -230,7 +185,7 @@ func (t *Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, er
// Span returns the first n bytes of src that conform to the Bidi rule. // Span returns the first n bytes of src that conform to the Bidi rule.
func (t *Transformer) Span(src []byte, atEOF bool) (n int, err error) { func (t *Transformer) Span(src []byte, atEOF bool) (n int, err error) {
if t.state == ruleInvalid && t.isRTL() { if t.state == ruleInvalid {
return 0, ErrInvalid return 0, ErrInvalid
} }
n, ok := t.advance(src) n, ok := t.advance(src)
@ -243,7 +198,7 @@ func (t *Transformer) Span(src []byte, atEOF bool) (n int, err error) {
break break
} }
err = ErrInvalid err = ErrInvalid
case !t.isFinal(): case t.state != ruleLTRFinal && t.state != ruleRTLFinal && t.state != ruleInitial:
err = ErrInvalid err = ErrInvalid
} }
return n, err return n, err
@ -270,15 +225,12 @@ func (t *Transformer) advance(s []byte) (n int, ok bool) {
e, sz = bidi.Lookup(s[n:]) e, sz = bidi.Lookup(s[n:])
if sz <= 1 { if sz <= 1 {
if sz == 1 { if sz == 1 {
// We always consider invalid UTF-8 to be invalid, even if return n, false // invalid UTF-8
// the string has not yet been determined to be RTL.
// TODO: is this correct?
return n, false
} }
return n, true // incomplete UTF-8 encoding return n, true // incomplete UTF-8 encoding
} }
} }
// TODO: using CompactClass would result in noticeable speedup. // TODO: using CompactClass results in noticeable speedup.
// See unicode/bidi/prop.go:Properties.CompactClass. // See unicode/bidi/prop.go:Properties.CompactClass.
c := uint16(1 << e.Class()) c := uint16(1 << e.Class())
t.seen |= c t.seen |= c
@ -293,9 +245,7 @@ func (t *Transformer) advance(s []byte) (n int, ok bool) {
t.state = tr[1].next t.state = tr[1].next
default: default:
t.state = ruleInvalid t.state = ruleInvalid
if t.isRTL() { return n, false
return n, false
}
} }
n += sz n += sz
} }
@ -332,9 +282,7 @@ func (t *Transformer) advanceString(s string) (n int, ok bool) {
t.state = tr[1].next t.state = tr[1].next
default: default:
t.state = ruleInvalid t.state = ruleInvalid
if t.isRTL() { return n, false
return n, false
}
} }
n += sz n += sz
} }

View file

@ -6,10 +6,10 @@ package precis
import ( import (
"golang.org/x/text/cases" "golang.org/x/text/cases"
"golang.org/x/text/language"
"golang.org/x/text/runes" "golang.org/x/text/runes"
"golang.org/x/text/transform" "golang.org/x/text/transform"
"golang.org/x/text/unicode/norm" "golang.org/x/text/unicode/norm"
"golang.org/x/text/width"
) )
// An Option is used to define the behavior and rules of a Profile. // An Option is used to define the behavior and rules of a Profile.
@ -20,12 +20,11 @@ type options struct {
foldWidth bool foldWidth bool
// Enforcement options // Enforcement options
asciiLower bool cases transform.Transformer
cases transform.SpanningTransformer
disallow runes.Set disallow runes.Set
norm transform.SpanningTransformer norm norm.Form
additional []func() transform.SpanningTransformer additional []func() transform.Transformer
width transform.SpanningTransformer width *width.Transformer
disallowEmpty bool disallowEmpty bool
bidiRule bool bidiRule bool
@ -37,11 +36,6 @@ func getOpts(o ...Option) (res options) {
for _, f := range o { for _, f := range o {
f(&res) f(&res)
} }
// Using a SpanningTransformer, instead of norm.Form prevents an allocation
// down the road.
if res.norm == nil {
res.norm = norm.NFC
}
return return
} }
@ -80,36 +74,11 @@ var (
} }
) )
// TODO: move this logic to package transform
type spanWrap struct{ transform.Transformer }
func (s spanWrap) Span(src []byte, atEOF bool) (n int, err error) {
return 0, transform.ErrEndOfSpan
}
// TODO: allow different types? For instance:
// func() transform.Transformer
// func() transform.SpanningTransformer
// func([]byte) bool // validation only
//
// Also, would be great if we could detect if a transformer is reentrant.
// The AdditionalMapping option defines the additional mapping rule for the // The AdditionalMapping option defines the additional mapping rule for the
// Profile by applying Transformer's in sequence. // Profile by applying Transformer's in sequence.
func AdditionalMapping(t ...func() transform.Transformer) Option { func AdditionalMapping(t ...func() transform.Transformer) Option {
return func(o *options) { return func(o *options) {
for _, f := range t { o.additional = t
sf := func() transform.SpanningTransformer {
return f().(transform.SpanningTransformer)
}
if _, ok := f().(transform.SpanningTransformer); !ok {
sf = func() transform.SpanningTransformer {
return spanWrap{f()}
}
}
o.additional = append(o.additional, sf)
}
} }
} }
@ -124,26 +93,10 @@ func Norm(f norm.Form) Option {
// provided to determine the type of case folding used. // provided to determine the type of case folding used.
func FoldCase(opts ...cases.Option) Option { func FoldCase(opts ...cases.Option) Option {
return func(o *options) { return func(o *options) {
o.asciiLower = true
o.cases = cases.Fold(opts...) o.cases = cases.Fold(opts...)
} }
} }
// The LowerCase option defines a Profile's case mapping rule. Options can be
// provided to determine the type of case folding used.
func LowerCase(opts ...cases.Option) Option {
return func(o *options) {
o.asciiLower = true
if len(opts) == 0 {
o.cases = cases.Lower(language.Und, cases.HandleFinalSigma(false))
return
}
opts = append([]cases.Option{cases.HandleFinalSigma(false)}, opts...)
o.cases = cases.Lower(language.Und, opts...)
}
}
// The Disallow option further restricts a Profile's allowed characters beyond // The Disallow option further restricts a Profile's allowed characters beyond
// what is disallowed by the underlying string class. // what is disallowed by the underlying string class.
func Disallow(set runes.Set) Option { func Disallow(set runes.Set) Option {

View file

@ -5,12 +5,9 @@
package precis package precis
import ( import (
"bytes"
"errors" "errors"
"unicode/utf8" "unicode/utf8"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"golang.org/x/text/runes" "golang.org/x/text/runes"
"golang.org/x/text/secure/bidirule" "golang.org/x/text/secure/bidirule"
"golang.org/x/text/transform" "golang.org/x/text/transform"
@ -93,80 +90,32 @@ type buffers struct {
next int next int
} }
func (b *buffers) apply(t transform.SpanningTransformer) (err error) { func (b *buffers) init(n int) {
n, err := t.Span(b.src, true) b.buf[0] = make([]byte, 0, n)
if err != transform.ErrEndOfSpan { b.buf[1] = make([]byte, 0, n)
return err }
}
func (b *buffers) apply(t transform.Transformer) (err error) {
// TODO: use Span, once available.
x := b.next & 1 x := b.next & 1
if b.buf[x] == nil { b.src, _, err = transform.Append(t, b.buf[x][:0], b.src)
b.buf[x] = make([]byte, 0, 8+len(b.src)+len(b.src)>>2)
}
span := append(b.buf[x][:0], b.src[:n]...)
b.src, _, err = transform.Append(t, span, b.src[n:])
b.buf[x] = b.src b.buf[x] = b.src
b.next++ b.next++
return err return err
} }
// Pre-allocate transformers when possible. In some cases this avoids allocation. func (b *buffers) enforce(p *Profile, src []byte) (str []byte, err error) {
var (
foldWidthT transform.SpanningTransformer = width.Fold
lowerCaseT transform.SpanningTransformer = cases.Lower(language.Und, cases.HandleFinalSigma(false))
)
// TODO: make this a method on profile.
func (b *buffers) enforce(p *Profile, src []byte, comparing bool) (str []byte, err error) {
b.src = src b.src = src
ascii := true
for _, c := range src {
if c >= utf8.RuneSelf {
ascii = false
break
}
}
// ASCII fast path.
if ascii {
for _, f := range p.options.additional {
if err = b.apply(f()); err != nil {
return nil, err
}
}
switch {
case p.options.asciiLower || (comparing && p.options.ignorecase):
for i, c := range b.src {
if 'A' <= c && c <= 'Z' {
b.src[i] = c ^ 1<<5
}
}
case p.options.cases != nil:
b.apply(p.options.cases)
}
c := checker{p: p}
if _, err := c.span(b.src, true); err != nil {
return nil, err
}
if p.disallow != nil {
for _, c := range b.src {
if p.disallow.Contains(rune(c)) {
return nil, errDisallowedRune
}
}
}
if p.options.disallowEmpty && len(b.src) == 0 {
return nil, errEmptyString
}
return b.src, nil
}
// These transforms are applied in the order defined in // These transforms are applied in the order defined in
// https://tools.ietf.org/html/rfc7564#section-7 // https://tools.ietf.org/html/rfc7564#section-7
// TODO: allow different width transforms options. // TODO: allow different width transforms options.
if p.options.foldWidth || (p.options.ignorecase && comparing) { if p.options.foldWidth {
b.apply(foldWidthT) // TODO: use Span, once available.
if err = b.apply(width.Fold); err != nil {
return nil, err
}
} }
for _, f := range p.options.additional { for _, f := range p.options.additional {
if err = b.apply(f()); err != nil { if err = b.apply(f()); err != nil {
@ -174,14 +123,24 @@ func (b *buffers) enforce(p *Profile, src []byte, comparing bool) (str []byte, e
} }
} }
if p.options.cases != nil { if p.options.cases != nil {
b.apply(p.options.cases) if err = b.apply(p.options.cases); err != nil {
return nil, err
}
} }
if comparing && p.options.ignorecase { if n := p.norm.QuickSpan(b.src); n < len(b.src) {
b.apply(lowerCaseT) x := b.next & 1
n = copy(b.buf[x], b.src[:n])
b.src, _, err = transform.Append(p.norm, b.buf[x][:n], b.src[n:])
b.buf[x] = b.src
b.next++
if err != nil {
return nil, err
}
} }
b.apply(p.norm) if p.options.bidiRule {
if p.options.bidiRule && !bidirule.Valid(b.src) { if err := b.apply(bidirule.New()); err != nil {
return nil, bidirule.ErrInvalid return nil, err
}
} }
c := checker{p: p} c := checker{p: p}
if _, err := c.span(b.src, true); err != nil { if _, err := c.span(b.src, true); err != nil {
@ -196,6 +155,9 @@ func (b *buffers) enforce(p *Profile, src []byte, comparing bool) (str []byte, e
i += size i += size
} }
} }
// TODO: Add the disallow empty rule with a dummy transformer?
if p.options.disallowEmpty && len(b.src) == 0 { if p.options.disallowEmpty && len(b.src) == 0 {
return nil, errEmptyString return nil, errEmptyString
} }
@ -206,16 +168,19 @@ func (b *buffers) enforce(p *Profile, src []byte, comparing bool) (str []byte, e
// It returns an error if the input string is invalid. // It returns an error if the input string is invalid.
func (p *Profile) Append(dst, src []byte) ([]byte, error) { func (p *Profile) Append(dst, src []byte) ([]byte, error) {
var buf buffers var buf buffers
b, err := buf.enforce(p, src, false) buf.init(8 + len(src) + len(src)>>2)
b, err := buf.enforce(p, src)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return append(dst, b...), nil return append(dst, b...), nil
} }
func processBytes(p *Profile, b []byte, key bool) ([]byte, error) { // Bytes returns a new byte slice with the result of applying the profile to b.
func (p *Profile) Bytes(b []byte) ([]byte, error) {
var buf buffers var buf buffers
b, err := buf.enforce(p, b, key) buf.init(8 + len(b) + len(b)>>2)
b, err := buf.enforce(p, b)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -227,62 +192,39 @@ func processBytes(p *Profile, b []byte, key bool) ([]byte, error) {
return b, nil return b, nil
} }
// Bytes returns a new byte slice with the result of applying the profile to b. // String returns a string with the result of applying the profile to s.
func (p *Profile) Bytes(b []byte) ([]byte, error) { func (p *Profile) String(s string) (string, error) {
return processBytes(p, b, false)
}
// AppendCompareKey appends the result of applying p to src (including any
// optional rules to make strings comparable or useful in a map key such as
// applying lowercasing) writing the result to dst. It returns an error if the
// input string is invalid.
func (p *Profile) AppendCompareKey(dst, src []byte) ([]byte, error) {
var buf buffers var buf buffers
b, err := buf.enforce(p, src, true) buf.init(8 + len(s) + len(s)>>2)
if err != nil { b, err := buf.enforce(p, []byte(s))
return nil, err
}
return append(dst, b...), nil
}
func processString(p *Profile, s string, key bool) (string, error) {
var buf buffers
b, err := buf.enforce(p, []byte(s), key)
if err != nil { if err != nil {
return "", err return "", err
} }
return string(b), nil return string(b), nil
} }
// String returns a string with the result of applying the profile to s.
func (p *Profile) String(s string) (string, error) {
return processString(p, s, false)
}
// CompareKey returns a string that can be used for comparison, hashing, or
// collation.
func (p *Profile) CompareKey(s string) (string, error) {
return processString(p, s, true)
}
// Compare enforces both strings, and then compares them for bit-string identity // Compare enforces both strings, and then compares them for bit-string identity
// (byte-for-byte equality). If either string cannot be enforced, the comparison // (byte-for-byte equality). If either string cannot be enforced, the comparison
// is false. // is false.
func (p *Profile) Compare(a, b string) bool { func (p *Profile) Compare(a, b string) bool {
var buf buffers a, err := p.String(a)
if err != nil {
akey, err := buf.enforce(p, []byte(a), true) return false
}
b, err = p.String(b)
if err != nil { if err != nil {
return false return false
} }
buf = buffers{} // TODO: This is out of order. Need to extract the transformation logic and
bkey, err := buf.enforce(p, []byte(b), true) // put this in where the normal case folding would go (but only for
if err != nil { // comparison).
return false if p.options.ignorecase {
a = width.Fold.String(a)
b = width.Fold.String(a)
} }
return bytes.Compare(akey, bkey) == 0 return a == b
} }
// Allowed returns a runes.Set containing every rune that is a member of the // Allowed returns a runes.Set containing every rune that is a member of the

View file

@ -19,51 +19,38 @@ var (
OpaqueString *Profile = opaquestring // Implements the OpaqueString profile defined in RFC 7613 for passwords and other secure labels. OpaqueString *Profile = opaquestring // Implements the OpaqueString profile defined in RFC 7613 for passwords and other secure labels.
) )
// TODO: mvl: "Ultimately, I would manually define the structs for the internal
// profiles. This avoid pulling in unneeded tables when they are not used."
var ( var (
nickname = &Profile{ nickname = NewFreeform(
options: getOpts( AdditionalMapping(func() transform.Transformer {
AdditionalMapping(func() transform.Transformer { return &nickAdditionalMapping{}
return &nickAdditionalMapping{} }),
}), IgnoreCase,
IgnoreCase, Norm(norm.NFKC),
Norm(norm.NFKC), DisallowEmpty,
DisallowEmpty, )
), usernameCaseMap = NewIdentifier(
class: freeform, FoldWidth,
} FoldCase(),
usernameCaseMap = &Profile{ Norm(norm.NFC),
options: getOpts( BidiRule,
FoldWidth, )
LowerCase(), usernameNoCaseMap = NewIdentifier(
Norm(norm.NFC), FoldWidth,
BidiRule, Norm(norm.NFC),
), BidiRule,
class: identifier, )
} opaquestring = NewFreeform(
usernameNoCaseMap = &Profile{ AdditionalMapping(func() transform.Transformer {
options: getOpts( return runes.Map(func(r rune) rune {
FoldWidth, if unicode.Is(unicode.Zs, r) {
Norm(norm.NFC), return ' '
BidiRule, }
), return r
class: identifier, })
} }),
opaquestring = &Profile{ Norm(norm.NFC),
options: getOpts( DisallowEmpty,
AdditionalMapping(func() transform.Transformer { )
return mapSpaces
}),
Norm(norm.NFC),
DisallowEmpty,
),
class: freeform,
}
) )
// mapSpaces is a shared value of a runes.Map transformer.
var mapSpaces transform.Transformer = runes.Map(func(r rune) rune {
if unicode.Is(unicode.Zs, r) {
return ' '
}
return r
})

View file

@ -24,10 +24,6 @@ var (
// complete the transformation. // complete the transformation.
ErrShortSrc = errors.New("transform: short source buffer") ErrShortSrc = errors.New("transform: short source buffer")
// ErrEndOfSpan means that the input and output (the transformed input)
// are not identical.
ErrEndOfSpan = errors.New("transform: input and output are not identical")
// errInconsistentByteCount means that Transform returned success (nil // errInconsistentByteCount means that Transform returned success (nil
// error) but also returned nSrc inconsistent with the src argument. // error) but also returned nSrc inconsistent with the src argument.
errInconsistentByteCount = errors.New("transform: inconsistent byte count returned") errInconsistentByteCount = errors.New("transform: inconsistent byte count returned")
@ -64,41 +60,6 @@ type Transformer interface {
Reset() Reset()
} }
// SpanningTransformer extends the Transformer interface with a Span method
// that determines how much of the input already conforms to the Transformer.
type SpanningTransformer interface {
Transformer
// Span returns a position in src such that transforming src[:n] results in
// identical output src[:n] for these bytes. It does not necessarily return
// the largest such n. The atEOF argument tells whether src represents the
// last bytes of the input.
//
// Callers should always account for the n bytes consumed before
// considering the error err.
//
// A nil error means that all input bytes are known to be identical to the
// output produced by the Transformer. A nil error can be be returned
// regardless of whether atEOF is true. If err is nil, then then n must
// equal len(src); the converse is not necessarily true.
//
// ErrEndOfSpan means that the Transformer output may differ from the
// input after n bytes. Note that n may be len(src), meaning that the output
// would contain additional bytes after otherwise identical output.
// ErrShortSrc means that src had insufficient data to determine whether the
// remaining bytes would change. Other than the error conditions listed
// here, implementations are free to report other errors that arise.
//
// Calling Span can modify the Transformer state as a side effect. In
// effect, it does the transformation just as calling Transform would, only
// without copying to a destination buffer and only up to a point it can
// determine the input and output bytes are the same. This is obviously more
// limited than calling Transform, but can be more efficient in terms of
// copying and allocating buffers. Calls to Span and Transform may be
// interleaved.
Span(src []byte, atEOF bool) (n int, err error)
}
// NopResetter can be embedded by implementations of Transformer to add a nop // NopResetter can be embedded by implementations of Transformer to add a nop
// Reset method. // Reset method.
type NopResetter struct{} type NopResetter struct{}
@ -317,10 +278,6 @@ func (nop) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
return n, n, err return n, n, err
} }
func (nop) Span(src []byte, atEOF bool) (n int, err error) {
return len(src), nil
}
type discard struct{ NopResetter } type discard struct{ NopResetter }
func (discard) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (discard) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
@ -332,8 +289,8 @@ var (
// by consuming all bytes and writing nothing. // by consuming all bytes and writing nothing.
Discard Transformer = discard{} Discard Transformer = discard{}
// Nop is a SpanningTransformer that copies src to dst. // Nop is a Transformer that copies src to dst.
Nop SpanningTransformer = nop{} Nop Transformer = nop{}
) )
// chain is a sequence of links. A chain with N Transformers has N+1 links and // chain is a sequence of links. A chain with N Transformers has N+1 links and
@ -401,8 +358,6 @@ func (c *chain) Reset() {
} }
} }
// TODO: make chain use Span (is going to be fun to implement!)
// Transform applies the transformers of c in sequence. // Transform applies the transformers of c in sequence.
func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
// Set up src and dst in the chain. // Set up src and dst in the chain.
@ -493,7 +448,8 @@ func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err erro
return dstL.n, srcL.p, err return dstL.n, srcL.p, err
} }
// Deprecated: use runes.Remove instead. // RemoveFunc returns a Transformer that removes from the input all runes r for
// which f(r) is true. Illegal bytes in the input are replaced by RuneError.
func RemoveFunc(f func(r rune) bool) Transformer { func RemoveFunc(f func(r rune) bool) Transformer {
return removeF(f) return removeF(f)
} }

View file

@ -84,7 +84,7 @@ func resolvePairedBrackets(s *isolatingRunSequence) {
dirEmbed = R dirEmbed = R
} }
p.locateBrackets(s.p.pairTypes, s.p.pairValues) p.locateBrackets(s.p.pairTypes, s.p.pairValues)
p.resolveBrackets(dirEmbed, s.p.initialTypes) p.resolveBrackets(dirEmbed)
} }
type bracketPairer struct { type bracketPairer struct {
@ -125,8 +125,6 @@ func (p *bracketPairer) matchOpener(pairValues []rune, opener, closer int) bool
return pairValues[p.indexes[opener]] == pairValues[p.indexes[closer]] return pairValues[p.indexes[opener]] == pairValues[p.indexes[closer]]
} }
const maxPairingDepth = 63
// locateBrackets locates matching bracket pairs according to BD16. // locateBrackets locates matching bracket pairs according to BD16.
// //
// This implementation uses a linked list instead of a stack, because, while // This implementation uses a linked list instead of a stack, because, while
@ -138,17 +136,11 @@ func (p *bracketPairer) locateBrackets(pairTypes []bracketType, pairValues []run
for i, index := range p.indexes { for i, index := range p.indexes {
// look at the bracket type for each character // look at the bracket type for each character
if pairTypes[index] == bpNone || p.codesIsolatedRun[i] != ON {
// continue scanning
continue
}
switch pairTypes[index] { switch pairTypes[index] {
case bpNone:
// continue scanning
case bpOpen: case bpOpen:
// check if maximum pairing depth reached
if p.openers.Len() == maxPairingDepth {
p.openers.Init()
return
}
// remember opener location, most recent first // remember opener location, most recent first
p.openers.PushFront(i) p.openers.PushFront(i)
@ -278,7 +270,7 @@ func (p *bracketPairer) classBeforePair(loc bracketPair) Class {
} }
// assignBracketType implements rule N0 for a single bracket pair. // assignBracketType implements rule N0 for a single bracket pair.
func (p *bracketPairer) assignBracketType(loc bracketPair, dirEmbed Class, initialTypes []Class) { func (p *bracketPairer) assignBracketType(loc bracketPair, dirEmbed Class) {
// rule "N0, a", inspect contents of pair // rule "N0, a", inspect contents of pair
dirPair := p.classifyPairContent(loc, dirEmbed) dirPair := p.classifyPairContent(loc, dirEmbed)
@ -303,33 +295,13 @@ func (p *bracketPairer) assignBracketType(loc bracketPair, dirEmbed Class, initi
// direction // direction
// set the bracket types to the type found // set the bracket types to the type found
p.setBracketsToType(loc, dirPair, initialTypes)
}
func (p *bracketPairer) setBracketsToType(loc bracketPair, dirPair Class, initialTypes []Class) {
p.codesIsolatedRun[loc.opener] = dirPair p.codesIsolatedRun[loc.opener] = dirPair
p.codesIsolatedRun[loc.closer] = dirPair p.codesIsolatedRun[loc.closer] = dirPair
for i := loc.opener + 1; i < loc.closer; i++ {
index := p.indexes[i]
if initialTypes[index] != NSM {
break
}
p.codesIsolatedRun[i] = dirPair
}
for i := loc.closer + 1; i < len(p.indexes); i++ {
index := p.indexes[i]
if initialTypes[index] != NSM {
break
}
p.codesIsolatedRun[i] = dirPair
}
} }
// resolveBrackets implements rule N0 for a list of pairs. // resolveBrackets implements rule N0 for a list of pairs.
func (p *bracketPairer) resolveBrackets(dirEmbed Class, initialTypes []Class) { func (p *bracketPairer) resolveBrackets(dirEmbed Class) {
for _, loc := range p.pairPositions { for _, loc := range p.pairPositions {
p.assignBracketType(loc, dirEmbed, initialTypes) p.assignBracketType(loc, dirEmbed)
} }
} }

View file

@ -309,9 +309,6 @@ func (p *paragraph) determineExplicitEmbeddingLevels() {
} }
if isIsolate { if isIsolate {
p.resultLevels[i] = stack.lastEmbeddingLevel() p.resultLevels[i] = stack.lastEmbeddingLevel()
if stack.lastDirectionalOverrideStatus() != ON {
p.resultTypes[i] = stack.lastDirectionalOverrideStatus()
}
} }
var newLevel level var newLevel level

View file

@ -8,11 +8,7 @@
// Package norm contains types and functions for normalizing Unicode strings. // Package norm contains types and functions for normalizing Unicode strings.
package norm // import "golang.org/x/text/unicode/norm" package norm // import "golang.org/x/text/unicode/norm"
import ( import "unicode/utf8"
"unicode/utf8"
"golang.org/x/text/transform"
)
// A Form denotes a canonical representation of Unicode code points. // A Form denotes a canonical representation of Unicode code points.
// The Unicode-defined normalization and equivalence forms are: // The Unicode-defined normalization and equivalence forms are:
@ -267,34 +263,6 @@ func (f Form) QuickSpan(b []byte) int {
return n return n
} }
// Span implements transform.SpanningTransformer. It returns a boundary n such
// that b[0:n] == f(b[0:n]). It is not guaranteed to return the largest such n.
func (f Form) Span(b []byte, atEOF bool) (n int, err error) {
n, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), atEOF)
if n < len(b) {
if !ok {
err = transform.ErrEndOfSpan
} else {
err = transform.ErrShortSrc
}
}
return n, err
}
// SpanString returns a boundary n such that s[0:n] == f(s[0:n]).
// It is not guaranteed to return the largest such n.
func (f Form) SpanString(s string, atEOF bool) (n int, err error) {
n, ok := formTable[f].quickSpan(inputString(s), 0, len(s), atEOF)
if n < len(s) {
if !ok {
err = transform.ErrEndOfSpan
} else {
err = transform.ErrShortSrc
}
}
return n, err
}
// quickSpan returns a boundary n such that src[0:n] == f(src[0:n]) and // quickSpan returns a boundary n such that src[0:n] == f(src[0:n]) and
// whether any non-normalized parts were found. If atEOF is false, n will // whether any non-normalized parts were found. If atEOF is false, n will
// not point past the last segment if this segment might be become // not point past the last segment if this segment might be become
@ -353,7 +321,7 @@ func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool)
return lastSegStart, false return lastSegStart, false
} }
// QuickSpanString returns a boundary n such that s[0:n] == f(s[0:n]). // QuickSpanString returns a boundary n such that b[0:n] == f(s[0:n]).
// It is not guaranteed to return the largest such n. // It is not guaranteed to return the largest such n.
func (f Form) QuickSpanString(s string) int { func (f Form) QuickSpanString(s string) int {
n, _ := formTable[f].quickSpan(inputString(s), 0, len(s), true) n, _ := formTable[f].quickSpan(inputString(s), 0, len(s), true)

View file

@ -112,6 +112,7 @@ func (r *normReader) Read(p []byte) (int, error) {
} }
} }
} }
panic("should not reach here")
} }
// Reader returns a new reader that implements Read // Reader returns a new reader that implements Read

View file

@ -14,32 +14,6 @@ type foldTransform struct {
transform.NopResetter transform.NopResetter
} }
func (foldTransform) Span(src []byte, atEOF bool) (n int, err error) {
for n < len(src) {
if src[n] < utf8.RuneSelf {
// ASCII fast path.
for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
}
continue
}
v, size := trie.lookup(src[n:])
if size == 0 { // incomplete UTF-8 encoding
if !atEOF {
err = transform.ErrShortSrc
} else {
n = len(src)
}
break
}
if elem(v)&tagNeedsFold != 0 {
err = transform.ErrEndOfSpan
break
}
n += size
}
return n, err
}
func (foldTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (foldTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for nSrc < len(src) { for nSrc < len(src) {
if src[nSrc] < utf8.RuneSelf { if src[nSrc] < utf8.RuneSelf {
@ -96,33 +70,6 @@ type narrowTransform struct {
transform.NopResetter transform.NopResetter
} }
func (narrowTransform) Span(src []byte, atEOF bool) (n int, err error) {
for n < len(src) {
if src[n] < utf8.RuneSelf {
// ASCII fast path.
for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
}
continue
}
v, size := trie.lookup(src[n:])
if size == 0 { // incomplete UTF-8 encoding
if !atEOF {
err = transform.ErrShortSrc
} else {
n = len(src)
}
break
}
if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
} else {
err = transform.ErrEndOfSpan
break
}
n += size
}
return n, err
}
func (narrowTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (narrowTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for nSrc < len(src) { for nSrc < len(src) {
if src[nSrc] < utf8.RuneSelf { if src[nSrc] < utf8.RuneSelf {
@ -179,30 +126,6 @@ type wideTransform struct {
transform.NopResetter transform.NopResetter
} }
func (wideTransform) Span(src []byte, atEOF bool) (n int, err error) {
for n < len(src) {
// TODO: Consider ASCII fast path. Special-casing ASCII handling can
// reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
// not enough to warrant the extra code and complexity.
v, size := trie.lookup(src[n:])
if size == 0 { // incomplete UTF-8 encoding
if !atEOF {
err = transform.ErrShortSrc
} else {
n = len(src)
}
break
}
if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
} else {
err = transform.ErrEndOfSpan
break
}
n += size
}
return n, err
}
func (wideTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (wideTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for nSrc < len(src) { for nSrc < len(src) {
// TODO: Consider ASCII fast path. Special-casing ASCII handling can // TODO: Consider ASCII fast path. Special-casing ASCII handling can

View file

@ -153,22 +153,17 @@ func (p Properties) Wide() rune {
// Transformer implements the transform.Transformer interface. // Transformer implements the transform.Transformer interface.
type Transformer struct { type Transformer struct {
t transform.SpanningTransformer t transform.Transformer
} }
// Reset implements the transform.Transformer interface. // Reset implements the transform.Transformer interface.
func (t Transformer) Reset() { t.t.Reset() } func (t Transformer) Reset() { t.t.Reset() }
// Transform implements the transform.Transformer interface. // Transform implements the Transformer interface.
func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
return t.t.Transform(dst, src, atEOF) return t.t.Transform(dst, src, atEOF)
} }
// Span implements the transform.SpanningTransformer interface.
func (t Transformer) Span(src []byte, atEOF bool) (n int, err error) {
return t.t.Span(src, atEOF)
}
// Bytes returns a new byte slice with the result of applying t to b. // Bytes returns a new byte slice with the result of applying t to b.
func (t Transformer) Bytes(b []byte) []byte { func (t Transformer) Bytes(b []byte) []byte {
b, _, _ = transform.Bytes(t, b) b, _, _ = transform.Bytes(t, b)

View file

@ -17,6 +17,42 @@ import (
"google.golang.org/appengine/internal" "google.golang.org/appengine/internal"
) )
// The gophers party all night; the rabbits provide the beats.
// Main is the principal entry point for an app running in App Engine.
//
// On App Engine Flexible it installs a trivial health checker if one isn't
// already registered, and starts listening on port 8080 (overridden by the
// $PORT environment variable).
//
// See https://cloud.google.com/appengine/docs/flexible/custom-runtimes#health_check_requests
// for details on how to do your own health checking.
//
// Main is not yet supported on App Engine Standard.
//
// Main never returns.
//
// Main is designed so that the app's main package looks like this:
//
// package main
//
// import (
// "google.golang.org/appengine"
//
// _ "myapp/package0"
// _ "myapp/package1"
// )
//
// func main() {
// appengine.Main()
// }
//
// The "myapp/packageX" packages are expected to register HTTP handlers
// in their init functions.
func Main() {
internal.Main()
}
// IsDevAppServer reports whether the App Engine app is running in the // IsDevAppServer reports whether the App Engine app is running in the
// development App Server. // development App Server.
func IsDevAppServer() bool { func IsDevAppServer() bool {

Some files were not shown because too many files have changed in this diff Show more