mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-31 16:13:45 +08:00 
			
		
		
		
	vendor: update Cobra v1.0.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
		
							
								
								
									
										73
									
								
								vendor/github.com/prometheus/client_golang/prometheus/collector.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/prometheus/client_golang/prometheus/collector.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -29,27 +29,72 @@ type Collector interface { | ||||
| 	// collected by this Collector to the provided channel and returns once | ||||
| 	// the last descriptor has been sent. The sent descriptors fulfill the | ||||
| 	// consistency and uniqueness requirements described in the Desc | ||||
| 	// documentation. (It is valid if one and the same Collector sends | ||||
| 	// duplicate descriptors. Those duplicates are simply ignored. However, | ||||
| 	// two different Collectors must not send duplicate descriptors.) This | ||||
| 	// method idempotently sends the same descriptors throughout the | ||||
| 	// lifetime of the Collector. If a Collector encounters an error while | ||||
| 	// executing this method, it must send an invalid descriptor (created | ||||
| 	// with NewInvalidDesc) to signal the error to the registry. | ||||
| 	// documentation. | ||||
| 	// | ||||
| 	// It is valid if one and the same Collector sends duplicate | ||||
| 	// descriptors. Those duplicates are simply ignored. However, two | ||||
| 	// different Collectors must not send duplicate descriptors. | ||||
| 	// | ||||
| 	// Sending no descriptor at all marks the Collector as “unchecked”, | ||||
| 	// i.e. no checks will be performed at registration time, and the | ||||
| 	// Collector may yield any Metric it sees fit in its Collect method. | ||||
| 	// | ||||
| 	// This method idempotently sends the same descriptors throughout the | ||||
| 	// lifetime of the Collector. It may be called concurrently and | ||||
| 	// therefore must be implemented in a concurrency safe way. | ||||
| 	// | ||||
| 	// If a Collector encounters an error while executing this method, it | ||||
| 	// must send an invalid descriptor (created with NewInvalidDesc) to | ||||
| 	// signal the error to the registry. | ||||
| 	Describe(chan<- *Desc) | ||||
| 	// Collect is called by the Prometheus registry when collecting | ||||
| 	// metrics. The implementation sends each collected metric via the | ||||
| 	// provided channel and returns once the last metric has been sent. The | ||||
| 	// descriptor of each sent metric is one of those returned by | ||||
| 	// Describe. Returned metrics that share the same descriptor must differ | ||||
| 	// in their variable label values. This method may be called | ||||
| 	// concurrently and must therefore be implemented in a concurrency safe | ||||
| 	// way. Blocking occurs at the expense of total performance of rendering | ||||
| 	// all registered metrics. Ideally, Collector implementations support | ||||
| 	// concurrent readers. | ||||
| 	// descriptor of each sent metric is one of those returned by Describe | ||||
| 	// (unless the Collector is unchecked, see above). Returned metrics that | ||||
| 	// share the same descriptor must differ in their variable label | ||||
| 	// values. | ||||
| 	// | ||||
| 	// This method may be called concurrently and must therefore be | ||||
| 	// implemented in a concurrency safe way. Blocking occurs at the expense | ||||
| 	// of total performance of rendering all registered metrics. Ideally, | ||||
| 	// Collector implementations support concurrent readers. | ||||
| 	Collect(chan<- Metric) | ||||
| } | ||||
|  | ||||
| // DescribeByCollect is a helper to implement the Describe method of a custom | ||||
| // Collector. It collects the metrics from the provided Collector and sends | ||||
| // their descriptors to the provided channel. | ||||
| // | ||||
| // If a Collector collects the same metrics throughout its lifetime, its | ||||
| // Describe method can simply be implemented as: | ||||
| // | ||||
| //   func (c customCollector) Describe(ch chan<- *Desc) { | ||||
| //   	DescribeByCollect(c, ch) | ||||
| //   } | ||||
| // | ||||
| // However, this will not work if the metrics collected change dynamically over | ||||
| // the lifetime of the Collector in a way that their combined set of descriptors | ||||
| // changes as well. The shortcut implementation will then violate the contract | ||||
| // of the Describe method. If a Collector sometimes collects no metrics at all | ||||
| // (for example vectors like CounterVec, GaugeVec, etc., which only collect | ||||
| // metrics after a metric with a fully specified label set has been accessed), | ||||
| // it might even get registered as an unchecked Collector (cf. the Register | ||||
| // method of the Registerer interface). Hence, only use this shortcut | ||||
| // implementation of Describe if you are certain to fulfill the contract. | ||||
| // | ||||
| // The Collector example demonstrates a use of DescribeByCollect. | ||||
| func DescribeByCollect(c Collector, descs chan<- *Desc) { | ||||
| 	metrics := make(chan Metric) | ||||
| 	go func() { | ||||
| 		c.Collect(metrics) | ||||
| 		close(metrics) | ||||
| 	}() | ||||
| 	for m := range metrics { | ||||
| 		descs <- m.Desc() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // selfCollector implements Collector for a single Metric so that the Metric | ||||
| // collects itself. Add it as an anonymous field to a struct that implements | ||||
| // Metric, and call init with the Metric itself as an argument. | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/prometheus/client_golang/prometheus/counter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/prometheus/client_golang/prometheus/counter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -136,7 +136,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec { | ||||
| 	return &CounterVec{ | ||||
| 		metricVec: newMetricVec(desc, func(lvs ...string) Metric { | ||||
| 			if len(lvs) != len(desc.variableLabels) { | ||||
| 				panic(errInconsistentCardinality) | ||||
| 				panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) | ||||
| 			} | ||||
| 			result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs)} | ||||
| 			result.init(result) // Init self-collection. | ||||
|   | ||||
							
								
								
									
										12
									
								
								vendor/github.com/prometheus/client_golang/prometheus/desc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/prometheus/client_golang/prometheus/desc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -67,7 +67,7 @@ type Desc struct { | ||||
|  | ||||
| // NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc | ||||
| // and will be reported on registration time. variableLabels and constLabels can | ||||
| // be nil if no such labels should be set. fqName and help must not be empty. | ||||
| // be nil if no such labels should be set. fqName must not be empty. | ||||
| // | ||||
| // variableLabels only contain the label names. Their label values are variable | ||||
| // and therefore not part of the Desc. (They are managed within the Metric.) | ||||
| @@ -80,10 +80,6 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * | ||||
| 		help:           help, | ||||
| 		variableLabels: variableLabels, | ||||
| 	} | ||||
| 	if help == "" { | ||||
| 		d.err = errors.New("empty help string") | ||||
| 		return d | ||||
| 	} | ||||
| 	if !model.IsValidMetricName(model.LabelValue(fqName)) { | ||||
| 		d.err = fmt.Errorf("%q is not a valid metric name", fqName) | ||||
| 		return d | ||||
| @@ -97,7 +93,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * | ||||
| 	// First add only the const label names and sort them... | ||||
| 	for labelName := range constLabels { | ||||
| 		if !checkLabelName(labelName) { | ||||
| 			d.err = fmt.Errorf("%q is not a valid label name", labelName) | ||||
| 			d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName) | ||||
| 			return d | ||||
| 		} | ||||
| 		labelNames = append(labelNames, labelName) | ||||
| @@ -119,7 +115,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * | ||||
| 	// dimension with a different mix between preset and variable labels. | ||||
| 	for _, labelName := range variableLabels { | ||||
| 		if !checkLabelName(labelName) { | ||||
| 			d.err = fmt.Errorf("%q is not a valid label name", labelName) | ||||
| 			d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName) | ||||
| 			return d | ||||
| 		} | ||||
| 		labelNames = append(labelNames, "$"+labelName) | ||||
| @@ -156,7 +152,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * | ||||
| 			Value: proto.String(v), | ||||
| 		}) | ||||
| 	} | ||||
| 	sort.Sort(LabelPairSorter(d.constLabelPairs)) | ||||
| 	sort.Sort(labelPairSorter(d.constLabelPairs)) | ||||
| 	return d | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										27
									
								
								vendor/github.com/prometheus/client_golang/prometheus/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/prometheus/client_golang/prometheus/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,10 +11,12 @@ | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| // Package prometheus provides metrics primitives to instrument code for | ||||
| // monitoring. It also offers a registry for metrics. Sub-packages allow to | ||||
| // expose the registered metrics via HTTP (package promhttp) or push them to a | ||||
| // Pushgateway (package push). | ||||
| // Package prometheus is the core instrumentation package. It provides metrics | ||||
| // primitives to instrument code for monitoring. It also offers a registry for | ||||
| // metrics. Sub-packages allow to expose the registered metrics via HTTP | ||||
| // (package promhttp) or push them to a Pushgateway (package push). There is | ||||
| // also a sub-package promauto, which provides metrics constructors with | ||||
| // automatic registration. | ||||
| // | ||||
| // All exported functions and methods are safe to be used concurrently unless | ||||
| // specified otherwise. | ||||
| @@ -72,7 +74,10 @@ | ||||
| // The number of exported identifiers in this package might appear a bit | ||||
| // overwhelming. However, in addition to the basic plumbing shown in the example | ||||
| // above, you only need to understand the different metric types and their | ||||
| // vector versions for basic usage. | ||||
| // vector versions for basic usage. Furthermore, if you are not concerned with | ||||
| // fine-grained control of when and how to register metrics with the registry, | ||||
| // have a look at the promauto package, which will effectively allow you to | ||||
| // ignore registration altogether in simple cases. | ||||
| // | ||||
| // Above, you have already touched the Counter and the Gauge. There are two more | ||||
| // advanced metric types: the Summary and Histogram. A more thorough description | ||||
| @@ -116,7 +121,17 @@ | ||||
| // NewConstSummary (and their respective Must… versions). That will happen in | ||||
| // the Collect method. The Describe method has to return separate Desc | ||||
| // instances, representative of the “throw-away” metrics to be created later. | ||||
| // NewDesc comes in handy to create those Desc instances. | ||||
| // NewDesc comes in handy to create those Desc instances. Alternatively, you | ||||
| // could return no Desc at all, which will mark the Collector “unchecked”.  No | ||||
| // checks are performed at registration time, but metric consistency will still | ||||
| // be ensured at scrape time, i.e. any inconsistencies will lead to scrape | ||||
| // errors. Thus, with unchecked Collectors, the responsibility to not collect | ||||
| // metrics that lead to inconsistencies in the total scrape result lies with the | ||||
| // implementer of the Collector. While this is not a desirable state, it is | ||||
| // sometimes necessary. The typical use case is a situation where the exact | ||||
| // metrics to be returned by a Collector cannot be predicted at registration | ||||
| // time, but the implementer has sufficient knowledge of the whole system to | ||||
| // guarantee metric consistency. | ||||
| // | ||||
| // The Collector example illustrates the use case. You can also look at the | ||||
| // source code of the processCollector (mirroring process metrics), the | ||||
|   | ||||
							
								
								
									
										13
									
								
								vendor/github.com/prometheus/client_golang/prometheus/fnv.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/prometheus/client_golang/prometheus/fnv.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,3 +1,16 @@ | ||||
| // Copyright 2018 The Prometheus Authors | ||||
| // 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 prometheus | ||||
|  | ||||
| // Inline and byte-free variant of hash/fnv's fnv64a. | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/prometheus/client_golang/prometheus/gauge.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/prometheus/client_golang/prometheus/gauge.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -147,7 +147,7 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec { | ||||
| 	return &GaugeVec{ | ||||
| 		metricVec: newMetricVec(desc, func(lvs ...string) Metric { | ||||
| 			if len(lvs) != len(desc.variableLabels) { | ||||
| 				panic(errInconsistentCardinality) | ||||
| 				panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) | ||||
| 			} | ||||
| 			result := &gauge{desc: desc, labelPairs: makeLabelPairs(desc, lvs)} | ||||
| 			result.init(result) // Init self-collection. | ||||
|   | ||||
							
								
								
									
										106
									
								
								vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										106
									
								
								vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,9 +1,22 @@ | ||||
| // Copyright 2018 The Prometheus Authors | ||||
| // 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 prometheus | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"runtime" | ||||
| 	"runtime/debug" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| @@ -13,12 +26,41 @@ type goCollector struct { | ||||
| 	gcDesc         *Desc | ||||
| 	goInfoDesc     *Desc | ||||
|  | ||||
| 	// metrics to describe and collect | ||||
| 	metrics memStatsMetrics | ||||
| 	// ms... are memstats related. | ||||
| 	msLast          *runtime.MemStats // Previously collected memstats. | ||||
| 	msLastTimestamp time.Time | ||||
| 	msMtx           sync.Mutex // Protects msLast and msLastTimestamp. | ||||
| 	msMetrics       memStatsMetrics | ||||
| 	msRead          func(*runtime.MemStats) // For mocking in tests. | ||||
| 	msMaxWait       time.Duration           // Wait time for fresh memstats. | ||||
| 	msMaxAge        time.Duration           // Maximum allowed age of old memstats. | ||||
| } | ||||
|  | ||||
| // NewGoCollector returns a collector which exports metrics about the current | ||||
| // go process. | ||||
| // NewGoCollector returns a collector which exports metrics about the current Go | ||||
| // process. This includes memory stats. To collect those, runtime.ReadMemStats | ||||
| // is called. This requires to “stop the world”, which usually only happens for | ||||
| // garbage collection (GC). Take the following implications into account when | ||||
| // deciding whether to use the Go collector: | ||||
| // | ||||
| // 1. The performance impact of stopping the world is the more relevant the more | ||||
| // frequently metrics are collected. However, with Go1.9 or later the | ||||
| // stop-the-world time per metrics collection is very short (~25µs) so that the | ||||
| // performance impact will only matter in rare cases. However, with older Go | ||||
| // versions, the stop-the-world duration depends on the heap size and can be | ||||
| // quite significant (~1.7 ms/GiB as per | ||||
| // https://go-review.googlesource.com/c/go/+/34937). | ||||
| // | ||||
| // 2. During an ongoing GC, nothing else can stop the world. Therefore, if the | ||||
| // metrics collection happens to coincide with GC, it will only complete after | ||||
| // GC has finished. Usually, GC is fast enough to not cause problems. However, | ||||
| // with a very large heap, GC might take multiple seconds, which is enough to | ||||
| // cause scrape timeouts in common setups. To avoid this problem, the Go | ||||
| // collector will use the memstats from a previous collection if | ||||
| // runtime.ReadMemStats takes more than 1s. However, if there are no previously | ||||
| // collected memstats, or their collection is more than 5m ago, the collection | ||||
| // will block until runtime.ReadMemStats succeeds. (The problem might be solved | ||||
| // in Go1.13, see https://github.com/golang/go/issues/19812 for the related Go | ||||
| // issue.) | ||||
| func NewGoCollector() Collector { | ||||
| 	return &goCollector{ | ||||
| 		goroutinesDesc: NewDesc( | ||||
| @@ -37,7 +79,11 @@ func NewGoCollector() Collector { | ||||
| 			"go_info", | ||||
| 			"Information about the Go environment.", | ||||
| 			nil, Labels{"version": runtime.Version()}), | ||||
| 		metrics: memStatsMetrics{ | ||||
| 		msLast:    &runtime.MemStats{}, | ||||
| 		msRead:    runtime.ReadMemStats, | ||||
| 		msMaxWait: time.Second, | ||||
| 		msMaxAge:  5 * time.Minute, | ||||
| 		msMetrics: memStatsMetrics{ | ||||
| 			{ | ||||
| 				desc: NewDesc( | ||||
| 					memstatNamespace("alloc_bytes"), | ||||
| @@ -236,7 +282,7 @@ func NewGoCollector() Collector { | ||||
| } | ||||
|  | ||||
| func memstatNamespace(s string) string { | ||||
| 	return fmt.Sprintf("go_memstats_%s", s) | ||||
| 	return "go_memstats_" + s | ||||
| } | ||||
|  | ||||
| // Describe returns all descriptions of the collector. | ||||
| @@ -245,13 +291,27 @@ func (c *goCollector) Describe(ch chan<- *Desc) { | ||||
| 	ch <- c.threadsDesc | ||||
| 	ch <- c.gcDesc | ||||
| 	ch <- c.goInfoDesc | ||||
| 	for _, i := range c.metrics { | ||||
| 	for _, i := range c.msMetrics { | ||||
| 		ch <- i.desc | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Collect returns the current state of all metrics of the collector. | ||||
| func (c *goCollector) Collect(ch chan<- Metric) { | ||||
| 	var ( | ||||
| 		ms   = &runtime.MemStats{} | ||||
| 		done = make(chan struct{}) | ||||
| 	) | ||||
| 	// Start reading memstats first as it might take a while. | ||||
| 	go func() { | ||||
| 		c.msRead(ms) | ||||
| 		c.msMtx.Lock() | ||||
| 		c.msLast = ms | ||||
| 		c.msLastTimestamp = time.Now() | ||||
| 		c.msMtx.Unlock() | ||||
| 		close(done) | ||||
| 	}() | ||||
|  | ||||
| 	ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine())) | ||||
| 	n, _ := runtime.ThreadCreateProfile(nil) | ||||
| 	ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n)) | ||||
| @@ -265,13 +325,35 @@ func (c *goCollector) Collect(ch chan<- Metric) { | ||||
| 		quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds() | ||||
| 	} | ||||
| 	quantiles[0.0] = stats.PauseQuantiles[0].Seconds() | ||||
| 	ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles) | ||||
| 	ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), stats.PauseTotal.Seconds(), quantiles) | ||||
|  | ||||
| 	ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1) | ||||
|  | ||||
| 	ms := &runtime.MemStats{} | ||||
| 	runtime.ReadMemStats(ms) | ||||
| 	for _, i := range c.metrics { | ||||
| 	timer := time.NewTimer(c.msMaxWait) | ||||
| 	select { | ||||
| 	case <-done: // Our own ReadMemStats succeeded in time. Use it. | ||||
| 		timer.Stop() // Important for high collection frequencies to not pile up timers. | ||||
| 		c.msCollect(ch, ms) | ||||
| 		return | ||||
| 	case <-timer.C: // Time out, use last memstats if possible. Continue below. | ||||
| 	} | ||||
| 	c.msMtx.Lock() | ||||
| 	if time.Since(c.msLastTimestamp) < c.msMaxAge { | ||||
| 		// Last memstats are recent enough. Collect from them under the lock. | ||||
| 		c.msCollect(ch, c.msLast) | ||||
| 		c.msMtx.Unlock() | ||||
| 		return | ||||
| 	} | ||||
| 	// If we are here, the last memstats are too old or don't exist. We have | ||||
| 	// to wait until our own ReadMemStats finally completes. For that to | ||||
| 	// happen, we have to release the lock. | ||||
| 	c.msMtx.Unlock() | ||||
| 	<-done | ||||
| 	c.msCollect(ch, ms) | ||||
| } | ||||
|  | ||||
| func (c *goCollector) msCollect(ch chan<- Metric, ms *runtime.MemStats) { | ||||
| 	for _, i := range c.msMetrics { | ||||
| 		ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms)) | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										135
									
								
								vendor/github.com/prometheus/client_golang/prometheus/histogram.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										135
									
								
								vendor/github.com/prometheus/client_golang/prometheus/histogram.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -16,7 +16,9 @@ package prometheus | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"runtime" | ||||
| 	"sort" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| @@ -108,8 +110,9 @@ func ExponentialBuckets(start, factor float64, count int) []float64 { | ||||
| } | ||||
|  | ||||
| // HistogramOpts bundles the options for creating a Histogram metric. It is | ||||
| // mandatory to set Name and Help to a non-empty string. All other fields are | ||||
| // optional and can safely be left at their zero value. | ||||
| // mandatory to set Name to a non-empty string. All other fields are optional | ||||
| // and can safely be left at their zero value, although it is strongly | ||||
| // encouraged to set a Help string. | ||||
| type HistogramOpts struct { | ||||
| 	// Namespace, Subsystem, and Name are components of the fully-qualified | ||||
| 	// name of the Histogram (created by joining these components with | ||||
| @@ -120,7 +123,7 @@ type HistogramOpts struct { | ||||
| 	Subsystem string | ||||
| 	Name      string | ||||
|  | ||||
| 	// Help provides information about this Histogram. Mandatory! | ||||
| 	// Help provides information about this Histogram. | ||||
| 	// | ||||
| 	// Metrics with the same fully-qualified name must have the same Help | ||||
| 	// string. | ||||
| @@ -162,7 +165,7 @@ func NewHistogram(opts HistogramOpts) Histogram { | ||||
|  | ||||
| func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogram { | ||||
| 	if len(desc.variableLabels) != len(labelValues) { | ||||
| 		panic(errInconsistentCardinality) | ||||
| 		panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) | ||||
| 	} | ||||
|  | ||||
| 	for _, n := range desc.variableLabels { | ||||
| @@ -184,6 +187,7 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr | ||||
| 		desc:        desc, | ||||
| 		upperBounds: opts.Buckets, | ||||
| 		labelPairs:  makeLabelPairs(desc, labelValues), | ||||
| 		counts:      [2]*histogramCounts{&histogramCounts{}, &histogramCounts{}}, | ||||
| 	} | ||||
| 	for i, upperBound := range h.upperBounds { | ||||
| 		if i < len(h.upperBounds)-1 { | ||||
| @@ -200,30 +204,56 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// Finally we know the final length of h.upperBounds and can make counts. | ||||
| 	h.counts = make([]uint64, len(h.upperBounds)) | ||||
| 	// Finally we know the final length of h.upperBounds and can make buckets | ||||
| 	// for both counts: | ||||
| 	h.counts[0].buckets = make([]uint64, len(h.upperBounds)) | ||||
| 	h.counts[1].buckets = make([]uint64, len(h.upperBounds)) | ||||
|  | ||||
| 	h.init(h) // Init self-collection. | ||||
| 	return h | ||||
| } | ||||
|  | ||||
| type histogram struct { | ||||
| type histogramCounts struct { | ||||
| 	// sumBits contains the bits of the float64 representing the sum of all | ||||
| 	// observations. sumBits and count have to go first in the struct to | ||||
| 	// guarantee alignment for atomic operations. | ||||
| 	// http://golang.org/pkg/sync/atomic/#pkg-note-BUG | ||||
| 	sumBits uint64 | ||||
| 	count   uint64 | ||||
| 	buckets []uint64 | ||||
| } | ||||
|  | ||||
| type histogram struct { | ||||
| 	// countAndHotIdx enables lock-free writes with use of atomic updates. | ||||
| 	// The most significant bit is the hot index [0 or 1] of the count field | ||||
| 	// below. Observe calls update the hot one. All remaining bits count the | ||||
| 	// number of Observe calls. Observe starts by incrementing this counter, | ||||
| 	// and finish by incrementing the count field in the respective | ||||
| 	// histogramCounts, as a marker for completion. | ||||
| 	// | ||||
| 	// Calls of the Write method (which are non-mutating reads from the | ||||
| 	// perspective of the histogram) swap the hot–cold under the writeMtx | ||||
| 	// lock. A cooldown is awaited (while locked) by comparing the number of | ||||
| 	// observations with the initiation count. Once they match, then the | ||||
| 	// last observation on the now cool one has completed. All cool fields must | ||||
| 	// be merged into the new hot before releasing writeMtx. | ||||
| 	// | ||||
| 	// Fields with atomic access first! See alignment constraint: | ||||
| 	// http://golang.org/pkg/sync/atomic/#pkg-note-BUG | ||||
| 	countAndHotIdx uint64 | ||||
|  | ||||
| 	selfCollector | ||||
| 	// Note that there is no mutex required. | ||||
| 	desc     *Desc | ||||
| 	writeMtx sync.Mutex // Only used in the Write method. | ||||
|  | ||||
| 	desc *Desc | ||||
| 	// Two counts, one is "hot" for lock-free observations, the other is | ||||
| 	// "cold" for writing out a dto.Metric. It has to be an array of | ||||
| 	// pointers to guarantee 64bit alignment of the histogramCounts, see | ||||
| 	// http://golang.org/pkg/sync/atomic/#pkg-note-BUG. | ||||
| 	counts [2]*histogramCounts | ||||
|  | ||||
| 	upperBounds []float64 | ||||
| 	counts      []uint64 | ||||
|  | ||||
| 	labelPairs []*dto.LabelPair | ||||
| 	labelPairs  []*dto.LabelPair | ||||
| } | ||||
|  | ||||
| func (h *histogram) Desc() *Desc { | ||||
| @@ -241,36 +271,84 @@ func (h *histogram) Observe(v float64) { | ||||
| 	// 100 buckets: 78.1 ns/op linear - binary 54.9 ns/op | ||||
| 	// 300 buckets: 154 ns/op linear - binary 61.6 ns/op | ||||
| 	i := sort.SearchFloat64s(h.upperBounds, v) | ||||
| 	if i < len(h.counts) { | ||||
| 		atomic.AddUint64(&h.counts[i], 1) | ||||
|  | ||||
| 	// We increment h.countAndHotIdx so that the counter in the lower | ||||
| 	// 63 bits gets incremented. At the same time, we get the new value | ||||
| 	// back, which we can use to find the currently-hot counts. | ||||
| 	n := atomic.AddUint64(&h.countAndHotIdx, 1) | ||||
| 	hotCounts := h.counts[n>>63] | ||||
|  | ||||
| 	if i < len(h.upperBounds) { | ||||
| 		atomic.AddUint64(&hotCounts.buckets[i], 1) | ||||
| 	} | ||||
| 	atomic.AddUint64(&h.count, 1) | ||||
| 	for { | ||||
| 		oldBits := atomic.LoadUint64(&h.sumBits) | ||||
| 		oldBits := atomic.LoadUint64(&hotCounts.sumBits) | ||||
| 		newBits := math.Float64bits(math.Float64frombits(oldBits) + v) | ||||
| 		if atomic.CompareAndSwapUint64(&h.sumBits, oldBits, newBits) { | ||||
| 		if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	// Increment count last as we take it as a signal that the observation | ||||
| 	// is complete. | ||||
| 	atomic.AddUint64(&hotCounts.count, 1) | ||||
| } | ||||
|  | ||||
| func (h *histogram) Write(out *dto.Metric) error { | ||||
| 	his := &dto.Histogram{} | ||||
| 	buckets := make([]*dto.Bucket, len(h.upperBounds)) | ||||
| 	// For simplicity, we protect this whole method by a mutex. It is not in | ||||
| 	// the hot path, i.e. Observe is called much more often than Write. The | ||||
| 	// complication of making Write lock-free isn't worth it, if possible at | ||||
| 	// all. | ||||
| 	h.writeMtx.Lock() | ||||
| 	defer h.writeMtx.Unlock() | ||||
|  | ||||
| 	his.SampleSum = proto.Float64(math.Float64frombits(atomic.LoadUint64(&h.sumBits))) | ||||
| 	his.SampleCount = proto.Uint64(atomic.LoadUint64(&h.count)) | ||||
| 	var count uint64 | ||||
| 	// Adding 1<<63 switches the hot index (from 0 to 1 or from 1 to 0) | ||||
| 	// without touching the count bits. See the struct comments for a full | ||||
| 	// description of the algorithm. | ||||
| 	n := atomic.AddUint64(&h.countAndHotIdx, 1<<63) | ||||
| 	// count is contained unchanged in the lower 63 bits. | ||||
| 	count := n & ((1 << 63) - 1) | ||||
| 	// The most significant bit tells us which counts is hot. The complement | ||||
| 	// is thus the cold one. | ||||
| 	hotCounts := h.counts[n>>63] | ||||
| 	coldCounts := h.counts[(^n)>>63] | ||||
|  | ||||
| 	// Await cooldown. | ||||
| 	for count != atomic.LoadUint64(&coldCounts.count) { | ||||
| 		runtime.Gosched() // Let observations get work done. | ||||
| 	} | ||||
|  | ||||
| 	his := &dto.Histogram{ | ||||
| 		Bucket:      make([]*dto.Bucket, len(h.upperBounds)), | ||||
| 		SampleCount: proto.Uint64(count), | ||||
| 		SampleSum:   proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), | ||||
| 	} | ||||
| 	var cumCount uint64 | ||||
| 	for i, upperBound := range h.upperBounds { | ||||
| 		count += atomic.LoadUint64(&h.counts[i]) | ||||
| 		buckets[i] = &dto.Bucket{ | ||||
| 			CumulativeCount: proto.Uint64(count), | ||||
| 		cumCount += atomic.LoadUint64(&coldCounts.buckets[i]) | ||||
| 		his.Bucket[i] = &dto.Bucket{ | ||||
| 			CumulativeCount: proto.Uint64(cumCount), | ||||
| 			UpperBound:      proto.Float64(upperBound), | ||||
| 		} | ||||
| 	} | ||||
| 	his.Bucket = buckets | ||||
|  | ||||
| 	out.Histogram = his | ||||
| 	out.Label = h.labelPairs | ||||
|  | ||||
| 	// Finally add all the cold counts to the new hot counts and reset the cold counts. | ||||
| 	atomic.AddUint64(&hotCounts.count, count) | ||||
| 	atomic.StoreUint64(&coldCounts.count, 0) | ||||
| 	for { | ||||
| 		oldBits := atomic.LoadUint64(&hotCounts.sumBits) | ||||
| 		newBits := math.Float64bits(math.Float64frombits(oldBits) + his.GetSampleSum()) | ||||
| 		if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { | ||||
| 			atomic.StoreUint64(&coldCounts.sumBits, 0) | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	for i := range h.upperBounds { | ||||
| 		atomic.AddUint64(&hotCounts.buckets[i], atomic.LoadUint64(&coldCounts.buckets[i])) | ||||
| 		atomic.StoreUint64(&coldCounts.buckets[i], 0) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -454,7 +532,7 @@ func (h *constHistogram) Write(out *dto.Metric) error { | ||||
| // bucket. | ||||
| // | ||||
| // NewConstHistogram returns an error if the length of labelValues is not | ||||
| // consistent with the variable labels in Desc. | ||||
| // consistent with the variable labels in Desc or if Desc is invalid. | ||||
| func NewConstHistogram( | ||||
| 	desc *Desc, | ||||
| 	count uint64, | ||||
| @@ -462,6 +540,9 @@ func NewConstHistogram( | ||||
| 	buckets map[float64]uint64, | ||||
| 	labelValues ...string, | ||||
| ) (Metric, error) { | ||||
| 	if desc.err != nil { | ||||
| 		return nil, desc.err | ||||
| 	} | ||||
| 	if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										156
									
								
								vendor/github.com/prometheus/client_golang/prometheus/http.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										156
									
								
								vendor/github.com/prometheus/client_golang/prometheus/http.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -15,9 +15,7 @@ package prometheus | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"compress/gzip" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| @@ -36,24 +34,14 @@ import ( | ||||
|  | ||||
| const ( | ||||
| 	contentTypeHeader     = "Content-Type" | ||||
| 	contentLengthHeader   = "Content-Length" | ||||
| 	contentEncodingHeader = "Content-Encoding" | ||||
| 	acceptEncodingHeader  = "Accept-Encoding" | ||||
| ) | ||||
|  | ||||
| var bufPool sync.Pool | ||||
|  | ||||
| func getBuf() *bytes.Buffer { | ||||
| 	buf := bufPool.Get() | ||||
| 	if buf == nil { | ||||
| 		return &bytes.Buffer{} | ||||
| 	} | ||||
| 	return buf.(*bytes.Buffer) | ||||
| } | ||||
|  | ||||
| func giveBuf(buf *bytes.Buffer) { | ||||
| 	buf.Reset() | ||||
| 	bufPool.Put(buf) | ||||
| var gzipPool = sync.Pool{ | ||||
| 	New: func() interface{} { | ||||
| 		return gzip.NewWriter(nil) | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // Handler returns an HTTP handler for the DefaultGatherer. It is | ||||
| @@ -61,68 +49,50 @@ func giveBuf(buf *bytes.Buffer) { | ||||
| // name). | ||||
| // | ||||
| // Deprecated: Please note the issues described in the doc comment of | ||||
| // InstrumentHandler. You might want to consider using | ||||
| // promhttp.InstrumentedHandler instead. | ||||
| // InstrumentHandler. You might want to consider using promhttp.Handler instead. | ||||
| func Handler() http.Handler { | ||||
| 	return InstrumentHandler("prometheus", UninstrumentedHandler()) | ||||
| } | ||||
|  | ||||
| // UninstrumentedHandler returns an HTTP handler for the DefaultGatherer. | ||||
| // | ||||
| // Deprecated: Use promhttp.Handler instead. See there for further documentation. | ||||
| // Deprecated: Use promhttp.HandlerFor(DefaultGatherer, promhttp.HandlerOpts{}) | ||||
| // instead. See there for further documentation. | ||||
| func UninstrumentedHandler() http.Handler { | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { | ||||
| 	return http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { | ||||
| 		mfs, err := DefaultGatherer.Gather() | ||||
| 		if err != nil { | ||||
| 			http.Error(w, "An error has occurred during metrics collection:\n\n"+err.Error(), http.StatusInternalServerError) | ||||
| 			httpError(rsp, err) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		contentType := expfmt.Negotiate(req.Header) | ||||
| 		buf := getBuf() | ||||
| 		defer giveBuf(buf) | ||||
| 		writer, encoding := decorateWriter(req, buf) | ||||
| 		enc := expfmt.NewEncoder(writer, contentType) | ||||
| 		var lastErr error | ||||
| 		header := rsp.Header() | ||||
| 		header.Set(contentTypeHeader, string(contentType)) | ||||
|  | ||||
| 		w := io.Writer(rsp) | ||||
| 		if gzipAccepted(req.Header) { | ||||
| 			header.Set(contentEncodingHeader, "gzip") | ||||
| 			gz := gzipPool.Get().(*gzip.Writer) | ||||
| 			defer gzipPool.Put(gz) | ||||
|  | ||||
| 			gz.Reset(w) | ||||
| 			defer gz.Close() | ||||
|  | ||||
| 			w = gz | ||||
| 		} | ||||
|  | ||||
| 		enc := expfmt.NewEncoder(w, contentType) | ||||
|  | ||||
| 		for _, mf := range mfs { | ||||
| 			if err := enc.Encode(mf); err != nil { | ||||
| 				lastErr = err | ||||
| 				http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError) | ||||
| 				httpError(rsp, err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		if closer, ok := writer.(io.Closer); ok { | ||||
| 			closer.Close() | ||||
| 		} | ||||
| 		if lastErr != nil && buf.Len() == 0 { | ||||
| 			http.Error(w, "No metrics encoded, last error:\n\n"+lastErr.Error(), http.StatusInternalServerError) | ||||
| 			return | ||||
| 		} | ||||
| 		header := w.Header() | ||||
| 		header.Set(contentTypeHeader, string(contentType)) | ||||
| 		header.Set(contentLengthHeader, fmt.Sprint(buf.Len())) | ||||
| 		if encoding != "" { | ||||
| 			header.Set(contentEncodingHeader, encoding) | ||||
| 		} | ||||
| 		w.Write(buf.Bytes()) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // decorateWriter wraps a writer to handle gzip compression if requested.  It | ||||
| // returns the decorated writer and the appropriate "Content-Encoding" header | ||||
| // (which is empty if no compression is enabled). | ||||
| func decorateWriter(request *http.Request, writer io.Writer) (io.Writer, string) { | ||||
| 	header := request.Header.Get(acceptEncodingHeader) | ||||
| 	parts := strings.Split(header, ",") | ||||
| 	for _, part := range parts { | ||||
| 		part := strings.TrimSpace(part) | ||||
| 		if part == "gzip" || strings.HasPrefix(part, "gzip;") { | ||||
| 			return gzip.NewWriter(writer), "gzip" | ||||
| 		} | ||||
| 	} | ||||
| 	return writer, "" | ||||
| } | ||||
|  | ||||
| var instLabels = []string{"method", "code"} | ||||
|  | ||||
| type nower interface { | ||||
| @@ -139,16 +109,6 @@ var now nower = nowFunc(func() time.Time { | ||||
| 	return time.Now() | ||||
| }) | ||||
|  | ||||
| func nowSeries(t ...time.Time) nower { | ||||
| 	return nowFunc(func() time.Time { | ||||
| 		defer func() { | ||||
| 			t = t[1:] | ||||
| 		}() | ||||
|  | ||||
| 		return t[0] | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // InstrumentHandler wraps the given HTTP handler for instrumentation. It | ||||
| // registers four metric collectors (if not already done) and reports HTTP | ||||
| // metrics to the (newly or already) registered collectors: http_requests_total | ||||
| @@ -159,21 +119,14 @@ func nowSeries(t ...time.Time) nower { | ||||
| // (label name "method") and HTTP status code (label name "code"). | ||||
| // | ||||
| // Deprecated: InstrumentHandler has several issues. Use the tooling provided in | ||||
| // package promhttp instead. The issues are the following: | ||||
| // | ||||
| // - It uses Summaries rather than Histograms. Summaries are not useful if | ||||
| // aggregation across multiple instances is required. | ||||
| // | ||||
| // - It uses microseconds as unit, which is deprecated and should be replaced by | ||||
| // seconds. | ||||
| // | ||||
| // - The size of the request is calculated in a separate goroutine. Since this | ||||
| // calculator requires access to the request header, it creates a race with | ||||
| // any writes to the header performed during request handling. | ||||
| // httputil.ReverseProxy is a prominent example for a handler | ||||
| // performing such writes. | ||||
| // | ||||
| // - It has additional issues with HTTP/2, cf. | ||||
| // package promhttp instead. The issues are the following: (1) It uses Summaries | ||||
| // rather than Histograms. Summaries are not useful if aggregation across | ||||
| // multiple instances is required. (2) It uses microseconds as unit, which is | ||||
| // deprecated and should be replaced by seconds. (3) The size of the request is | ||||
| // calculated in a separate goroutine. Since this calculator requires access to | ||||
| // the request header, it creates a race with any writes to the header performed | ||||
| // during request handling.  httputil.ReverseProxy is a prominent example for a | ||||
| // handler performing such writes. (4) It has additional issues with HTTP/2, cf. | ||||
| // https://github.com/prometheus/client_golang/issues/272. | ||||
| func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFunc { | ||||
| 	return InstrumentHandlerFunc(handlerName, handler.ServeHTTP) | ||||
| @@ -317,7 +270,7 @@ func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.Respo | ||||
| } | ||||
|  | ||||
| func computeApproximateRequestSize(r *http.Request) <-chan int { | ||||
| 	// Get URL length in current go routine for avoiding a race condition. | ||||
| 	// Get URL length in current goroutine for avoiding a race condition. | ||||
| 	// HandlerFunc that runs in parallel may modify the URL. | ||||
| 	s := 0 | ||||
| 	if r.URL != nil { | ||||
| @@ -352,10 +305,9 @@ func computeApproximateRequestSize(r *http.Request) <-chan int { | ||||
| type responseWriterDelegator struct { | ||||
| 	http.ResponseWriter | ||||
|  | ||||
| 	handler, method string | ||||
| 	status          int | ||||
| 	written         int64 | ||||
| 	wroteHeader     bool | ||||
| 	status      int | ||||
| 	written     int64 | ||||
| 	wroteHeader bool | ||||
| } | ||||
|  | ||||
| func (r *responseWriterDelegator) WriteHeader(code int) { | ||||
| @@ -378,6 +330,8 @@ type fancyResponseWriterDelegator struct { | ||||
| } | ||||
|  | ||||
| func (f *fancyResponseWriterDelegator) CloseNotify() <-chan bool { | ||||
| 	//lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to | ||||
| 	//remove support from client_golang yet. | ||||
| 	return f.ResponseWriter.(http.CloseNotifier).CloseNotify() | ||||
| } | ||||
|  | ||||
| @@ -521,3 +475,31 @@ func sanitizeCode(s int) string { | ||||
| 		return strconv.Itoa(s) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // gzipAccepted returns whether the client will accept gzip-encoded content. | ||||
| func gzipAccepted(header http.Header) bool { | ||||
| 	a := header.Get(acceptEncodingHeader) | ||||
| 	parts := strings.Split(a, ",") | ||||
| 	for _, part := range parts { | ||||
| 		part = strings.TrimSpace(part) | ||||
| 		if part == "gzip" || strings.HasPrefix(part, "gzip;") { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // httpError removes any content-encoding header and then calls http.Error with | ||||
| // the provided error and http.StatusInternalServerErrer. Error contents is | ||||
| // supposed to be uncompressed plain text. However, same as with a plain | ||||
| // http.Error, any header settings will be void if the header has already been | ||||
| // sent. The error message will still be written to the writer, but it will | ||||
| // probably be of limited use. | ||||
| func httpError(rsp http.ResponseWriter, err error) { | ||||
| 	rsp.Header().Del(contentEncodingHeader) | ||||
| 	http.Error( | ||||
| 		rsp, | ||||
| 		"An error has occurred while serving metrics:\n\n"+err.Error(), | ||||
| 		http.StatusInternalServerError, | ||||
| 	) | ||||
| } | ||||
|   | ||||
							
								
								
									
										85
									
								
								vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| // Copyright 2018 The Prometheus Authors | ||||
| // 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 ( | ||||
| 	"sort" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| // metricSorter is a sortable slice of *dto.Metric. | ||||
| type metricSorter []*dto.Metric | ||||
|  | ||||
| func (s metricSorter) Len() int { | ||||
| 	return len(s) | ||||
| } | ||||
|  | ||||
| func (s metricSorter) Swap(i, j int) { | ||||
| 	s[i], s[j] = s[j], s[i] | ||||
| } | ||||
|  | ||||
| func (s metricSorter) Less(i, j int) bool { | ||||
| 	if len(s[i].Label) != len(s[j].Label) { | ||||
| 		// This should not happen. The metrics are | ||||
| 		// inconsistent. However, we have to deal with the fact, as | ||||
| 		// people might use custom collectors or metric family injection | ||||
| 		// to create inconsistent metrics. So let's simply compare the | ||||
| 		// number of labels in this case. That will still yield | ||||
| 		// reproducible sorting. | ||||
| 		return len(s[i].Label) < len(s[j].Label) | ||||
| 	} | ||||
| 	for n, lp := range s[i].Label { | ||||
| 		vi := lp.GetValue() | ||||
| 		vj := s[j].Label[n].GetValue() | ||||
| 		if vi != vj { | ||||
| 			return vi < vj | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// We should never arrive here. Multiple metrics with the same | ||||
| 	// label set in the same scrape will lead to undefined ingestion | ||||
| 	// behavior. However, as above, we have to provide stable sorting | ||||
| 	// here, even for inconsistent metrics. So sort equal metrics | ||||
| 	// by their timestamp, with missing timestamps (implying "now") | ||||
| 	// coming last. | ||||
| 	if s[i].TimestampMs == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	if s[j].TimestampMs == nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	return s[i].GetTimestampMs() < s[j].GetTimestampMs() | ||||
| } | ||||
|  | ||||
| // NormalizeMetricFamilies returns a MetricFamily slice with empty | ||||
| // MetricFamilies pruned and the remaining MetricFamilies sorted by name within | ||||
| // the slice, with the contained Metrics sorted within each MetricFamily. | ||||
| func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily { | ||||
| 	for _, mf := range metricFamiliesByName { | ||||
| 		sort.Sort(metricSorter(mf.Metric)) | ||||
| 	} | ||||
| 	names := make([]string, 0, len(metricFamiliesByName)) | ||||
| 	for name, mf := range metricFamiliesByName { | ||||
| 		if len(mf.Metric) > 0 { | ||||
| 			names = append(names, name) | ||||
| 		} | ||||
| 	} | ||||
| 	sort.Strings(names) | ||||
| 	result := make([]*dto.MetricFamily, 0, len(names)) | ||||
| 	for _, name := range names { | ||||
| 		result = append(result, metricFamiliesByName[name]) | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
							
								
								
									
										34
									
								
								vendor/github.com/prometheus/client_golang/prometheus/labels.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/prometheus/client_golang/prometheus/labels.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,3 +1,16 @@ | ||||
| // Copyright 2018 The Prometheus Authors | ||||
| // 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 prometheus | ||||
|  | ||||
| import ( | ||||
| @@ -24,9 +37,22 @@ const reservedLabelPrefix = "__" | ||||
|  | ||||
| var errInconsistentCardinality = errors.New("inconsistent label cardinality") | ||||
|  | ||||
| func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error { | ||||
| 	return fmt.Errorf( | ||||
| 		"%s: %q has %d variable labels named %q but %d values %q were provided", | ||||
| 		errInconsistentCardinality, fqName, | ||||
| 		len(labels), labels, | ||||
| 		len(labelValues), labelValues, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { | ||||
| 	if len(labels) != expectedNumberOfValues { | ||||
| 		return errInconsistentCardinality | ||||
| 		return fmt.Errorf( | ||||
| 			"%s: expected %d label values but got %d in %#v", | ||||
| 			errInconsistentCardinality, expectedNumberOfValues, | ||||
| 			len(labels), labels, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	for name, val := range labels { | ||||
| @@ -40,7 +66,11 @@ func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { | ||||
|  | ||||
| func validateLabelValues(vals []string, expectedNumberOfValues int) error { | ||||
| 	if len(vals) != expectedNumberOfValues { | ||||
| 		return errInconsistentCardinality | ||||
| 		return fmt.Errorf( | ||||
| 			"%s: expected %d label values but got %d in %#v", | ||||
| 			errInconsistentCardinality, expectedNumberOfValues, | ||||
| 			len(vals), vals, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	for _, val := range vals { | ||||
|   | ||||
							
								
								
									
										70
									
								
								vendor/github.com/prometheus/client_golang/prometheus/metric.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										70
									
								
								vendor/github.com/prometheus/client_golang/prometheus/metric.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -15,6 +15,9 @@ package prometheus | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
| @@ -43,9 +46,8 @@ type Metric interface { | ||||
| 	// While populating dto.Metric, it is the responsibility of the | ||||
| 	// implementation to ensure validity of the Metric protobuf (like valid | ||||
| 	// UTF-8 strings or syntactically valid metric and label names). It is | ||||
| 	// recommended to sort labels lexicographically. (Implementers may find | ||||
| 	// LabelPairSorter useful for that.) Callers of Write should still make | ||||
| 	// sure of sorting if they depend on it. | ||||
| 	// recommended to sort labels lexicographically. Callers of Write should | ||||
| 	// still make sure of sorting if they depend on it. | ||||
| 	Write(*dto.Metric) error | ||||
| 	// TODO(beorn7): The original rationale of passing in a pre-allocated | ||||
| 	// dto.Metric protobuf to save allocations has disappeared. The | ||||
| @@ -57,8 +59,9 @@ type Metric interface { | ||||
| // implementation XXX has its own XXXOpts type, but in most cases, it is just be | ||||
| // an alias of this type (which might change when the requirement arises.) | ||||
| // | ||||
| // It is mandatory to set Name and Help to a non-empty string. All other fields | ||||
| // are optional and can safely be left at their zero value. | ||||
| // It is mandatory to set Name to a non-empty string. All other fields are | ||||
| // optional and can safely be left at their zero value, although it is strongly | ||||
| // encouraged to set a Help string. | ||||
| type Opts struct { | ||||
| 	// Namespace, Subsystem, and Name are components of the fully-qualified | ||||
| 	// name of the Metric (created by joining these components with | ||||
| @@ -69,7 +72,7 @@ type Opts struct { | ||||
| 	Subsystem string | ||||
| 	Name      string | ||||
|  | ||||
| 	// Help provides information about this metric. Mandatory! | ||||
| 	// Help provides information about this metric. | ||||
| 	// | ||||
| 	// Metrics with the same fully-qualified name must have the same Help | ||||
| 	// string. | ||||
| @@ -110,37 +113,22 @@ func BuildFQName(namespace, subsystem, name string) string { | ||||
| 	return name | ||||
| } | ||||
|  | ||||
| // LabelPairSorter implements sort.Interface. It is used to sort a slice of | ||||
| // dto.LabelPair pointers. This is useful for implementing the Write method of | ||||
| // custom metrics. | ||||
| type LabelPairSorter []*dto.LabelPair | ||||
| // labelPairSorter implements sort.Interface. It is used to sort a slice of | ||||
| // dto.LabelPair pointers. | ||||
| type labelPairSorter []*dto.LabelPair | ||||
|  | ||||
| func (s LabelPairSorter) Len() int { | ||||
| func (s labelPairSorter) Len() int { | ||||
| 	return len(s) | ||||
| } | ||||
|  | ||||
| func (s LabelPairSorter) Swap(i, j int) { | ||||
| func (s labelPairSorter) Swap(i, j int) { | ||||
| 	s[i], s[j] = s[j], s[i] | ||||
| } | ||||
|  | ||||
| func (s LabelPairSorter) Less(i, j int) bool { | ||||
| func (s labelPairSorter) Less(i, j int) bool { | ||||
| 	return s[i].GetName() < s[j].GetName() | ||||
| } | ||||
|  | ||||
| type hashSorter []uint64 | ||||
|  | ||||
| func (s hashSorter) Len() int { | ||||
| 	return len(s) | ||||
| } | ||||
|  | ||||
| func (s hashSorter) Swap(i, j int) { | ||||
| 	s[i], s[j] = s[j], s[i] | ||||
| } | ||||
|  | ||||
| func (s hashSorter) Less(i, j int) bool { | ||||
| 	return s[i] < s[j] | ||||
| } | ||||
|  | ||||
| type invalidMetric struct { | ||||
| 	desc *Desc | ||||
| 	err  error | ||||
| @@ -156,3 +144,31 @@ func NewInvalidMetric(desc *Desc, err error) Metric { | ||||
| func (m *invalidMetric) Desc() *Desc { return m.desc } | ||||
|  | ||||
| func (m *invalidMetric) Write(*dto.Metric) error { return m.err } | ||||
|  | ||||
| type timestampedMetric struct { | ||||
| 	Metric | ||||
| 	t time.Time | ||||
| } | ||||
|  | ||||
| func (m timestampedMetric) Write(pb *dto.Metric) error { | ||||
| 	e := m.Metric.Write(pb) | ||||
| 	pb.TimestampMs = proto.Int64(m.t.Unix()*1000 + int64(m.t.Nanosecond()/1000000)) | ||||
| 	return e | ||||
| } | ||||
|  | ||||
| // NewMetricWithTimestamp returns a new Metric wrapping the provided Metric in a | ||||
| // way that it has an explicit timestamp set to the provided Time. This is only | ||||
| // useful in rare cases as the timestamp of a Prometheus metric should usually | ||||
| // be set by the Prometheus server during scraping. Exceptions include mirroring | ||||
| // metrics with given timestamps from other metric | ||||
| // sources. | ||||
| // | ||||
| // NewMetricWithTimestamp works best with MustNewConstMetric, | ||||
| // MustNewConstHistogram, and MustNewConstSummary, see example. | ||||
| // | ||||
| // Currently, the exposition formats used by Prometheus are limited to | ||||
| // millisecond resolution. Thus, the provided time will be rounded down to the | ||||
| // next full millisecond value. | ||||
| func NewMetricWithTimestamp(t time.Time, m Metric) Metric { | ||||
| 	return timestampedMetric{Metric: m, t: t} | ||||
| } | ||||
|   | ||||
							
								
								
									
										116
									
								
								vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										116
									
								
								vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -13,46 +13,74 @@ | ||||
|  | ||||
| package prometheus | ||||
|  | ||||
| import "github.com/prometheus/procfs" | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/prometheus/procfs" | ||||
| ) | ||||
|  | ||||
| type processCollector struct { | ||||
| 	pid             int | ||||
| 	collectFn       func(chan<- Metric) | ||||
| 	pidFn           func() (int, error) | ||||
| 	reportErrors    bool | ||||
| 	cpuTotal        *Desc | ||||
| 	openFDs, maxFDs *Desc | ||||
| 	vsize, rss      *Desc | ||||
| 	vsize, maxVsize *Desc | ||||
| 	rss             *Desc | ||||
| 	startTime       *Desc | ||||
| } | ||||
|  | ||||
| // ProcessCollectorOpts defines the behavior of a process metrics collector | ||||
| // created with NewProcessCollector. | ||||
| type ProcessCollectorOpts struct { | ||||
| 	// PidFn returns the PID of the process the collector collects metrics | ||||
| 	// for. It is called upon each collection. By default, the PID of the | ||||
| 	// current process is used, as determined on construction time by | ||||
| 	// calling os.Getpid(). | ||||
| 	PidFn func() (int, error) | ||||
| 	// If non-empty, each of the collected metrics is prefixed by the | ||||
| 	// provided string and an underscore ("_"). | ||||
| 	Namespace string | ||||
| 	// If true, any error encountered during collection is reported as an | ||||
| 	// invalid metric (see NewInvalidMetric). Otherwise, errors are ignored | ||||
| 	// and the collected metrics will be incomplete. (Possibly, no metrics | ||||
| 	// will be collected at all.) While that's usually not desired, it is | ||||
| 	// appropriate for the common "mix-in" of process metrics, where process | ||||
| 	// metrics are nice to have, but failing to collect them should not | ||||
| 	// disrupt the collection of the remaining metrics. | ||||
| 	ReportErrors bool | ||||
| } | ||||
|  | ||||
| // NewProcessCollector returns a collector which exports the current state of | ||||
| // process metrics including CPU, memory and file descriptor usage as well as | ||||
| // the process start time for the given process ID under the given namespace. | ||||
| // the process start time. The detailed behavior is defined by the provided | ||||
| // ProcessCollectorOpts. The zero value of ProcessCollectorOpts creates a | ||||
| // collector for the current process with an empty namespace string and no error | ||||
| // reporting. | ||||
| // | ||||
| // Currently, the collector depends on a Linux-style proc filesystem and | ||||
| // therefore only exports metrics for Linux. | ||||
| func NewProcessCollector(pid int, namespace string) Collector { | ||||
| 	return NewProcessCollectorPIDFn( | ||||
| 		func() (int, error) { return pid, nil }, | ||||
| 		namespace, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| // NewProcessCollectorPIDFn works like NewProcessCollector but the process ID is | ||||
| // determined on each collect anew by calling the given pidFn function. | ||||
| func NewProcessCollectorPIDFn( | ||||
| 	pidFn func() (int, error), | ||||
| 	namespace string, | ||||
| ) Collector { | ||||
| // | ||||
| // Note: An older version of this function had the following signature: | ||||
| // | ||||
| //     NewProcessCollector(pid int, namespace string) Collector | ||||
| // | ||||
| // Most commonly, it was called as | ||||
| // | ||||
| //     NewProcessCollector(os.Getpid(), "") | ||||
| // | ||||
| // The following call of the current version is equivalent to the above: | ||||
| // | ||||
| //     NewProcessCollector(ProcessCollectorOpts{}) | ||||
| func NewProcessCollector(opts ProcessCollectorOpts) Collector { | ||||
| 	ns := "" | ||||
| 	if len(namespace) > 0 { | ||||
| 		ns = namespace + "_" | ||||
| 	if len(opts.Namespace) > 0 { | ||||
| 		ns = opts.Namespace + "_" | ||||
| 	} | ||||
|  | ||||
| 	c := processCollector{ | ||||
| 		pidFn:     pidFn, | ||||
| 		collectFn: func(chan<- Metric) {}, | ||||
|  | ||||
| 	c := &processCollector{ | ||||
| 		reportErrors: opts.ReportErrors, | ||||
| 		cpuTotal: NewDesc( | ||||
| 			ns+"process_cpu_seconds_total", | ||||
| 			"Total user and system CPU time spent in seconds.", | ||||
| @@ -73,6 +101,11 @@ func NewProcessCollectorPIDFn( | ||||
| 			"Virtual memory size in bytes.", | ||||
| 			nil, nil, | ||||
| 		), | ||||
| 		maxVsize: NewDesc( | ||||
| 			ns+"process_virtual_memory_max_bytes", | ||||
| 			"Maximum amount of virtual memory available in bytes.", | ||||
| 			nil, nil, | ||||
| 		), | ||||
| 		rss: NewDesc( | ||||
| 			ns+"process_resident_memory_bytes", | ||||
| 			"Resident memory size in bytes.", | ||||
| @@ -85,12 +118,23 @@ func NewProcessCollectorPIDFn( | ||||
| 		), | ||||
| 	} | ||||
|  | ||||
| 	if opts.PidFn == nil { | ||||
| 		pid := os.Getpid() | ||||
| 		c.pidFn = func() (int, error) { return pid, nil } | ||||
| 	} else { | ||||
| 		c.pidFn = opts.PidFn | ||||
| 	} | ||||
|  | ||||
| 	// Set up process metric collection if supported by the runtime. | ||||
| 	if _, err := procfs.NewStat(); err == nil { | ||||
| 		c.collectFn = c.processCollect | ||||
| 	} else { | ||||
| 		c.collectFn = func(ch chan<- Metric) { | ||||
| 			c.reportError(ch, nil, errors.New("process metrics not supported on this platform")) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &c | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| // Describe returns all descriptions of the collector. | ||||
| @@ -99,6 +143,7 @@ func (c *processCollector) Describe(ch chan<- *Desc) { | ||||
| 	ch <- c.openFDs | ||||
| 	ch <- c.maxFDs | ||||
| 	ch <- c.vsize | ||||
| 	ch <- c.maxVsize | ||||
| 	ch <- c.rss | ||||
| 	ch <- c.startTime | ||||
| } | ||||
| @@ -108,16 +153,16 @@ func (c *processCollector) Collect(ch chan<- Metric) { | ||||
| 	c.collectFn(ch) | ||||
| } | ||||
|  | ||||
| // TODO(ts): Bring back error reporting by reverting 7faf9e7 as soon as the | ||||
| // client allows users to configure the error behavior. | ||||
| func (c *processCollector) processCollect(ch chan<- Metric) { | ||||
| 	pid, err := c.pidFn() | ||||
| 	if err != nil { | ||||
| 		c.reportError(ch, nil, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	p, err := procfs.NewProc(pid) | ||||
| 	if err != nil { | ||||
| 		c.reportError(ch, nil, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -127,14 +172,33 @@ func (c *processCollector) processCollect(ch chan<- Metric) { | ||||
| 		ch <- MustNewConstMetric(c.rss, GaugeValue, float64(stat.ResidentMemory())) | ||||
| 		if startTime, err := stat.StartTime(); err == nil { | ||||
| 			ch <- MustNewConstMetric(c.startTime, GaugeValue, startTime) | ||||
| 		} else { | ||||
| 			c.reportError(ch, c.startTime, err) | ||||
| 		} | ||||
| 	} else { | ||||
| 		c.reportError(ch, nil, err) | ||||
| 	} | ||||
|  | ||||
| 	if fds, err := p.FileDescriptorsLen(); err == nil { | ||||
| 		ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(fds)) | ||||
| 	} else { | ||||
| 		c.reportError(ch, c.openFDs, err) | ||||
| 	} | ||||
|  | ||||
| 	if limits, err := p.NewLimits(); err == nil { | ||||
| 		ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(limits.OpenFiles)) | ||||
| 		ch <- MustNewConstMetric(c.maxVsize, GaugeValue, float64(limits.AddressSpace)) | ||||
| 	} else { | ||||
| 		c.reportError(ch, nil, err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error) { | ||||
| 	if !c.reportErrors { | ||||
| 		return | ||||
| 	} | ||||
| 	if desc == nil { | ||||
| 		desc = NewInvalidDesc(err) | ||||
| 	} | ||||
| 	ch <- NewInvalidMetric(desc, err) | ||||
| } | ||||
|   | ||||
							
								
								
									
										196
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										196
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -38,7 +38,6 @@ type delegator interface { | ||||
| type responseWriterDelegator struct { | ||||
| 	http.ResponseWriter | ||||
|  | ||||
| 	handler, method    string | ||||
| 	status             int | ||||
| 	written            int64 | ||||
| 	wroteHeader        bool | ||||
| @@ -75,17 +74,20 @@ type closeNotifierDelegator struct{ *responseWriterDelegator } | ||||
| type flusherDelegator struct{ *responseWriterDelegator } | ||||
| type hijackerDelegator struct{ *responseWriterDelegator } | ||||
| type readerFromDelegator struct{ *responseWriterDelegator } | ||||
| type pusherDelegator struct{ *responseWriterDelegator } | ||||
|  | ||||
| func (d *closeNotifierDelegator) CloseNotify() <-chan bool { | ||||
| func (d closeNotifierDelegator) CloseNotify() <-chan bool { | ||||
| 	//lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to | ||||
| 	//remove support from client_golang yet. | ||||
| 	return d.ResponseWriter.(http.CloseNotifier).CloseNotify() | ||||
| } | ||||
| func (d *flusherDelegator) Flush() { | ||||
| func (d flusherDelegator) Flush() { | ||||
| 	d.ResponseWriter.(http.Flusher).Flush() | ||||
| } | ||||
| func (d *hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) { | ||||
| func (d hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) { | ||||
| 	return d.ResponseWriter.(http.Hijacker).Hijack() | ||||
| } | ||||
| func (d *readerFromDelegator) ReadFrom(re io.Reader) (int64, error) { | ||||
| func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) { | ||||
| 	if !d.wroteHeader { | ||||
| 		d.WriteHeader(http.StatusOK) | ||||
| 	} | ||||
| @@ -93,6 +95,9 @@ func (d *readerFromDelegator) ReadFrom(re io.Reader) (int64, error) { | ||||
| 	d.written += n | ||||
| 	return n, err | ||||
| } | ||||
| func (d pusherDelegator) Push(target string, opts *http.PushOptions) error { | ||||
| 	return d.ResponseWriter.(http.Pusher).Push(target, opts) | ||||
| } | ||||
|  | ||||
| var pickDelegator = make([]func(*responseWriterDelegator) delegator, 32) | ||||
|  | ||||
| @@ -102,34 +107,34 @@ func init() { | ||||
| 		return d | ||||
| 	} | ||||
| 	pickDelegator[closeNotifier] = func(d *responseWriterDelegator) delegator { // 1 | ||||
| 		return &closeNotifierDelegator{d} | ||||
| 		return closeNotifierDelegator{d} | ||||
| 	} | ||||
| 	pickDelegator[flusher] = func(d *responseWriterDelegator) delegator { // 2 | ||||
| 		return &flusherDelegator{d} | ||||
| 		return flusherDelegator{d} | ||||
| 	} | ||||
| 	pickDelegator[flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 3 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &flusherDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 		}{d, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[hijacker] = func(d *responseWriterDelegator) delegator { // 4 | ||||
| 		return &hijackerDelegator{d} | ||||
| 		return hijackerDelegator{d} | ||||
| 	} | ||||
| 	pickDelegator[hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 5 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Hijacker | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &hijackerDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 		}{d, hijackerDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 6 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 		}{d, &hijackerDelegator{d}, &flusherDelegator{d}} | ||||
| 		}{d, hijackerDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 7 | ||||
| 		return struct { | ||||
| @@ -137,7 +142,7 @@ func init() { | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &hijackerDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 		}{d, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom] = func(d *responseWriterDelegator) delegator { // 8 | ||||
| 		return readerFromDelegator{d} | ||||
| @@ -147,14 +152,14 @@ func init() { | ||||
| 			*responseWriterDelegator | ||||
| 			io.ReaderFrom | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &readerFromDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 		}{d, readerFromDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 10 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			io.ReaderFrom | ||||
| 			http.Flusher | ||||
| 		}{d, &readerFromDelegator{d}, &flusherDelegator{d}} | ||||
| 		}{d, readerFromDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 11 | ||||
| 		return struct { | ||||
| @@ -162,14 +167,14 @@ func init() { | ||||
| 			io.ReaderFrom | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &readerFromDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 		}{d, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 12 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 		}{d, &readerFromDelegator{d}, &hijackerDelegator{d}} | ||||
| 		}{d, readerFromDelegator{d}, hijackerDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 13 | ||||
| 		return struct { | ||||
| @@ -177,7 +182,7 @@ func init() { | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &readerFromDelegator{d}, &hijackerDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 		}{d, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 14 | ||||
| 		return struct { | ||||
| @@ -185,7 +190,7 @@ func init() { | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 		}{d, &readerFromDelegator{d}, &hijackerDelegator{d}, &flusherDelegator{d}} | ||||
| 		}{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 15 | ||||
| 		return struct { | ||||
| @@ -194,6 +199,159 @@ func init() { | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &readerFromDelegator{d}, &hijackerDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 		}{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher] = func(d *responseWriterDelegator) delegator { // 16 | ||||
| 		return pusherDelegator{d} | ||||
| 	} | ||||
| 	pickDelegator[pusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 17 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+flusher] = func(d *responseWriterDelegator) delegator { // 18 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Flusher | ||||
| 		}{d, pusherDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 19 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker] = func(d *responseWriterDelegator) delegator { // 20 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 		}{d, pusherDelegator{d}, hijackerDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 21 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 22 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 		}{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom] = func(d *responseWriterDelegator) delegator { // 24 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 25 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 26 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Flusher | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 27 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 28 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 29 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 30 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 31 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator { | ||||
| 	d := &responseWriterDelegator{ | ||||
| 		ResponseWriter:     w, | ||||
| 		observeWriteHeader: observeWriteHeaderFunc, | ||||
| 	} | ||||
|  | ||||
| 	id := 0 | ||||
| 	//lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to | ||||
| 	//remove support from client_golang yet. | ||||
| 	if _, ok := w.(http.CloseNotifier); ok { | ||||
| 		id += closeNotifier | ||||
| 	} | ||||
| 	if _, ok := w.(http.Flusher); ok { | ||||
| 		id += flusher | ||||
| 	} | ||||
| 	if _, ok := w.(http.Hijacker); ok { | ||||
| 		id += hijacker | ||||
| 	} | ||||
| 	if _, ok := w.(io.ReaderFrom); ok { | ||||
| 		id += readerFrom | ||||
| 	} | ||||
| 	if _, ok := w.(http.Pusher); ok { | ||||
| 		id += pusher | ||||
| 	} | ||||
|  | ||||
| 	return pickDelegator[id](d) | ||||
| } | ||||
|   | ||||
							
								
								
									
										181
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										181
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,181 +0,0 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // 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 go1.8 | ||||
|  | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| type pusherDelegator struct{ *responseWriterDelegator } | ||||
|  | ||||
| func (d *pusherDelegator) Push(target string, opts *http.PushOptions) error { | ||||
| 	return d.ResponseWriter.(http.Pusher).Push(target, opts) | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	pickDelegator[pusher] = func(d *responseWriterDelegator) delegator { // 16 | ||||
| 		return &pusherDelegator{d} | ||||
| 	} | ||||
| 	pickDelegator[pusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 17 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &pusherDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+flusher] = func(d *responseWriterDelegator) delegator { // 18 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Flusher | ||||
| 		}{d, &pusherDelegator{d}, &flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 19 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &pusherDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker] = func(d *responseWriterDelegator) delegator { // 20 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 		}{d, &pusherDelegator{d}, &hijackerDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 21 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &pusherDelegator{d}, &hijackerDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 22 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 		}{d, &pusherDelegator{d}, &hijackerDelegator{d}, &flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &pusherDelegator{d}, &hijackerDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom] = func(d *responseWriterDelegator) delegator { // 24 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 		}{d, &pusherDelegator{d}, &readerFromDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 25 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &pusherDelegator{d}, &readerFromDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 26 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Flusher | ||||
| 		}{d, &pusherDelegator{d}, &readerFromDelegator{d}, &flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 27 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &pusherDelegator{d}, &readerFromDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 28 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 		}{d, &pusherDelegator{d}, &readerFromDelegator{d}, &hijackerDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 29 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &pusherDelegator{d}, &readerFromDelegator{d}, &hijackerDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 30 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 		}{d, &pusherDelegator{d}, &readerFromDelegator{d}, &hijackerDelegator{d}, &flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 31 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, &pusherDelegator{d}, &readerFromDelegator{d}, &hijackerDelegator{d}, &flusherDelegator{d}, &closeNotifierDelegator{d}} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator { | ||||
| 	d := &responseWriterDelegator{ | ||||
| 		ResponseWriter:     w, | ||||
| 		observeWriteHeader: observeWriteHeaderFunc, | ||||
| 	} | ||||
|  | ||||
| 	id := 0 | ||||
| 	if _, ok := w.(http.CloseNotifier); ok { | ||||
| 		id += closeNotifier | ||||
| 	} | ||||
| 	if _, ok := w.(http.Flusher); ok { | ||||
| 		id += flusher | ||||
| 	} | ||||
| 	if _, ok := w.(http.Hijacker); ok { | ||||
| 		id += hijacker | ||||
| 	} | ||||
| 	if _, ok := w.(io.ReaderFrom); ok { | ||||
| 		id += readerFrom | ||||
| 	} | ||||
| 	if _, ok := w.(http.Pusher); ok { | ||||
| 		id += pusher | ||||
| 	} | ||||
|  | ||||
| 	return pickDelegator[id](d) | ||||
| } | ||||
							
								
								
									
										44
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,44 +0,0 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // 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 !go1.8 | ||||
|  | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator { | ||||
| 	d := &responseWriterDelegator{ | ||||
| 		ResponseWriter:     w, | ||||
| 		observeWriteHeader: observeWriteHeaderFunc, | ||||
| 	} | ||||
|  | ||||
| 	id := 0 | ||||
| 	if _, ok := w.(http.CloseNotifier); ok { | ||||
| 		id += closeNotifier | ||||
| 	} | ||||
| 	if _, ok := w.(http.Flusher); ok { | ||||
| 		id += flusher | ||||
| 	} | ||||
| 	if _, ok := w.(http.Hijacker); ok { | ||||
| 		id += hijacker | ||||
| 	} | ||||
| 	if _, ok := w.(io.ReaderFrom); ok { | ||||
| 		id += readerFrom | ||||
| 	} | ||||
|  | ||||
| 	return pickDelegator[id](d) | ||||
| } | ||||
							
								
								
									
										143
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										143
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -32,13 +32,13 @@ | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"compress/gzip" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/prometheus/common/expfmt" | ||||
|  | ||||
| @@ -47,24 +47,14 @@ import ( | ||||
|  | ||||
| const ( | ||||
| 	contentTypeHeader     = "Content-Type" | ||||
| 	contentLengthHeader   = "Content-Length" | ||||
| 	contentEncodingHeader = "Content-Encoding" | ||||
| 	acceptEncodingHeader  = "Accept-Encoding" | ||||
| ) | ||||
|  | ||||
| var bufPool sync.Pool | ||||
|  | ||||
| func getBuf() *bytes.Buffer { | ||||
| 	buf := bufPool.Get() | ||||
| 	if buf == nil { | ||||
| 		return &bytes.Buffer{} | ||||
| 	} | ||||
| 	return buf.(*bytes.Buffer) | ||||
| } | ||||
|  | ||||
| func giveBuf(buf *bytes.Buffer) { | ||||
| 	buf.Reset() | ||||
| 	bufPool.Put(buf) | ||||
| var gzipPool = sync.Pool{ | ||||
| 	New: func() interface{} { | ||||
| 		return gzip.NewWriter(nil) | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // Handler returns an http.Handler for the prometheus.DefaultGatherer, using | ||||
| @@ -94,7 +84,23 @@ func Handler() http.Handler { | ||||
| // instrumentation. Use the InstrumentMetricHandler function to apply the same | ||||
| // kind of instrumentation as it is used by the Handler function. | ||||
| func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { | ||||
| 	var inFlightSem chan struct{} | ||||
| 	if opts.MaxRequestsInFlight > 0 { | ||||
| 		inFlightSem = make(chan struct{}, opts.MaxRequestsInFlight) | ||||
| 	} | ||||
|  | ||||
| 	h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { | ||||
| 		if inFlightSem != nil { | ||||
| 			select { | ||||
| 			case inFlightSem <- struct{}{}: // All good, carry on. | ||||
| 				defer func() { <-inFlightSem }() | ||||
| 			default: | ||||
| 				http.Error(rsp, fmt.Sprintf( | ||||
| 					"Limit of concurrent requests reached (%d), try again later.", opts.MaxRequestsInFlight, | ||||
| 				), http.StatusServiceUnavailable) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		mfs, err := reg.Gather() | ||||
| 		if err != nil { | ||||
| 			if opts.ErrorLog != nil { | ||||
| @@ -105,26 +111,40 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { | ||||
| 				panic(err) | ||||
| 			case ContinueOnError: | ||||
| 				if len(mfs) == 0 { | ||||
| 					http.Error(w, "No metrics gathered, last error:\n\n"+err.Error(), http.StatusInternalServerError) | ||||
| 					// Still report the error if no metrics have been gathered. | ||||
| 					httpError(rsp, err) | ||||
| 					return | ||||
| 				} | ||||
| 			case HTTPErrorOnError: | ||||
| 				http.Error(w, "An error has occurred during metrics gathering:\n\n"+err.Error(), http.StatusInternalServerError) | ||||
| 				httpError(rsp, err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		contentType := expfmt.Negotiate(req.Header) | ||||
| 		buf := getBuf() | ||||
| 		defer giveBuf(buf) | ||||
| 		writer, encoding := decorateWriter(req, buf, opts.DisableCompression) | ||||
| 		enc := expfmt.NewEncoder(writer, contentType) | ||||
| 		header := rsp.Header() | ||||
| 		header.Set(contentTypeHeader, string(contentType)) | ||||
|  | ||||
| 		w := io.Writer(rsp) | ||||
| 		if !opts.DisableCompression && gzipAccepted(req.Header) { | ||||
| 			header.Set(contentEncodingHeader, "gzip") | ||||
| 			gz := gzipPool.Get().(*gzip.Writer) | ||||
| 			defer gzipPool.Put(gz) | ||||
|  | ||||
| 			gz.Reset(w) | ||||
| 			defer gz.Close() | ||||
|  | ||||
| 			w = gz | ||||
| 		} | ||||
|  | ||||
| 		enc := expfmt.NewEncoder(w, contentType) | ||||
|  | ||||
| 		var lastErr error | ||||
| 		for _, mf := range mfs { | ||||
| 			if err := enc.Encode(mf); err != nil { | ||||
| 				lastErr = err | ||||
| 				if opts.ErrorLog != nil { | ||||
| 					opts.ErrorLog.Println("error encoding metric family:", err) | ||||
| 					opts.ErrorLog.Println("error encoding and sending metric family:", err) | ||||
| 				} | ||||
| 				switch opts.ErrorHandling { | ||||
| 				case PanicOnError: | ||||
| @@ -132,27 +152,24 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { | ||||
| 				case ContinueOnError: | ||||
| 					// Handled later. | ||||
| 				case HTTPErrorOnError: | ||||
| 					http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError) | ||||
| 					httpError(rsp, err) | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if closer, ok := writer.(io.Closer); ok { | ||||
| 			closer.Close() | ||||
|  | ||||
| 		if lastErr != nil { | ||||
| 			httpError(rsp, lastErr) | ||||
| 		} | ||||
| 		if lastErr != nil && buf.Len() == 0 { | ||||
| 			http.Error(w, "No metrics encoded, last error:\n\n"+lastErr.Error(), http.StatusInternalServerError) | ||||
| 			return | ||||
| 		} | ||||
| 		header := w.Header() | ||||
| 		header.Set(contentTypeHeader, string(contentType)) | ||||
| 		header.Set(contentLengthHeader, fmt.Sprint(buf.Len())) | ||||
| 		if encoding != "" { | ||||
| 			header.Set(contentEncodingHeader, encoding) | ||||
| 		} | ||||
| 		w.Write(buf.Bytes()) | ||||
| 		// TODO(beorn7): Consider streaming serving of metrics. | ||||
| 	}) | ||||
|  | ||||
| 	if opts.Timeout <= 0 { | ||||
| 		return h | ||||
| 	} | ||||
| 	return http.TimeoutHandler(h, opts.Timeout, fmt.Sprintf( | ||||
| 		"Exceeded configured timeout of %v.\n", | ||||
| 		opts.Timeout, | ||||
| 	)) | ||||
| } | ||||
|  | ||||
| // InstrumentMetricHandler is usually used with an http.Handler returned by the | ||||
| @@ -182,6 +199,7 @@ func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) ht | ||||
| 	// Initialize the most likely HTTP status codes. | ||||
| 	cnt.WithLabelValues("200") | ||||
| 	cnt.WithLabelValues("500") | ||||
| 	cnt.WithLabelValues("503") | ||||
| 	if err := reg.Register(cnt); err != nil { | ||||
| 		if are, ok := err.(prometheus.AlreadyRegisteredError); ok { | ||||
| 			cnt = are.ExistingCollector.(*prometheus.CounterVec) | ||||
| @@ -246,22 +264,47 @@ type HandlerOpts struct { | ||||
| 	// If DisableCompression is true, the handler will never compress the | ||||
| 	// response, even if requested by the client. | ||||
| 	DisableCompression bool | ||||
| 	// The number of concurrent HTTP requests is limited to | ||||
| 	// MaxRequestsInFlight. Additional requests are responded to with 503 | ||||
| 	// Service Unavailable and a suitable message in the body. If | ||||
| 	// MaxRequestsInFlight is 0 or negative, no limit is applied. | ||||
| 	MaxRequestsInFlight int | ||||
| 	// If handling a request takes longer than Timeout, it is responded to | ||||
| 	// with 503 ServiceUnavailable and a suitable Message. No timeout is | ||||
| 	// applied if Timeout is 0 or negative. Note that with the current | ||||
| 	// implementation, reaching the timeout simply ends the HTTP requests as | ||||
| 	// described above (and even that only if sending of the body hasn't | ||||
| 	// started yet), while the bulk work of gathering all the metrics keeps | ||||
| 	// running in the background (with the eventual result to be thrown | ||||
| 	// away). Until the implementation is improved, it is recommended to | ||||
| 	// implement a separate timeout in potentially slow Collectors. | ||||
| 	Timeout time.Duration | ||||
| } | ||||
|  | ||||
| // decorateWriter wraps a writer to handle gzip compression if requested.  It | ||||
| // returns the decorated writer and the appropriate "Content-Encoding" header | ||||
| // (which is empty if no compression is enabled). | ||||
| func decorateWriter(request *http.Request, writer io.Writer, compressionDisabled bool) (io.Writer, string) { | ||||
| 	if compressionDisabled { | ||||
| 		return writer, "" | ||||
| 	} | ||||
| 	header := request.Header.Get(acceptEncodingHeader) | ||||
| 	parts := strings.Split(header, ",") | ||||
| // gzipAccepted returns whether the client will accept gzip-encoded content. | ||||
| func gzipAccepted(header http.Header) bool { | ||||
| 	a := header.Get(acceptEncodingHeader) | ||||
| 	parts := strings.Split(a, ",") | ||||
| 	for _, part := range parts { | ||||
| 		part := strings.TrimSpace(part) | ||||
| 		part = strings.TrimSpace(part) | ||||
| 		if part == "gzip" || strings.HasPrefix(part, "gzip;") { | ||||
| 			return gzip.NewWriter(writer), "gzip" | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return writer, "" | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // httpError removes any content-encoding header and then calls http.Error with | ||||
| // the provided error and http.StatusInternalServerErrer. Error contents is | ||||
| // supposed to be uncompressed plain text. However, same as with a plain | ||||
| // http.Error, any header settings will be void if the header has already been | ||||
| // sent. The error message will still be written to the writer, but it will | ||||
| // probably be of limited use. | ||||
| func httpError(rsp http.ResponseWriter, err error) { | ||||
| 	rsp.Header().Del(contentEncodingHeader) | ||||
| 	http.Error( | ||||
| 		rsp, | ||||
| 		"An error has occurred while serving metrics:\n\n"+err.Error(), | ||||
| 		http.StatusInternalServerError, | ||||
| 	) | ||||
| } | ||||
|   | ||||
							
								
								
									
										122
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										122
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -14,7 +14,9 @@ | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"crypto/tls" | ||||
| 	"net/http" | ||||
| 	"net/http/httptrace" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/prometheus/client_golang/prometheus" | ||||
| @@ -95,3 +97,123 @@ func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundT | ||||
| 		return resp, err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // InstrumentTrace is used to offer flexibility in instrumenting the available | ||||
| // httptrace.ClientTrace hook functions. Each function is passed a float64 | ||||
| // representing the time in seconds since the start of the http request. A user | ||||
| // may choose to use separately buckets Histograms, or implement custom | ||||
| // instance labels on a per function basis. | ||||
| type InstrumentTrace struct { | ||||
| 	GotConn              func(float64) | ||||
| 	PutIdleConn          func(float64) | ||||
| 	GotFirstResponseByte func(float64) | ||||
| 	Got100Continue       func(float64) | ||||
| 	DNSStart             func(float64) | ||||
| 	DNSDone              func(float64) | ||||
| 	ConnectStart         func(float64) | ||||
| 	ConnectDone          func(float64) | ||||
| 	TLSHandshakeStart    func(float64) | ||||
| 	TLSHandshakeDone     func(float64) | ||||
| 	WroteHeaders         func(float64) | ||||
| 	Wait100Continue      func(float64) | ||||
| 	WroteRequest         func(float64) | ||||
| } | ||||
|  | ||||
| // InstrumentRoundTripperTrace is a middleware that wraps the provided | ||||
| // RoundTripper and reports times to hook functions provided in the | ||||
| // InstrumentTrace struct. Hook functions that are not present in the provided | ||||
| // InstrumentTrace struct are ignored. Times reported to the hook functions are | ||||
| // time since the start of the request. Only with Go1.9+, those times are | ||||
| // guaranteed to never be negative. (Earlier Go versions are not using a | ||||
| // monotonic clock.) Note that partitioning of Histograms is expensive and | ||||
| // should be used judiciously. | ||||
| // | ||||
| // For hook functions that receive an error as an argument, no observations are | ||||
| // made in the event of a non-nil error value. | ||||
| // | ||||
| // See the example for ExampleInstrumentRoundTripperDuration for example usage. | ||||
| func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc { | ||||
| 	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { | ||||
| 		start := time.Now() | ||||
|  | ||||
| 		trace := &httptrace.ClientTrace{ | ||||
| 			GotConn: func(_ httptrace.GotConnInfo) { | ||||
| 				if it.GotConn != nil { | ||||
| 					it.GotConn(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			PutIdleConn: func(err error) { | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if it.PutIdleConn != nil { | ||||
| 					it.PutIdleConn(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			DNSStart: func(_ httptrace.DNSStartInfo) { | ||||
| 				if it.DNSStart != nil { | ||||
| 					it.DNSStart(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			DNSDone: func(_ httptrace.DNSDoneInfo) { | ||||
| 				if it.DNSDone != nil { | ||||
| 					it.DNSDone(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			ConnectStart: func(_, _ string) { | ||||
| 				if it.ConnectStart != nil { | ||||
| 					it.ConnectStart(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			ConnectDone: func(_, _ string, err error) { | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if it.ConnectDone != nil { | ||||
| 					it.ConnectDone(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			GotFirstResponseByte: func() { | ||||
| 				if it.GotFirstResponseByte != nil { | ||||
| 					it.GotFirstResponseByte(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			Got100Continue: func() { | ||||
| 				if it.Got100Continue != nil { | ||||
| 					it.Got100Continue(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			TLSHandshakeStart: func() { | ||||
| 				if it.TLSHandshakeStart != nil { | ||||
| 					it.TLSHandshakeStart(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			TLSHandshakeDone: func(_ tls.ConnectionState, err error) { | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if it.TLSHandshakeDone != nil { | ||||
| 					it.TLSHandshakeDone(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			WroteHeaders: func() { | ||||
| 				if it.WroteHeaders != nil { | ||||
| 					it.WroteHeaders(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			Wait100Continue: func() { | ||||
| 				if it.Wait100Continue != nil { | ||||
| 					it.Wait100Continue(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			WroteRequest: func(_ httptrace.WroteRequestInfo) { | ||||
| 				if it.WroteRequest != nil { | ||||
| 					it.WroteRequest(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 		} | ||||
| 		r = r.WithContext(httptrace.WithClientTrace(r.Context(), trace)) | ||||
|  | ||||
| 		return next.RoundTrip(r) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
							
								
								
									
										144
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										144
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,144 +0,0 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // 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 go1.8 | ||||
|  | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"net/http" | ||||
| 	"net/http/httptrace" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // InstrumentTrace is used to offer flexibility in instrumenting the available | ||||
| // httptrace.ClientTrace hook functions. Each function is passed a float64 | ||||
| // representing the time in seconds since the start of the http request. A user | ||||
| // may choose to use separately buckets Histograms, or implement custom | ||||
| // instance labels on a per function basis. | ||||
| type InstrumentTrace struct { | ||||
| 	GotConn              func(float64) | ||||
| 	PutIdleConn          func(float64) | ||||
| 	GotFirstResponseByte func(float64) | ||||
| 	Got100Continue       func(float64) | ||||
| 	DNSStart             func(float64) | ||||
| 	DNSDone              func(float64) | ||||
| 	ConnectStart         func(float64) | ||||
| 	ConnectDone          func(float64) | ||||
| 	TLSHandshakeStart    func(float64) | ||||
| 	TLSHandshakeDone     func(float64) | ||||
| 	WroteHeaders         func(float64) | ||||
| 	Wait100Continue      func(float64) | ||||
| 	WroteRequest         func(float64) | ||||
| } | ||||
|  | ||||
| // InstrumentRoundTripperTrace is a middleware that wraps the provided | ||||
| // RoundTripper and reports times to hook functions provided in the | ||||
| // InstrumentTrace struct. Hook functions that are not present in the provided | ||||
| // InstrumentTrace struct are ignored. Times reported to the hook functions are | ||||
| // time since the start of the request. Only with Go1.9+, those times are | ||||
| // guaranteed to never be negative. (Earlier Go versions are not using a | ||||
| // monotonic clock.) Note that partitioning of Histograms is expensive and | ||||
| // should be used judiciously. | ||||
| // | ||||
| // For hook functions that receive an error as an argument, no observations are | ||||
| // made in the event of a non-nil error value. | ||||
| // | ||||
| // See the example for ExampleInstrumentRoundTripperDuration for example usage. | ||||
| func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc { | ||||
| 	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { | ||||
| 		start := time.Now() | ||||
|  | ||||
| 		trace := &httptrace.ClientTrace{ | ||||
| 			GotConn: func(_ httptrace.GotConnInfo) { | ||||
| 				if it.GotConn != nil { | ||||
| 					it.GotConn(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			PutIdleConn: func(err error) { | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if it.PutIdleConn != nil { | ||||
| 					it.PutIdleConn(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			DNSStart: func(_ httptrace.DNSStartInfo) { | ||||
| 				if it.DNSStart != nil { | ||||
| 					it.DNSStart(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			DNSDone: func(_ httptrace.DNSDoneInfo) { | ||||
| 				if it.DNSStart != nil { | ||||
| 					it.DNSStart(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			ConnectStart: func(_, _ string) { | ||||
| 				if it.ConnectStart != nil { | ||||
| 					it.ConnectStart(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			ConnectDone: func(_, _ string, err error) { | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if it.ConnectDone != nil { | ||||
| 					it.ConnectDone(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			GotFirstResponseByte: func() { | ||||
| 				if it.GotFirstResponseByte != nil { | ||||
| 					it.GotFirstResponseByte(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			Got100Continue: func() { | ||||
| 				if it.Got100Continue != nil { | ||||
| 					it.Got100Continue(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			TLSHandshakeStart: func() { | ||||
| 				if it.TLSHandshakeStart != nil { | ||||
| 					it.TLSHandshakeStart(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			TLSHandshakeDone: func(_ tls.ConnectionState, err error) { | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if it.TLSHandshakeDone != nil { | ||||
| 					it.TLSHandshakeDone(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			WroteHeaders: func() { | ||||
| 				if it.WroteHeaders != nil { | ||||
| 					it.WroteHeaders(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			Wait100Continue: func() { | ||||
| 				if it.Wait100Continue != nil { | ||||
| 					it.Wait100Continue(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			WroteRequest: func(_ httptrace.WroteRequestInfo) { | ||||
| 				if it.WroteRequest != nil { | ||||
| 					it.WroteRequest(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 		} | ||||
| 		r = r.WithContext(httptrace.WithClientTrace(context.Background(), trace)) | ||||
|  | ||||
| 		return next.RoundTrip(r) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										430
									
								
								vendor/github.com/prometheus/client_golang/prometheus/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										430
									
								
								vendor/github.com/prometheus/client_golang/prometheus/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -15,17 +15,22 @@ package prometheus | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/prometheus/common/expfmt" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
|  | ||||
| 	"github.com/prometheus/client_golang/prometheus/internal" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -38,12 +43,13 @@ const ( | ||||
| // Registerer and Gatherer interface a number of convenience functions in this | ||||
| // package act on. Initially, both variables point to the same Registry, which | ||||
| // has a process collector (currently on Linux only, see NewProcessCollector) | ||||
| // and a Go collector (see NewGoCollector) already registered. This approach to | ||||
| // keep default instances as global state mirrors the approach of other packages | ||||
| // in the Go standard library. Note that there are caveats. Change the variables | ||||
| // with caution and only if you understand the consequences. Users who want to | ||||
| // avoid global state altogether should not use the convenience functions and | ||||
| // act on custom instances instead. | ||||
| // and a Go collector (see NewGoCollector, in particular the note about | ||||
| // stop-the-world implication with Go versions older than 1.9) already | ||||
| // registered. This approach to keep default instances as global state mirrors | ||||
| // the approach of other packages in the Go standard library. Note that there | ||||
| // are caveats. Change the variables with caution and only if you understand the | ||||
| // consequences. Users who want to avoid global state altogether should not use | ||||
| // the convenience functions and act on custom instances instead. | ||||
| var ( | ||||
| 	defaultRegistry              = NewRegistry() | ||||
| 	DefaultRegisterer Registerer = defaultRegistry | ||||
| @@ -51,7 +57,7 @@ var ( | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	MustRegister(NewProcessCollector(os.Getpid(), "")) | ||||
| 	MustRegister(NewProcessCollector(ProcessCollectorOpts{})) | ||||
| 	MustRegister(NewGoCollector()) | ||||
| } | ||||
|  | ||||
| @@ -67,7 +73,8 @@ func NewRegistry() *Registry { | ||||
|  | ||||
| // NewPedanticRegistry returns a registry that checks during collection if each | ||||
| // collected Metric is consistent with its reported Desc, and if the Desc has | ||||
| // actually been registered with the registry. | ||||
| // actually been registered with the registry. Unchecked Collectors (those whose | ||||
| // Describe methed does not yield any descriptors) are excluded from the check. | ||||
| // | ||||
| // Usually, a Registry will be happy as long as the union of all collected | ||||
| // Metrics is consistent and valid even if some metrics are not consistent with | ||||
| @@ -97,8 +104,13 @@ type Registerer interface { | ||||
| 	// returned error is an instance of AlreadyRegisteredError, which | ||||
| 	// contains the previously registered Collector. | ||||
| 	// | ||||
| 	// It is in general not safe to register the same Collector multiple | ||||
| 	// times concurrently. | ||||
| 	// A Collector whose Describe method does not yield any Desc is treated | ||||
| 	// as unchecked. Registration will always succeed. No check for | ||||
| 	// re-registering (see previous paragraph) is performed. Thus, the | ||||
| 	// caller is responsible for not double-registering the same unchecked | ||||
| 	// Collector, and for providing a Collector that will not cause | ||||
| 	// inconsistent metrics on collection. (This would lead to scrape | ||||
| 	// errors.) | ||||
| 	Register(Collector) error | ||||
| 	// MustRegister works like Register but registers any number of | ||||
| 	// Collectors and panics upon the first registration that causes an | ||||
| @@ -107,7 +119,9 @@ type Registerer interface { | ||||
| 	// Unregister unregisters the Collector that equals the Collector passed | ||||
| 	// in as an argument.  (Two Collectors are considered equal if their | ||||
| 	// Describe method yields the same set of descriptors.) The function | ||||
| 	// returns whether a Collector was unregistered. | ||||
| 	// returns whether a Collector was unregistered. Note that an unchecked | ||||
| 	// Collector cannot be unregistered (as its Describe method does not | ||||
| 	// yield any descriptor). | ||||
| 	// | ||||
| 	// Note that even after unregistering, it will not be possible to | ||||
| 	// register a new Collector that is inconsistent with the unregistered | ||||
| @@ -125,15 +139,23 @@ type Registerer interface { | ||||
| type Gatherer interface { | ||||
| 	// Gather calls the Collect method of the registered Collectors and then | ||||
| 	// gathers the collected metrics into a lexicographically sorted slice | ||||
| 	// of MetricFamily protobufs. Even if an error occurs, Gather attempts | ||||
| 	// to gather as many metrics as possible. Hence, if a non-nil error is | ||||
| 	// returned, the returned MetricFamily slice could be nil (in case of a | ||||
| 	// fatal error that prevented any meaningful metric collection) or | ||||
| 	// contain a number of MetricFamily protobufs, some of which might be | ||||
| 	// incomplete, and some might be missing altogether. The returned error | ||||
| 	// (which might be a MultiError) explains the details. In scenarios | ||||
| 	// where complete collection is critical, the returned MetricFamily | ||||
| 	// protobufs should be disregarded if the returned error is non-nil. | ||||
| 	// of uniquely named MetricFamily protobufs. Gather ensures that the | ||||
| 	// returned slice is valid and self-consistent so that it can be used | ||||
| 	// for valid exposition. As an exception to the strict consistency | ||||
| 	// requirements described for metric.Desc, Gather will tolerate | ||||
| 	// different sets of label names for metrics of the same metric family. | ||||
| 	// | ||||
| 	// Even if an error occurs, Gather attempts to gather as many metrics as | ||||
| 	// possible. Hence, if a non-nil error is returned, the returned | ||||
| 	// MetricFamily slice could be nil (in case of a fatal error that | ||||
| 	// prevented any meaningful metric collection) or contain a number of | ||||
| 	// MetricFamily protobufs, some of which might be incomplete, and some | ||||
| 	// might be missing altogether. The returned error (which might be a | ||||
| 	// MultiError) explains the details. Note that this is mostly useful for | ||||
| 	// debugging purposes. If the gathered protobufs are to be used for | ||||
| 	// exposition in actual monitoring, it is almost always better to not | ||||
| 	// expose an incomplete result and instead disregard the returned | ||||
| 	// MetricFamily protobufs in case the returned error is non-nil. | ||||
| 	Gather() ([]*dto.MetricFamily, error) | ||||
| } | ||||
|  | ||||
| @@ -234,6 +256,7 @@ type Registry struct { | ||||
| 	collectorsByID        map[uint64]Collector // ID is a hash of the descIDs. | ||||
| 	descIDs               map[uint64]struct{} | ||||
| 	dimHashesByName       map[string]uint64 | ||||
| 	uncheckedCollectors   []Collector | ||||
| 	pedanticChecksEnabled bool | ||||
| } | ||||
|  | ||||
| @@ -251,7 +274,12 @@ func (r *Registry) Register(c Collector) error { | ||||
| 		close(descChan) | ||||
| 	}() | ||||
| 	r.mtx.Lock() | ||||
| 	defer r.mtx.Unlock() | ||||
| 	defer func() { | ||||
| 		// Drain channel in case of premature return to not leak a goroutine. | ||||
| 		for range descChan { | ||||
| 		} | ||||
| 		r.mtx.Unlock() | ||||
| 	}() | ||||
| 	// Conduct various tests... | ||||
| 	for desc := range descChan { | ||||
|  | ||||
| @@ -291,9 +319,10 @@ func (r *Registry) Register(c Collector) error { | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// Did anything happen at all? | ||||
| 	// A Collector yielding no Desc at all is considered unchecked. | ||||
| 	if len(newDescIDs) == 0 { | ||||
| 		return errors.New("collector has no descriptors") | ||||
| 		r.uncheckedCollectors = append(r.uncheckedCollectors, c) | ||||
| 		return nil | ||||
| 	} | ||||
| 	if existing, exists := r.collectorsByID[collectorID]; exists { | ||||
| 		return AlreadyRegisteredError{ | ||||
| @@ -367,20 +396,24 @@ func (r *Registry) MustRegister(cs ...Collector) { | ||||
| // Gather implements Gatherer. | ||||
| func (r *Registry) Gather() ([]*dto.MetricFamily, error) { | ||||
| 	var ( | ||||
| 		metricChan        = make(chan Metric, capMetricChan) | ||||
| 		metricHashes      = map[uint64]struct{}{} | ||||
| 		dimHashes         = map[string]uint64{} | ||||
| 		wg                sync.WaitGroup | ||||
| 		errs              MultiError          // The collected errors to return in the end. | ||||
| 		registeredDescIDs map[uint64]struct{} // Only used for pedantic checks | ||||
| 		checkedMetricChan   = make(chan Metric, capMetricChan) | ||||
| 		uncheckedMetricChan = make(chan Metric, capMetricChan) | ||||
| 		metricHashes        = map[uint64]struct{}{} | ||||
| 		wg                  sync.WaitGroup | ||||
| 		errs                MultiError          // The collected errors to return in the end. | ||||
| 		registeredDescIDs   map[uint64]struct{} // Only used for pedantic checks | ||||
| 	) | ||||
|  | ||||
| 	r.mtx.RLock() | ||||
| 	goroutineBudget := len(r.collectorsByID) | ||||
| 	goroutineBudget := len(r.collectorsByID) + len(r.uncheckedCollectors) | ||||
| 	metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName)) | ||||
| 	collectors := make(chan Collector, len(r.collectorsByID)) | ||||
| 	checkedCollectors := make(chan Collector, len(r.collectorsByID)) | ||||
| 	uncheckedCollectors := make(chan Collector, len(r.uncheckedCollectors)) | ||||
| 	for _, collector := range r.collectorsByID { | ||||
| 		collectors <- collector | ||||
| 		checkedCollectors <- collector | ||||
| 	} | ||||
| 	for _, collector := range r.uncheckedCollectors { | ||||
| 		uncheckedCollectors <- collector | ||||
| 	} | ||||
| 	// In case pedantic checks are enabled, we have to copy the map before | ||||
| 	// giving up the RLock. | ||||
| @@ -397,12 +430,14 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { | ||||
| 	collectWorker := func() { | ||||
| 		for { | ||||
| 			select { | ||||
| 			case collector := <-collectors: | ||||
| 				collector.Collect(metricChan) | ||||
| 				wg.Done() | ||||
| 			case collector := <-checkedCollectors: | ||||
| 				collector.Collect(checkedMetricChan) | ||||
| 			case collector := <-uncheckedCollectors: | ||||
| 				collector.Collect(uncheckedMetricChan) | ||||
| 			default: | ||||
| 				return | ||||
| 			} | ||||
| 			wg.Done() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -410,53 +445,128 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { | ||||
| 	go collectWorker() | ||||
| 	goroutineBudget-- | ||||
|  | ||||
| 	// Close the metricChan once all collectors are collected. | ||||
| 	// Close checkedMetricChan and uncheckedMetricChan once all collectors | ||||
| 	// are collected. | ||||
| 	go func() { | ||||
| 		wg.Wait() | ||||
| 		close(metricChan) | ||||
| 		close(checkedMetricChan) | ||||
| 		close(uncheckedMetricChan) | ||||
| 	}() | ||||
|  | ||||
| 	// Drain metricChan in case of premature return. | ||||
| 	// Drain checkedMetricChan and uncheckedMetricChan in case of premature return. | ||||
| 	defer func() { | ||||
| 		for range metricChan { | ||||
| 		if checkedMetricChan != nil { | ||||
| 			for range checkedMetricChan { | ||||
| 			} | ||||
| 		} | ||||
| 		if uncheckedMetricChan != nil { | ||||
| 			for range uncheckedMetricChan { | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| collectLoop: | ||||
| 	// Copy the channel references so we can nil them out later to remove | ||||
| 	// them from the select statements below. | ||||
| 	cmc := checkedMetricChan | ||||
| 	umc := uncheckedMetricChan | ||||
|  | ||||
| 	for { | ||||
| 		select { | ||||
| 		case metric, ok := <-metricChan: | ||||
| 		case metric, ok := <-cmc: | ||||
| 			if !ok { | ||||
| 				// metricChan is closed, we are done. | ||||
| 				break collectLoop | ||||
| 				cmc = nil | ||||
| 				break | ||||
| 			} | ||||
| 			errs.Append(processMetric( | ||||
| 				metric, metricFamiliesByName, | ||||
| 				metricHashes, dimHashes, | ||||
| 				metricHashes, | ||||
| 				registeredDescIDs, | ||||
| 			)) | ||||
| 		case metric, ok := <-umc: | ||||
| 			if !ok { | ||||
| 				umc = nil | ||||
| 				break | ||||
| 			} | ||||
| 			errs.Append(processMetric( | ||||
| 				metric, metricFamiliesByName, | ||||
| 				metricHashes, | ||||
| 				nil, | ||||
| 			)) | ||||
| 		default: | ||||
| 			if goroutineBudget <= 0 || len(collectors) == 0 { | ||||
| 				// All collectors are aleady being worked on or | ||||
| 			if goroutineBudget <= 0 || len(checkedCollectors)+len(uncheckedCollectors) == 0 { | ||||
| 				// All collectors are already being worked on or | ||||
| 				// we have already as many goroutines started as | ||||
| 				// there are collectors. Just process metrics | ||||
| 				// from now on. | ||||
| 				for metric := range metricChan { | ||||
| 				// there are collectors. Do the same as above, | ||||
| 				// just without the default. | ||||
| 				select { | ||||
| 				case metric, ok := <-cmc: | ||||
| 					if !ok { | ||||
| 						cmc = nil | ||||
| 						break | ||||
| 					} | ||||
| 					errs.Append(processMetric( | ||||
| 						metric, metricFamiliesByName, | ||||
| 						metricHashes, dimHashes, | ||||
| 						metricHashes, | ||||
| 						registeredDescIDs, | ||||
| 					)) | ||||
| 				case metric, ok := <-umc: | ||||
| 					if !ok { | ||||
| 						umc = nil | ||||
| 						break | ||||
| 					} | ||||
| 					errs.Append(processMetric( | ||||
| 						metric, metricFamiliesByName, | ||||
| 						metricHashes, | ||||
| 						nil, | ||||
| 					)) | ||||
| 				} | ||||
| 				break collectLoop | ||||
| 				break | ||||
| 			} | ||||
| 			// Start more workers. | ||||
| 			go collectWorker() | ||||
| 			goroutineBudget-- | ||||
| 			runtime.Gosched() | ||||
| 		} | ||||
| 		// Once both checkedMetricChan and uncheckdMetricChan are closed | ||||
| 		// and drained, the contraption above will nil out cmc and umc, | ||||
| 		// and then we can leave the collect loop here. | ||||
| 		if cmc == nil && umc == nil { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return normalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() | ||||
| 	return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() | ||||
| } | ||||
|  | ||||
| // WriteToTextfile calls Gather on the provided Gatherer, encodes the result in the | ||||
| // Prometheus text format, and writes it to a temporary file. Upon success, the | ||||
| // temporary file is renamed to the provided filename. | ||||
| // | ||||
| // This is intended for use with the textfile collector of the node exporter. | ||||
| // Note that the node exporter expects the filename to be suffixed with ".prom". | ||||
| func WriteToTextfile(filename string, g Gatherer) error { | ||||
| 	tmp, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer os.Remove(tmp.Name()) | ||||
|  | ||||
| 	mfs, err := g.Gather() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, mf := range mfs { | ||||
| 		if _, err := expfmt.MetricFamilyToText(tmp, mf); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if err := tmp.Close(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if err := os.Chmod(tmp.Name(), 0644); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return os.Rename(tmp.Name(), filename) | ||||
| } | ||||
|  | ||||
| // processMetric is an internal helper method only used by the Gather method. | ||||
| @@ -464,16 +574,20 @@ func processMetric( | ||||
| 	metric Metric, | ||||
| 	metricFamiliesByName map[string]*dto.MetricFamily, | ||||
| 	metricHashes map[uint64]struct{}, | ||||
| 	dimHashes map[string]uint64, | ||||
| 	registeredDescIDs map[uint64]struct{}, | ||||
| ) error { | ||||
| 	desc := metric.Desc() | ||||
| 	// Wrapped metrics collected by an unchecked Collector can have an | ||||
| 	// invalid Desc. | ||||
| 	if desc.err != nil { | ||||
| 		return desc.err | ||||
| 	} | ||||
| 	dtoMetric := &dto.Metric{} | ||||
| 	if err := metric.Write(dtoMetric); err != nil { | ||||
| 		return fmt.Errorf("error collecting metric %v: %s", desc, err) | ||||
| 	} | ||||
| 	metricFamily, ok := metricFamiliesByName[desc.fqName] | ||||
| 	if ok { | ||||
| 	if ok { // Existing name. | ||||
| 		if metricFamily.GetHelp() != desc.help { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %s %s has help %q but should have %q", | ||||
| @@ -520,7 +634,7 @@ func processMetric( | ||||
| 		default: | ||||
| 			panic("encountered MetricFamily with invalid type") | ||||
| 		} | ||||
| 	} else { | ||||
| 	} else { // New name. | ||||
| 		metricFamily = &dto.MetricFamily{} | ||||
| 		metricFamily.Name = proto.String(desc.fqName) | ||||
| 		metricFamily.Help = proto.String(desc.help) | ||||
| @@ -539,9 +653,12 @@ func processMetric( | ||||
| 		default: | ||||
| 			return fmt.Errorf("empty metric collected: %s", dtoMetric) | ||||
| 		} | ||||
| 		if err := checkSuffixCollisions(metricFamily, metricFamiliesByName); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		metricFamiliesByName[desc.fqName] = metricFamily | ||||
| 	} | ||||
| 	if err := checkMetricConsistency(metricFamily, dtoMetric, metricHashes, dimHashes); err != nil { | ||||
| 	if err := checkMetricConsistency(metricFamily, dtoMetric, metricHashes); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if registeredDescIDs != nil { | ||||
| @@ -563,7 +680,7 @@ func processMetric( | ||||
| // Gatherers is a slice of Gatherer instances that implements the Gatherer | ||||
| // interface itself. Its Gather method calls Gather on all Gatherers in the | ||||
| // slice in order and returns the merged results. Errors returned from the | ||||
| // Gather calles are all returned in a flattened MultiError. Duplicate and | ||||
| // Gather calls are all returned in a flattened MultiError. Duplicate and | ||||
| // inconsistent Metrics are skipped (first occurrence in slice order wins) and | ||||
| // reported in the returned error. | ||||
| // | ||||
| @@ -583,7 +700,6 @@ func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) { | ||||
| 	var ( | ||||
| 		metricFamiliesByName = map[string]*dto.MetricFamily{} | ||||
| 		metricHashes         = map[uint64]struct{}{} | ||||
| 		dimHashes            = map[string]uint64{} | ||||
| 		errs                 MultiError // The collected errors to return in the end. | ||||
| 	) | ||||
|  | ||||
| @@ -620,10 +736,14 @@ func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) { | ||||
| 				existingMF.Name = mf.Name | ||||
| 				existingMF.Help = mf.Help | ||||
| 				existingMF.Type = mf.Type | ||||
| 				if err := checkSuffixCollisions(existingMF, metricFamiliesByName); err != nil { | ||||
| 					errs = append(errs, err) | ||||
| 					continue | ||||
| 				} | ||||
| 				metricFamiliesByName[mf.GetName()] = existingMF | ||||
| 			} | ||||
| 			for _, m := range mf.Metric { | ||||
| 				if err := checkMetricConsistency(existingMF, m, metricHashes, dimHashes); err != nil { | ||||
| 				if err := checkMetricConsistency(existingMF, m, metricHashes); err != nil { | ||||
| 					errs = append(errs, err) | ||||
| 					continue | ||||
| 				} | ||||
| @@ -631,88 +751,80 @@ func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) { | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return normalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() | ||||
| 	return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() | ||||
| } | ||||
|  | ||||
| // metricSorter is a sortable slice of *dto.Metric. | ||||
| type metricSorter []*dto.Metric | ||||
|  | ||||
| func (s metricSorter) Len() int { | ||||
| 	return len(s) | ||||
| } | ||||
|  | ||||
| func (s metricSorter) Swap(i, j int) { | ||||
| 	s[i], s[j] = s[j], s[i] | ||||
| } | ||||
|  | ||||
| func (s metricSorter) Less(i, j int) bool { | ||||
| 	if len(s[i].Label) != len(s[j].Label) { | ||||
| 		// This should not happen. The metrics are | ||||
| 		// inconsistent. However, we have to deal with the fact, as | ||||
| 		// people might use custom collectors or metric family injection | ||||
| 		// to create inconsistent metrics. So let's simply compare the | ||||
| 		// number of labels in this case. That will still yield | ||||
| 		// reproducible sorting. | ||||
| 		return len(s[i].Label) < len(s[j].Label) | ||||
| // checkSuffixCollisions checks for collisions with the “magic” suffixes the | ||||
| // Prometheus text format and the internal metric representation of the | ||||
| // Prometheus server add while flattening Summaries and Histograms. | ||||
| func checkSuffixCollisions(mf *dto.MetricFamily, mfs map[string]*dto.MetricFamily) error { | ||||
| 	var ( | ||||
| 		newName              = mf.GetName() | ||||
| 		newType              = mf.GetType() | ||||
| 		newNameWithoutSuffix = "" | ||||
| 	) | ||||
| 	switch { | ||||
| 	case strings.HasSuffix(newName, "_count"): | ||||
| 		newNameWithoutSuffix = newName[:len(newName)-6] | ||||
| 	case strings.HasSuffix(newName, "_sum"): | ||||
| 		newNameWithoutSuffix = newName[:len(newName)-4] | ||||
| 	case strings.HasSuffix(newName, "_bucket"): | ||||
| 		newNameWithoutSuffix = newName[:len(newName)-7] | ||||
| 	} | ||||
| 	for n, lp := range s[i].Label { | ||||
| 		vi := lp.GetValue() | ||||
| 		vj := s[j].Label[n].GetValue() | ||||
| 		if vi != vj { | ||||
| 			return vi < vj | ||||
| 	if newNameWithoutSuffix != "" { | ||||
| 		if existingMF, ok := mfs[newNameWithoutSuffix]; ok { | ||||
| 			switch existingMF.GetType() { | ||||
| 			case dto.MetricType_SUMMARY: | ||||
| 				if !strings.HasSuffix(newName, "_bucket") { | ||||
| 					return fmt.Errorf( | ||||
| 						"collected metric named %q collides with previously collected summary named %q", | ||||
| 						newName, newNameWithoutSuffix, | ||||
| 					) | ||||
| 				} | ||||
| 			case dto.MetricType_HISTOGRAM: | ||||
| 				return fmt.Errorf( | ||||
| 					"collected metric named %q collides with previously collected histogram named %q", | ||||
| 					newName, newNameWithoutSuffix, | ||||
| 				) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// We should never arrive here. Multiple metrics with the same | ||||
| 	// label set in the same scrape will lead to undefined ingestion | ||||
| 	// behavior. However, as above, we have to provide stable sorting | ||||
| 	// here, even for inconsistent metrics. So sort equal metrics | ||||
| 	// by their timestamp, with missing timestamps (implying "now") | ||||
| 	// coming last. | ||||
| 	if s[i].TimestampMs == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	if s[j].TimestampMs == nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	return s[i].GetTimestampMs() < s[j].GetTimestampMs() | ||||
| } | ||||
|  | ||||
| // normalizeMetricFamilies returns a MetricFamily slice with empty | ||||
| // MetricFamilies pruned and the remaining MetricFamilies sorted by name within | ||||
| // the slice, with the contained Metrics sorted within each MetricFamily. | ||||
| func normalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily { | ||||
| 	for _, mf := range metricFamiliesByName { | ||||
| 		sort.Sort(metricSorter(mf.Metric)) | ||||
| 	} | ||||
| 	names := make([]string, 0, len(metricFamiliesByName)) | ||||
| 	for name, mf := range metricFamiliesByName { | ||||
| 		if len(mf.Metric) > 0 { | ||||
| 			names = append(names, name) | ||||
| 	if newType == dto.MetricType_SUMMARY || newType == dto.MetricType_HISTOGRAM { | ||||
| 		if _, ok := mfs[newName+"_count"]; ok { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected histogram or summary named %q collides with previously collected metric named %q", | ||||
| 				newName, newName+"_count", | ||||
| 			) | ||||
| 		} | ||||
| 		if _, ok := mfs[newName+"_sum"]; ok { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected histogram or summary named %q collides with previously collected metric named %q", | ||||
| 				newName, newName+"_sum", | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
| 	sort.Strings(names) | ||||
| 	result := make([]*dto.MetricFamily, 0, len(names)) | ||||
| 	for _, name := range names { | ||||
| 		result = append(result, metricFamiliesByName[name]) | ||||
| 	if newType == dto.MetricType_HISTOGRAM { | ||||
| 		if _, ok := mfs[newName+"_bucket"]; ok { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected histogram named %q collides with previously collected metric named %q", | ||||
| 				newName, newName+"_bucket", | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
| 	return result | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // checkMetricConsistency checks if the provided Metric is consistent with the | ||||
| // provided MetricFamily. It also hashed the Metric labels and the MetricFamily | ||||
| // provided MetricFamily. It also hashes the Metric labels and the MetricFamily | ||||
| // name. If the resulting hash is already in the provided metricHashes, an error | ||||
| // is returned. If not, it is added to metricHashes. The provided dimHashes maps | ||||
| // MetricFamily names to their dimHash (hashed sorted label names). If dimHashes | ||||
| // doesn't yet contain a hash for the provided MetricFamily, it is | ||||
| // added. Otherwise, an error is returned if the existing dimHashes in not equal | ||||
| // the calculated dimHash. | ||||
| // is returned. If not, it is added to metricHashes. | ||||
| func checkMetricConsistency( | ||||
| 	metricFamily *dto.MetricFamily, | ||||
| 	dtoMetric *dto.Metric, | ||||
| 	metricHashes map[uint64]struct{}, | ||||
| 	dimHashes map[string]uint64, | ||||
| ) error { | ||||
| 	name := metricFamily.GetName() | ||||
|  | ||||
| 	// Type consistency with metric family. | ||||
| 	if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil || | ||||
| 		metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil || | ||||
| @@ -720,47 +832,65 @@ func checkMetricConsistency( | ||||
| 		metricFamily.GetType() == dto.MetricType_HISTOGRAM && dtoMetric.Histogram == nil || | ||||
| 		metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil { | ||||
| 		return fmt.Errorf( | ||||
| 			"collected metric %s %s is not a %s", | ||||
| 			metricFamily.GetName(), dtoMetric, metricFamily.GetType(), | ||||
| 			"collected metric %q { %s} is not a %s", | ||||
| 			name, dtoMetric, metricFamily.GetType(), | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	previousLabelName := "" | ||||
| 	for _, labelPair := range dtoMetric.GetLabel() { | ||||
| 		if !utf8.ValidString(*labelPair.Value) { | ||||
| 			return fmt.Errorf("collected metric's label %s is not utf8: %#v", *labelPair.Name, *labelPair.Value) | ||||
| 		labelName := labelPair.GetName() | ||||
| 		if labelName == previousLabelName { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %q { %s} has two or more labels with the same name: %s", | ||||
| 				name, dtoMetric, labelName, | ||||
| 			) | ||||
| 		} | ||||
| 		if !checkLabelName(labelName) { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %q { %s} has a label with an invalid name: %s", | ||||
| 				name, dtoMetric, labelName, | ||||
| 			) | ||||
| 		} | ||||
| 		if dtoMetric.Summary != nil && labelName == quantileLabel { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %q { %s} must not have an explicit %q label", | ||||
| 				name, dtoMetric, quantileLabel, | ||||
| 			) | ||||
| 		} | ||||
| 		if !utf8.ValidString(labelPair.GetValue()) { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %q { %s} has a label named %q whose value is not utf8: %#v", | ||||
| 				name, dtoMetric, labelName, labelPair.GetValue()) | ||||
| 		} | ||||
| 		previousLabelName = labelName | ||||
| 	} | ||||
|  | ||||
| 	// Is the metric unique (i.e. no other metric with the same name and the same label values)? | ||||
| 	// Is the metric unique (i.e. no other metric with the same name and the same labels)? | ||||
| 	h := hashNew() | ||||
| 	h = hashAdd(h, metricFamily.GetName()) | ||||
| 	h = hashAdd(h, name) | ||||
| 	h = hashAddByte(h, separatorByte) | ||||
| 	dh := hashNew() | ||||
| 	// Make sure label pairs are sorted. We depend on it for the consistency | ||||
| 	// check. | ||||
| 	sort.Sort(LabelPairSorter(dtoMetric.Label)) | ||||
| 	if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) { | ||||
| 		// We cannot sort dtoMetric.Label in place as it is immutable by contract. | ||||
| 		copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label)) | ||||
| 		copy(copiedLabels, dtoMetric.Label) | ||||
| 		sort.Sort(labelPairSorter(copiedLabels)) | ||||
| 		dtoMetric.Label = copiedLabels | ||||
| 	} | ||||
| 	for _, lp := range dtoMetric.Label { | ||||
| 		h = hashAdd(h, lp.GetName()) | ||||
| 		h = hashAddByte(h, separatorByte) | ||||
| 		h = hashAdd(h, lp.GetValue()) | ||||
| 		h = hashAddByte(h, separatorByte) | ||||
| 		dh = hashAdd(dh, lp.GetName()) | ||||
| 		dh = hashAddByte(dh, separatorByte) | ||||
| 	} | ||||
| 	if _, exists := metricHashes[h]; exists { | ||||
| 		return fmt.Errorf( | ||||
| 			"collected metric %s %s was collected before with the same name and label values", | ||||
| 			metricFamily.GetName(), dtoMetric, | ||||
| 			"collected metric %q { %s} was collected before with the same name and label values", | ||||
| 			name, dtoMetric, | ||||
| 		) | ||||
| 	} | ||||
| 	if dimHash, ok := dimHashes[metricFamily.GetName()]; ok { | ||||
| 		if dimHash != dh { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %s %s has label dimensions inconsistent with previously collected metrics in the same metric family", | ||||
| 				metricFamily.GetName(), dtoMetric, | ||||
| 			) | ||||
| 		} | ||||
| 	} else { | ||||
| 		dimHashes[metricFamily.GetName()] = dh | ||||
| 	} | ||||
| 	metricHashes[h] = struct{}{} | ||||
| 	return nil | ||||
| } | ||||
| @@ -779,8 +909,8 @@ func checkDescConsistency( | ||||
| 	} | ||||
|  | ||||
| 	// Is the desc consistent with the content of the metric? | ||||
| 	lpsFromDesc := make([]*dto.LabelPair, 0, len(dtoMetric.Label)) | ||||
| 	lpsFromDesc = append(lpsFromDesc, desc.constLabelPairs...) | ||||
| 	lpsFromDesc := make([]*dto.LabelPair, len(desc.constLabelPairs), len(dtoMetric.Label)) | ||||
| 	copy(lpsFromDesc, desc.constLabelPairs) | ||||
| 	for _, l := range desc.variableLabels { | ||||
| 		lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{ | ||||
| 			Name: proto.String(l), | ||||
| @@ -792,7 +922,7 @@ func checkDescConsistency( | ||||
| 			metricFamily.GetName(), dtoMetric, desc, | ||||
| 		) | ||||
| 	} | ||||
| 	sort.Sort(LabelPairSorter(lpsFromDesc)) | ||||
| 	sort.Sort(labelPairSorter(lpsFromDesc)) | ||||
| 	for i, lpFromDesc := range lpsFromDesc { | ||||
| 		lpFromMetric := dtoMetric.Label[i] | ||||
| 		if lpFromDesc.GetName() != lpFromMetric.GetName() || | ||||
|   | ||||
							
								
								
									
										165
									
								
								vendor/github.com/prometheus/client_golang/prometheus/summary.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										165
									
								
								vendor/github.com/prometheus/client_golang/prometheus/summary.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -16,8 +16,10 @@ package prometheus | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"runtime" | ||||
| 	"sort" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/beorn7/perks/quantile" | ||||
| @@ -37,7 +39,7 @@ const quantileLabel = "quantile" | ||||
| // A typical use-case is the observation of request latencies. By default, a | ||||
| // Summary provides the median, the 90th and the 99th percentile of the latency | ||||
| // as rank estimations. However, the default behavior will change in the | ||||
| // upcoming v0.10 of the library. There will be no rank estiamtions at all by | ||||
| // upcoming v0.10 of the library. There will be no rank estimations at all by | ||||
| // default. For a sane transition, it is recommended to set the desired rank | ||||
| // estimations explicitly. | ||||
| // | ||||
| @@ -81,10 +83,10 @@ const ( | ||||
| ) | ||||
|  | ||||
| // SummaryOpts bundles the options for creating a Summary metric. It is | ||||
| // mandatory to set Name and Help to a non-empty string. While all other fields | ||||
| // are optional and can safely be left at their zero value, it is recommended to | ||||
| // explicitly set the Objectives field to the desired value as the default value | ||||
| // will change in the upcoming v0.10 of the library. | ||||
| // mandatory to set Name to a non-empty string. While all other fields are | ||||
| // optional and can safely be left at their zero value, it is recommended to set | ||||
| // a help string and to explicitly set the Objectives field to the desired value | ||||
| // as the default value will change in the upcoming v0.10 of the library. | ||||
| type SummaryOpts struct { | ||||
| 	// Namespace, Subsystem, and Name are components of the fully-qualified | ||||
| 	// name of the Summary (created by joining these components with | ||||
| @@ -95,7 +97,7 @@ type SummaryOpts struct { | ||||
| 	Subsystem string | ||||
| 	Name      string | ||||
|  | ||||
| 	// Help provides information about this Summary. Mandatory! | ||||
| 	// Help provides information about this Summary. | ||||
| 	// | ||||
| 	// Metrics with the same fully-qualified name must have the same Help | ||||
| 	// string. | ||||
| @@ -105,6 +107,11 @@ type SummaryOpts struct { | ||||
| 	// with the same fully-qualified name must have the same label names in | ||||
| 	// their ConstLabels. | ||||
| 	// | ||||
| 	// Due to the way a Summary is represented in the Prometheus text format | ||||
| 	// and how it is handled by the Prometheus server internally, “quantile” | ||||
| 	// is an illegal label name. Construction of a Summary or SummaryVec | ||||
| 	// will panic if this label name is used in ConstLabels. | ||||
| 	// | ||||
| 	// ConstLabels are only used rarely. In particular, do not use them to | ||||
| 	// attach the same labels to all your metrics. Those use cases are | ||||
| 	// better covered by target labels set by the scraping Prometheus | ||||
| @@ -120,9 +127,10 @@ type SummaryOpts struct { | ||||
| 	// its zero value (i.e. nil). To create a Summary without Objectives, | ||||
| 	// set it to an empty map (i.e. map[float64]float64{}). | ||||
| 	// | ||||
| 	// Deprecated: Note that the current value of DefObjectives is | ||||
| 	// deprecated. It will be replaced by an empty map in v0.10 of the | ||||
| 	// library. Please explicitly set Objectives to the desired value. | ||||
| 	// Note that the current value of DefObjectives is deprecated. It will | ||||
| 	// be replaced by an empty map in v0.10 of the library. Please | ||||
| 	// explicitly set Objectives to the desired value to avoid problems | ||||
| 	// during the transition. | ||||
| 	Objectives map[float64]float64 | ||||
|  | ||||
| 	// MaxAge defines the duration for which an observation stays relevant | ||||
| @@ -146,7 +154,7 @@ type SummaryOpts struct { | ||||
| 	BufCap uint32 | ||||
| } | ||||
|  | ||||
| // Great fuck-up with the sliding-window decay algorithm... The Merge method of | ||||
| // Problem with the sliding-window decay algorithm... The Merge method of | ||||
| // perk/quantile is actually not working as advertised - and it might be | ||||
| // unfixable, as the underlying algorithm is apparently not capable of merging | ||||
| // summaries in the first place. To avoid using Merge, we are currently adding | ||||
| @@ -176,7 +184,7 @@ func NewSummary(opts SummaryOpts) Summary { | ||||
|  | ||||
| func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { | ||||
| 	if len(desc.variableLabels) != len(labelValues) { | ||||
| 		panic(errInconsistentCardinality) | ||||
| 		panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) | ||||
| 	} | ||||
|  | ||||
| 	for _, n := range desc.variableLabels { | ||||
| @@ -209,6 +217,17 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { | ||||
| 		opts.BufCap = DefBufCap | ||||
| 	} | ||||
|  | ||||
| 	if len(opts.Objectives) == 0 { | ||||
| 		// Use the lock-free implementation of a Summary without objectives. | ||||
| 		s := &noObjectivesSummary{ | ||||
| 			desc:       desc, | ||||
| 			labelPairs: makeLabelPairs(desc, labelValues), | ||||
| 			counts:     [2]*summaryCounts{&summaryCounts{}, &summaryCounts{}}, | ||||
| 		} | ||||
| 		s.init(s) // Init self-collection. | ||||
| 		return s | ||||
| 	} | ||||
|  | ||||
| 	s := &summary{ | ||||
| 		desc: desc, | ||||
|  | ||||
| @@ -377,6 +396,116 @@ func (s *summary) swapBufs(now time.Time) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type summaryCounts struct { | ||||
| 	// sumBits contains the bits of the float64 representing the sum of all | ||||
| 	// observations. sumBits and count have to go first in the struct to | ||||
| 	// guarantee alignment for atomic operations. | ||||
| 	// http://golang.org/pkg/sync/atomic/#pkg-note-BUG | ||||
| 	sumBits uint64 | ||||
| 	count   uint64 | ||||
| } | ||||
|  | ||||
| type noObjectivesSummary struct { | ||||
| 	// countAndHotIdx enables lock-free writes with use of atomic updates. | ||||
| 	// The most significant bit is the hot index [0 or 1] of the count field | ||||
| 	// below. Observe calls update the hot one. All remaining bits count the | ||||
| 	// number of Observe calls. Observe starts by incrementing this counter, | ||||
| 	// and finish by incrementing the count field in the respective | ||||
| 	// summaryCounts, as a marker for completion. | ||||
| 	// | ||||
| 	// Calls of the Write method (which are non-mutating reads from the | ||||
| 	// perspective of the summary) swap the hot–cold under the writeMtx | ||||
| 	// lock. A cooldown is awaited (while locked) by comparing the number of | ||||
| 	// observations with the initiation count. Once they match, then the | ||||
| 	// last observation on the now cool one has completed. All cool fields must | ||||
| 	// be merged into the new hot before releasing writeMtx. | ||||
|  | ||||
| 	// Fields with atomic access first! See alignment constraint: | ||||
| 	// http://golang.org/pkg/sync/atomic/#pkg-note-BUG | ||||
| 	countAndHotIdx uint64 | ||||
|  | ||||
| 	selfCollector | ||||
| 	desc     *Desc | ||||
| 	writeMtx sync.Mutex // Only used in the Write method. | ||||
|  | ||||
| 	// Two counts, one is "hot" for lock-free observations, the other is | ||||
| 	// "cold" for writing out a dto.Metric. It has to be an array of | ||||
| 	// pointers to guarantee 64bit alignment of the histogramCounts, see | ||||
| 	// http://golang.org/pkg/sync/atomic/#pkg-note-BUG. | ||||
| 	counts [2]*summaryCounts | ||||
|  | ||||
| 	labelPairs []*dto.LabelPair | ||||
| } | ||||
|  | ||||
| func (s *noObjectivesSummary) Desc() *Desc { | ||||
| 	return s.desc | ||||
| } | ||||
|  | ||||
| func (s *noObjectivesSummary) Observe(v float64) { | ||||
| 	// We increment h.countAndHotIdx so that the counter in the lower | ||||
| 	// 63 bits gets incremented. At the same time, we get the new value | ||||
| 	// back, which we can use to find the currently-hot counts. | ||||
| 	n := atomic.AddUint64(&s.countAndHotIdx, 1) | ||||
| 	hotCounts := s.counts[n>>63] | ||||
|  | ||||
| 	for { | ||||
| 		oldBits := atomic.LoadUint64(&hotCounts.sumBits) | ||||
| 		newBits := math.Float64bits(math.Float64frombits(oldBits) + v) | ||||
| 		if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	// Increment count last as we take it as a signal that the observation | ||||
| 	// is complete. | ||||
| 	atomic.AddUint64(&hotCounts.count, 1) | ||||
| } | ||||
|  | ||||
| func (s *noObjectivesSummary) Write(out *dto.Metric) error { | ||||
| 	// For simplicity, we protect this whole method by a mutex. It is not in | ||||
| 	// the hot path, i.e. Observe is called much more often than Write. The | ||||
| 	// complication of making Write lock-free isn't worth it, if possible at | ||||
| 	// all. | ||||
| 	s.writeMtx.Lock() | ||||
| 	defer s.writeMtx.Unlock() | ||||
|  | ||||
| 	// Adding 1<<63 switches the hot index (from 0 to 1 or from 1 to 0) | ||||
| 	// without touching the count bits. See the struct comments for a full | ||||
| 	// description of the algorithm. | ||||
| 	n := atomic.AddUint64(&s.countAndHotIdx, 1<<63) | ||||
| 	// count is contained unchanged in the lower 63 bits. | ||||
| 	count := n & ((1 << 63) - 1) | ||||
| 	// The most significant bit tells us which counts is hot. The complement | ||||
| 	// is thus the cold one. | ||||
| 	hotCounts := s.counts[n>>63] | ||||
| 	coldCounts := s.counts[(^n)>>63] | ||||
|  | ||||
| 	// Await cooldown. | ||||
| 	for count != atomic.LoadUint64(&coldCounts.count) { | ||||
| 		runtime.Gosched() // Let observations get work done. | ||||
| 	} | ||||
|  | ||||
| 	sum := &dto.Summary{ | ||||
| 		SampleCount: proto.Uint64(count), | ||||
| 		SampleSum:   proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), | ||||
| 	} | ||||
|  | ||||
| 	out.Summary = sum | ||||
| 	out.Label = s.labelPairs | ||||
|  | ||||
| 	// Finally add all the cold counts to the new hot counts and reset the cold counts. | ||||
| 	atomic.AddUint64(&hotCounts.count, count) | ||||
| 	atomic.StoreUint64(&coldCounts.count, 0) | ||||
| 	for { | ||||
| 		oldBits := atomic.LoadUint64(&hotCounts.sumBits) | ||||
| 		newBits := math.Float64bits(math.Float64frombits(oldBits) + sum.GetSampleSum()) | ||||
| 		if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { | ||||
| 			atomic.StoreUint64(&coldCounts.sumBits, 0) | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type quantSort []*dto.Quantile | ||||
|  | ||||
| func (s quantSort) Len() int { | ||||
| @@ -402,7 +531,16 @@ type SummaryVec struct { | ||||
|  | ||||
| // NewSummaryVec creates a new SummaryVec based on the provided SummaryOpts and | ||||
| // partitioned by the given label names. | ||||
| // | ||||
| // Due to the way a Summary is represented in the Prometheus text format and how | ||||
| // it is handled by the Prometheus server internally, “quantile” is an illegal | ||||
| // label name. NewSummaryVec will panic if this label name is used. | ||||
| func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec { | ||||
| 	for _, ln := range labelNames { | ||||
| 		if ln == quantileLabel { | ||||
| 			panic(errQuantileLabelNotAllowed) | ||||
| 		} | ||||
| 	} | ||||
| 	desc := NewDesc( | ||||
| 		BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), | ||||
| 		opts.Help, | ||||
| @@ -572,7 +710,7 @@ func (s *constSummary) Write(out *dto.Metric) error { | ||||
| //     map[float64]float64{0.5: 0.23, 0.99: 0.56} | ||||
| // | ||||
| // NewConstSummary returns an error if the length of labelValues is not | ||||
| // consistent with the variable labels in Desc. | ||||
| // consistent with the variable labels in Desc or if Desc is invalid. | ||||
| func NewConstSummary( | ||||
| 	desc *Desc, | ||||
| 	count uint64, | ||||
| @@ -580,6 +718,9 @@ func NewConstSummary( | ||||
| 	quantiles map[float64]float64, | ||||
| 	labelValues ...string, | ||||
| ) (Metric, error) { | ||||
| 	if desc.err != nil { | ||||
| 		return nil, desc.err | ||||
| 	} | ||||
| 	if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										11
									
								
								vendor/github.com/prometheus/client_golang/prometheus/timer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/prometheus/client_golang/prometheus/timer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -39,13 +39,16 @@ func NewTimer(o Observer) *Timer { | ||||
|  | ||||
| // ObserveDuration records the duration passed since the Timer was created with | ||||
| // NewTimer. It calls the Observe method of the Observer provided during | ||||
| // construction with the duration in seconds as an argument. ObserveDuration is | ||||
| // usually called with a defer statement. | ||||
| // construction with the duration in seconds as an argument. The observed | ||||
| // duration is also returned. ObserveDuration is usually called with a defer | ||||
| // statement. | ||||
| // | ||||
| // Note that this method is only guaranteed to never observe negative durations | ||||
| // if used with Go1.9+. | ||||
| func (t *Timer) ObserveDuration() { | ||||
| func (t *Timer) ObserveDuration() time.Duration { | ||||
| 	d := time.Since(t.begin) | ||||
| 	if t.observer != nil { | ||||
| 		t.observer.Observe(time.Since(t.begin).Seconds()) | ||||
| 		t.observer.Observe(d.Seconds()) | ||||
| 	} | ||||
| 	return d | ||||
| } | ||||
|   | ||||
							
								
								
									
										16
									
								
								vendor/github.com/prometheus/client_golang/prometheus/value.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/prometheus/client_golang/prometheus/value.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,9 +17,9 @@ import ( | ||||
| 	"fmt" | ||||
| 	"sort" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| // ValueType is an enumeration of metric types that represent a simple value. | ||||
| @@ -77,8 +77,12 @@ func (v *valueFunc) Write(out *dto.Metric) error { | ||||
| // operations. However, when implementing custom Collectors, it is useful as a | ||||
| // throw-away metric that is generated on the fly to send it to Prometheus in | ||||
| // the Collect method. NewConstMetric returns an error if the length of | ||||
| // labelValues is not consistent with the variable labels in Desc. | ||||
| // labelValues is not consistent with the variable labels in Desc or if Desc is | ||||
| // invalid. | ||||
| func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) { | ||||
| 	if desc.err != nil { | ||||
| 		return nil, desc.err | ||||
| 	} | ||||
| 	if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -152,9 +156,7 @@ func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair { | ||||
| 			Value: proto.String(labelValues[i]), | ||||
| 		}) | ||||
| 	} | ||||
| 	for _, lp := range desc.constLabelPairs { | ||||
| 		labelPairs = append(labelPairs, lp) | ||||
| 	} | ||||
| 	sort.Sort(LabelPairSorter(labelPairs)) | ||||
| 	labelPairs = append(labelPairs, desc.constLabelPairs...) | ||||
| 	sort.Sort(labelPairSorter(labelPairs)) | ||||
| 	return labelPairs | ||||
| } | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/prometheus/client_golang/prometheus/vec.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/prometheus/client_golang/prometheus/vec.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -277,6 +277,9 @@ func (m *metricMap) deleteByHashWithLabelValues( | ||||
| func (m *metricMap) deleteByHashWithLabels( | ||||
| 	h uint64, labels Labels, curry []curriedLabelValue, | ||||
| ) bool { | ||||
| 	m.mtx.Lock() | ||||
| 	defer m.mtx.Unlock() | ||||
|  | ||||
| 	metrics, ok := m.metrics[h] | ||||
| 	if !ok { | ||||
| 		return false | ||||
|   | ||||
							
								
								
									
										179
									
								
								vendor/github.com/prometheus/client_golang/prometheus/wrap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								vendor/github.com/prometheus/client_golang/prometheus/wrap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,179 @@ | ||||
| // Copyright 2018 The Prometheus Authors | ||||
| // 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 prometheus | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"sort" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| // WrapRegistererWith returns a Registerer wrapping the provided | ||||
| // Registerer. Collectors registered with the returned Registerer will be | ||||
| // registered with the wrapped Registerer in a modified way. The modified | ||||
| // Collector adds the provided Labels to all Metrics it collects (as | ||||
| // ConstLabels). The Metrics collected by the unmodified Collector must not | ||||
| // duplicate any of those labels. | ||||
| // | ||||
| // WrapRegistererWith provides a way to add fixed labels to a subset of | ||||
| // Collectors. It should not be used to add fixed labels to all metrics exposed. | ||||
| // | ||||
| // The Collector example demonstrates a use of WrapRegistererWith. | ||||
| func WrapRegistererWith(labels Labels, reg Registerer) Registerer { | ||||
| 	return &wrappingRegisterer{ | ||||
| 		wrappedRegisterer: reg, | ||||
| 		labels:            labels, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WrapRegistererWithPrefix returns a Registerer wrapping the provided | ||||
| // Registerer. Collectors registered with the returned Registerer will be | ||||
| // registered with the wrapped Registerer in a modified way. The modified | ||||
| // Collector adds the provided prefix to the name of all Metrics it collects. | ||||
| // | ||||
| // WrapRegistererWithPrefix is useful to have one place to prefix all metrics of | ||||
| // a sub-system. To make this work, register metrics of the sub-system with the | ||||
| // wrapping Registerer returned by WrapRegistererWithPrefix. It is rarely useful | ||||
| // to use the same prefix for all metrics exposed. In particular, do not prefix | ||||
| // metric names that are standardized across applications, as that would break | ||||
| // horizontal monitoring, for example the metrics provided by the Go collector | ||||
| // (see NewGoCollector) and the process collector (see NewProcessCollector). (In | ||||
| // fact, those metrics are already prefixed with “go_” or “process_”, | ||||
| // respectively.) | ||||
| func WrapRegistererWithPrefix(prefix string, reg Registerer) Registerer { | ||||
| 	return &wrappingRegisterer{ | ||||
| 		wrappedRegisterer: reg, | ||||
| 		prefix:            prefix, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type wrappingRegisterer struct { | ||||
| 	wrappedRegisterer Registerer | ||||
| 	prefix            string | ||||
| 	labels            Labels | ||||
| } | ||||
|  | ||||
| func (r *wrappingRegisterer) Register(c Collector) error { | ||||
| 	return r.wrappedRegisterer.Register(&wrappingCollector{ | ||||
| 		wrappedCollector: c, | ||||
| 		prefix:           r.prefix, | ||||
| 		labels:           r.labels, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (r *wrappingRegisterer) MustRegister(cs ...Collector) { | ||||
| 	for _, c := range cs { | ||||
| 		if err := r.Register(c); err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *wrappingRegisterer) Unregister(c Collector) bool { | ||||
| 	return r.wrappedRegisterer.Unregister(&wrappingCollector{ | ||||
| 		wrappedCollector: c, | ||||
| 		prefix:           r.prefix, | ||||
| 		labels:           r.labels, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| type wrappingCollector struct { | ||||
| 	wrappedCollector Collector | ||||
| 	prefix           string | ||||
| 	labels           Labels | ||||
| } | ||||
|  | ||||
| func (c *wrappingCollector) Collect(ch chan<- Metric) { | ||||
| 	wrappedCh := make(chan Metric) | ||||
| 	go func() { | ||||
| 		c.wrappedCollector.Collect(wrappedCh) | ||||
| 		close(wrappedCh) | ||||
| 	}() | ||||
| 	for m := range wrappedCh { | ||||
| 		ch <- &wrappingMetric{ | ||||
| 			wrappedMetric: m, | ||||
| 			prefix:        c.prefix, | ||||
| 			labels:        c.labels, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *wrappingCollector) Describe(ch chan<- *Desc) { | ||||
| 	wrappedCh := make(chan *Desc) | ||||
| 	go func() { | ||||
| 		c.wrappedCollector.Describe(wrappedCh) | ||||
| 		close(wrappedCh) | ||||
| 	}() | ||||
| 	for desc := range wrappedCh { | ||||
| 		ch <- wrapDesc(desc, c.prefix, c.labels) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type wrappingMetric struct { | ||||
| 	wrappedMetric Metric | ||||
| 	prefix        string | ||||
| 	labels        Labels | ||||
| } | ||||
|  | ||||
| func (m *wrappingMetric) Desc() *Desc { | ||||
| 	return wrapDesc(m.wrappedMetric.Desc(), m.prefix, m.labels) | ||||
| } | ||||
|  | ||||
| func (m *wrappingMetric) Write(out *dto.Metric) error { | ||||
| 	if err := m.wrappedMetric.Write(out); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if len(m.labels) == 0 { | ||||
| 		// No wrapping labels. | ||||
| 		return nil | ||||
| 	} | ||||
| 	for ln, lv := range m.labels { | ||||
| 		out.Label = append(out.Label, &dto.LabelPair{ | ||||
| 			Name:  proto.String(ln), | ||||
| 			Value: proto.String(lv), | ||||
| 		}) | ||||
| 	} | ||||
| 	sort.Sort(labelPairSorter(out.Label)) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc { | ||||
| 	constLabels := Labels{} | ||||
| 	for _, lp := range desc.constLabelPairs { | ||||
| 		constLabels[*lp.Name] = *lp.Value | ||||
| 	} | ||||
| 	for ln, lv := range labels { | ||||
| 		if _, alreadyUsed := constLabels[ln]; alreadyUsed { | ||||
| 			return &Desc{ | ||||
| 				fqName:          desc.fqName, | ||||
| 				help:            desc.help, | ||||
| 				variableLabels:  desc.variableLabels, | ||||
| 				constLabelPairs: desc.constLabelPairs, | ||||
| 				err:             fmt.Errorf("attempted wrapping with already existing label name %q", ln), | ||||
| 			} | ||||
| 		} | ||||
| 		constLabels[ln] = lv | ||||
| 	} | ||||
| 	// NewDesc will do remaining validations. | ||||
| 	newDesc := NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels) | ||||
| 	// Propagate errors if there was any. This will override any errer | ||||
| 	// created by NewDesc above, i.e. earlier errors get precedence. | ||||
| 	if desc.err != nil { | ||||
| 		newDesc.err = desc.err | ||||
| 	} | ||||
| 	return newDesc | ||||
| } | ||||
							
								
								
									
										385
									
								
								vendor/github.com/prometheus/common/expfmt/text_create.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										385
									
								
								vendor/github.com/prometheus/common/expfmt/text_create.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -14,13 +14,45 @@ | ||||
| package expfmt | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/prometheus/common/model" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| 	"github.com/prometheus/common/model" | ||||
| ) | ||||
|  | ||||
| // enhancedWriter has all the enhanced write functions needed here. bytes.Buffer | ||||
| // implements it. | ||||
| type enhancedWriter interface { | ||||
| 	io.Writer | ||||
| 	WriteRune(r rune) (n int, err error) | ||||
| 	WriteString(s string) (n int, err error) | ||||
| 	WriteByte(c byte) error | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	initialBufSize    = 512 | ||||
| 	initialNumBufSize = 24 | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	bufPool = sync.Pool{ | ||||
| 		New: func() interface{} { | ||||
| 			return bytes.NewBuffer(make([]byte, 0, initialBufSize)) | ||||
| 		}, | ||||
| 	} | ||||
| 	numBufPool = sync.Pool{ | ||||
| 		New: func() interface{} { | ||||
| 			b := make([]byte, 0, initialNumBufSize) | ||||
| 			return &b | ||||
| 		}, | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| // MetricFamilyToText converts a MetricFamily proto message into text format and | ||||
| @@ -32,37 +64,92 @@ import ( | ||||
| // will result in invalid text format output. | ||||
| // | ||||
| // This method fulfills the type 'prometheus.encoder'. | ||||
| func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) { | ||||
| 	var written int | ||||
|  | ||||
| func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err error) { | ||||
| 	// Fail-fast checks. | ||||
| 	if len(in.Metric) == 0 { | ||||
| 		return written, fmt.Errorf("MetricFamily has no metrics: %s", in) | ||||
| 		return 0, fmt.Errorf("MetricFamily has no metrics: %s", in) | ||||
| 	} | ||||
| 	name := in.GetName() | ||||
| 	if name == "" { | ||||
| 		return written, fmt.Errorf("MetricFamily has no name: %s", in) | ||||
| 		return 0, fmt.Errorf("MetricFamily has no name: %s", in) | ||||
| 	} | ||||
|  | ||||
| 	// Try the interface upgrade. If it doesn't work, we'll use a | ||||
| 	// bytes.Buffer from the sync.Pool and write out its content to out in a | ||||
| 	// single go in the end. | ||||
| 	w, ok := out.(enhancedWriter) | ||||
| 	if !ok { | ||||
| 		b := bufPool.Get().(*bytes.Buffer) | ||||
| 		b.Reset() | ||||
| 		w = b | ||||
| 		defer func() { | ||||
| 			bWritten, bErr := out.Write(b.Bytes()) | ||||
| 			written = bWritten | ||||
| 			if err == nil { | ||||
| 				err = bErr | ||||
| 			} | ||||
| 			bufPool.Put(b) | ||||
| 		}() | ||||
| 	} | ||||
|  | ||||
| 	var n int | ||||
|  | ||||
| 	// Comments, first HELP, then TYPE. | ||||
| 	if in.Help != nil { | ||||
| 		n, err := fmt.Fprintf( | ||||
| 			out, "# HELP %s %s\n", | ||||
| 			name, escapeString(*in.Help, false), | ||||
| 		) | ||||
| 		n, err = w.WriteString("# HELP ") | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 			return | ||||
| 		} | ||||
| 		n, err = w.WriteString(name) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		err = w.WriteByte(' ') | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		n, err = writeEscapedString(w, *in.Help, false) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		err = w.WriteByte('\n') | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	metricType := in.GetType() | ||||
| 	n, err := fmt.Fprintf( | ||||
| 		out, "# TYPE %s %s\n", | ||||
| 		name, strings.ToLower(metricType.String()), | ||||
| 	) | ||||
| 	n, err = w.WriteString("# TYPE ") | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 		return | ||||
| 	} | ||||
| 	n, err = w.WriteString(name) | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	metricType := in.GetType() | ||||
| 	switch metricType { | ||||
| 	case dto.MetricType_COUNTER: | ||||
| 		n, err = w.WriteString(" counter\n") | ||||
| 	case dto.MetricType_GAUGE: | ||||
| 		n, err = w.WriteString(" gauge\n") | ||||
| 	case dto.MetricType_SUMMARY: | ||||
| 		n, err = w.WriteString(" summary\n") | ||||
| 	case dto.MetricType_UNTYPED: | ||||
| 		n, err = w.WriteString(" untyped\n") | ||||
| 	case dto.MetricType_HISTOGRAM: | ||||
| 		n, err = w.WriteString(" histogram\n") | ||||
| 	default: | ||||
| 		return written, fmt.Errorf("unknown metric type %s", metricType.String()) | ||||
| 	} | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Finally the samples, one line for each. | ||||
| @@ -75,9 +162,8 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) { | ||||
| 				) | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				name, metric, "", "", | ||||
| 				w, name, "", metric, "", 0, | ||||
| 				metric.Counter.GetValue(), | ||||
| 				out, | ||||
| 			) | ||||
| 		case dto.MetricType_GAUGE: | ||||
| 			if metric.Gauge == nil { | ||||
| @@ -86,9 +172,8 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) { | ||||
| 				) | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				name, metric, "", "", | ||||
| 				w, name, "", metric, "", 0, | ||||
| 				metric.Gauge.GetValue(), | ||||
| 				out, | ||||
| 			) | ||||
| 		case dto.MetricType_UNTYPED: | ||||
| 			if metric.Untyped == nil { | ||||
| @@ -97,9 +182,8 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) { | ||||
| 				) | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				name, metric, "", "", | ||||
| 				w, name, "", metric, "", 0, | ||||
| 				metric.Untyped.GetValue(), | ||||
| 				out, | ||||
| 			) | ||||
| 		case dto.MetricType_SUMMARY: | ||||
| 			if metric.Summary == nil { | ||||
| @@ -109,29 +193,26 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) { | ||||
| 			} | ||||
| 			for _, q := range metric.Summary.Quantile { | ||||
| 				n, err = writeSample( | ||||
| 					name, metric, | ||||
| 					model.QuantileLabel, fmt.Sprint(q.GetQuantile()), | ||||
| 					w, name, "", metric, | ||||
| 					model.QuantileLabel, q.GetQuantile(), | ||||
| 					q.GetValue(), | ||||
| 					out, | ||||
| 				) | ||||
| 				written += n | ||||
| 				if err != nil { | ||||
| 					return written, err | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				name+"_sum", metric, "", "", | ||||
| 				w, name, "_sum", metric, "", 0, | ||||
| 				metric.Summary.GetSampleSum(), | ||||
| 				out, | ||||
| 			) | ||||
| 			if err != nil { | ||||
| 				return written, err | ||||
| 			} | ||||
| 			written += n | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				name+"_count", metric, "", "", | ||||
| 				w, name, "_count", metric, "", 0, | ||||
| 				float64(metric.Summary.GetSampleCount()), | ||||
| 				out, | ||||
| 			) | ||||
| 		case dto.MetricType_HISTOGRAM: | ||||
| 			if metric.Histogram == nil { | ||||
| @@ -140,46 +221,42 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) { | ||||
| 				) | ||||
| 			} | ||||
| 			infSeen := false | ||||
| 			for _, q := range metric.Histogram.Bucket { | ||||
| 			for _, b := range metric.Histogram.Bucket { | ||||
| 				n, err = writeSample( | ||||
| 					name+"_bucket", metric, | ||||
| 					model.BucketLabel, fmt.Sprint(q.GetUpperBound()), | ||||
| 					float64(q.GetCumulativeCount()), | ||||
| 					out, | ||||
| 					w, name, "_bucket", metric, | ||||
| 					model.BucketLabel, b.GetUpperBound(), | ||||
| 					float64(b.GetCumulativeCount()), | ||||
| 				) | ||||
| 				written += n | ||||
| 				if err != nil { | ||||
| 					return written, err | ||||
| 					return | ||||
| 				} | ||||
| 				if math.IsInf(q.GetUpperBound(), +1) { | ||||
| 				if math.IsInf(b.GetUpperBound(), +1) { | ||||
| 					infSeen = true | ||||
| 				} | ||||
| 			} | ||||
| 			if !infSeen { | ||||
| 				n, err = writeSample( | ||||
| 					name+"_bucket", metric, | ||||
| 					model.BucketLabel, "+Inf", | ||||
| 					w, name, "_bucket", metric, | ||||
| 					model.BucketLabel, math.Inf(+1), | ||||
| 					float64(metric.Histogram.GetSampleCount()), | ||||
| 					out, | ||||
| 				) | ||||
| 				if err != nil { | ||||
| 					return written, err | ||||
| 				} | ||||
| 				written += n | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				name+"_sum", metric, "", "", | ||||
| 				w, name, "_sum", metric, "", 0, | ||||
| 				metric.Histogram.GetSampleSum(), | ||||
| 				out, | ||||
| 			) | ||||
| 			if err != nil { | ||||
| 				return written, err | ||||
| 			} | ||||
| 			written += n | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				name+"_count", metric, "", "", | ||||
| 				w, name, "_count", metric, "", 0, | ||||
| 				float64(metric.Histogram.GetSampleCount()), | ||||
| 				out, | ||||
| 			) | ||||
| 		default: | ||||
| 			return written, fmt.Errorf( | ||||
| @@ -188,116 +265,204 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) { | ||||
| 		} | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	return written, nil | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // writeSample writes a single sample in text format to out, given the metric | ||||
| // writeSample writes a single sample in text format to w, given the metric | ||||
| // name, the metric proto message itself, optionally an additional label name | ||||
| // and value (use empty strings if not required), and the value. The function | ||||
| // returns the number of bytes written and any error encountered. | ||||
| // with a float64 value (use empty string as label name if not required), and | ||||
| // the value. The function returns the number of bytes written and any error | ||||
| // encountered. | ||||
| func writeSample( | ||||
| 	name string, | ||||
| 	w enhancedWriter, | ||||
| 	name, suffix string, | ||||
| 	metric *dto.Metric, | ||||
| 	additionalLabelName, additionalLabelValue string, | ||||
| 	additionalLabelName string, additionalLabelValue float64, | ||||
| 	value float64, | ||||
| 	out io.Writer, | ||||
| ) (int, error) { | ||||
| 	var written int | ||||
| 	n, err := fmt.Fprint(out, name) | ||||
| 	n, err := w.WriteString(name) | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	n, err = labelPairsToText( | ||||
| 		metric.Label, | ||||
| 		additionalLabelName, additionalLabelValue, | ||||
| 		out, | ||||
| 	) | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	n, err = fmt.Fprintf(out, " %v", value) | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	if metric.TimestampMs != nil { | ||||
| 		n, err = fmt.Fprintf(out, " %v", *metric.TimestampMs) | ||||
| 	if suffix != "" { | ||||
| 		n, err = w.WriteString(suffix) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 	} | ||||
| 	n, err = out.Write([]byte{'\n'}) | ||||
| 	n, err = writeLabelPairs( | ||||
| 		w, metric.Label, additionalLabelName, additionalLabelValue, | ||||
| 	) | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	err = w.WriteByte(' ') | ||||
| 	written++ | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	n, err = writeFloat(w, value) | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	if metric.TimestampMs != nil { | ||||
| 		err = w.WriteByte(' ') | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err = writeInt(w, *metric.TimestampMs) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 	} | ||||
| 	err = w.WriteByte('\n') | ||||
| 	written++ | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	return written, nil | ||||
| } | ||||
|  | ||||
| // labelPairsToText converts a slice of LabelPair proto messages plus the | ||||
| // writeLabelPairs converts a slice of LabelPair proto messages plus the | ||||
| // explicitly given additional label pair into text formatted as required by the | ||||
| // text format and writes it to 'out'. An empty slice in combination with an | ||||
| // empty string 'additionalLabelName' results in nothing being | ||||
| // written. Otherwise, the label pairs are written, escaped as required by the | ||||
| // text format, and enclosed in '{...}'. The function returns the number of | ||||
| // bytes written and any error encountered. | ||||
| func labelPairsToText( | ||||
| // text format and writes it to 'w'. An empty slice in combination with an empty | ||||
| // string 'additionalLabelName' results in nothing being written. Otherwise, the | ||||
| // label pairs are written, escaped as required by the text format, and enclosed | ||||
| // in '{...}'. The function returns the number of bytes written and any error | ||||
| // encountered. | ||||
| func writeLabelPairs( | ||||
| 	w enhancedWriter, | ||||
| 	in []*dto.LabelPair, | ||||
| 	additionalLabelName, additionalLabelValue string, | ||||
| 	out io.Writer, | ||||
| 	additionalLabelName string, additionalLabelValue float64, | ||||
| ) (int, error) { | ||||
| 	if len(in) == 0 && additionalLabelName == "" { | ||||
| 		return 0, nil | ||||
| 	} | ||||
| 	var written int | ||||
| 	separator := '{' | ||||
| 	var ( | ||||
| 		written   int | ||||
| 		separator byte = '{' | ||||
| 	) | ||||
| 	for _, lp := range in { | ||||
| 		n, err := fmt.Fprintf( | ||||
| 			out, `%c%s="%s"`, | ||||
| 			separator, lp.GetName(), escapeString(lp.GetValue(), true), | ||||
| 		) | ||||
| 		err := w.WriteByte(separator) | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err := w.WriteString(lp.GetName()) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err = w.WriteString(`="`) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err = writeEscapedString(w, lp.GetValue(), true) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		err = w.WriteByte('"') | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		separator = ',' | ||||
| 	} | ||||
| 	if additionalLabelName != "" { | ||||
| 		n, err := fmt.Fprintf( | ||||
| 			out, `%c%s="%s"`, | ||||
| 			separator, additionalLabelName, | ||||
| 			escapeString(additionalLabelValue, true), | ||||
| 		) | ||||
| 		err := w.WriteByte(separator) | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err := w.WriteString(additionalLabelName) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err = w.WriteString(`="`) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err = writeFloat(w, additionalLabelValue) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		err = w.WriteByte('"') | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 	} | ||||
| 	n, err := out.Write([]byte{'}'}) | ||||
| 	written += n | ||||
| 	err := w.WriteByte('}') | ||||
| 	written++ | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	return written, nil | ||||
| } | ||||
|  | ||||
| // writeEscapedString replaces '\' by '\\', new line character by '\n', and - if | ||||
| // includeDoubleQuote is true - '"' by '\"'. | ||||
| var ( | ||||
| 	escape                = strings.NewReplacer("\\", `\\`, "\n", `\n`) | ||||
| 	escapeWithDoubleQuote = strings.NewReplacer("\\", `\\`, "\n", `\n`, "\"", `\"`) | ||||
| 	escaper       = strings.NewReplacer("\\", `\\`, "\n", `\n`) | ||||
| 	quotedEscaper = strings.NewReplacer("\\", `\\`, "\n", `\n`, "\"", `\"`) | ||||
| ) | ||||
|  | ||||
| // escapeString replaces '\' by '\\', new line character by '\n', and - if | ||||
| // includeDoubleQuote is true - '"' by '\"'. | ||||
| func escapeString(v string, includeDoubleQuote bool) string { | ||||
| func writeEscapedString(w enhancedWriter, v string, includeDoubleQuote bool) (int, error) { | ||||
| 	if includeDoubleQuote { | ||||
| 		return escapeWithDoubleQuote.Replace(v) | ||||
| 		return quotedEscaper.WriteString(w, v) | ||||
| 	} else { | ||||
| 		return escaper.WriteString(w, v) | ||||
| 	} | ||||
|  | ||||
| 	return escape.Replace(v) | ||||
| } | ||||
|  | ||||
| // writeFloat is equivalent to fmt.Fprint with a float64 argument but hardcodes | ||||
| // a few common cases for increased efficiency. For non-hardcoded cases, it uses | ||||
| // strconv.AppendFloat to avoid allocations, similar to writeInt. | ||||
| func writeFloat(w enhancedWriter, f float64) (int, error) { | ||||
| 	switch { | ||||
| 	case f == 1: | ||||
| 		return 1, w.WriteByte('1') | ||||
| 	case f == 0: | ||||
| 		return 1, w.WriteByte('0') | ||||
| 	case f == -1: | ||||
| 		return w.WriteString("-1") | ||||
| 	case math.IsNaN(f): | ||||
| 		return w.WriteString("NaN") | ||||
| 	case math.IsInf(f, +1): | ||||
| 		return w.WriteString("+Inf") | ||||
| 	case math.IsInf(f, -1): | ||||
| 		return w.WriteString("-Inf") | ||||
| 	default: | ||||
| 		bp := numBufPool.Get().(*[]byte) | ||||
| 		*bp = strconv.AppendFloat((*bp)[:0], f, 'g', -1, 64) | ||||
| 		written, err := w.Write(*bp) | ||||
| 		numBufPool.Put(bp) | ||||
| 		return written, err | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // writeInt is equivalent to fmt.Fprint with an int64 argument but uses | ||||
| // strconv.AppendInt with a byte slice taken from a sync.Pool to avoid | ||||
| // allocations. | ||||
| func writeInt(w enhancedWriter, i int64) (int, error) { | ||||
| 	bp := numBufPool.Get().(*[]byte) | ||||
| 	*bp = strconv.AppendInt((*bp)[:0], i, 10) | ||||
| 	written, err := w.Write(*bp) | ||||
| 	numBufPool.Put(bp) | ||||
| 	return written, err | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/prometheus/common/expfmt/text_parse.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/prometheus/common/expfmt/text_parse.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -359,7 +359,7 @@ func (p *TextParser) startLabelValue() stateFn { | ||||
| 		} | ||||
| 		return p.readingValue | ||||
| 	default: | ||||
| 		p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.Value)) | ||||
| 		p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.GetValue())) | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										6
									
								
								vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,12 +1,12 @@ | ||||
| /* | ||||
| Copyright (c) 2011, Open Knowledge Foundation Ltd. | ||||
| All rights reserved. | ||||
|  | ||||
| HTTP Content-Type Autonegotiation. | ||||
|  | ||||
| The functions in this package implement the behaviour specified in | ||||
| http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html | ||||
|  | ||||
| Copyright (c) 2011, Open Knowledge Foundation Ltd. | ||||
| All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|   | ||||
							
								
								
									
										1
									
								
								vendor/github.com/prometheus/common/model/metric.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/prometheus/common/model/metric.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -21,7 +21,6 @@ import ( | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	separator = []byte{0} | ||||
| 	// MetricNameRE is a regular expression matching valid metric | ||||
| 	// names. Note that the IsValidMetricName function performs the same | ||||
| 	// check but faster than a match with this regular expression. | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/prometheus/common/model/time.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/prometheus/common/model/time.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -43,7 +43,7 @@ const ( | ||||
| // (1970-01-01 00:00 UTC) excluding leap seconds. | ||||
| type Time int64 | ||||
|  | ||||
| // Interval describes and interval between two timestamps. | ||||
| // Interval describes an interval between two timestamps. | ||||
| type Interval struct { | ||||
| 	Start, End Time | ||||
| } | ||||
|   | ||||
							
								
								
									
										5
									
								
								vendor/github.com/spf13/cobra/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/spf13/cobra/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -32,5 +32,8 @@ Session.vim | ||||
| tags | ||||
|  | ||||
| *.exe | ||||
|  | ||||
| cobra.test | ||||
| bin | ||||
|  | ||||
| .idea/ | ||||
| *.iml | ||||
|   | ||||
							
								
								
									
										42
									
								
								vendor/github.com/spf13/cobra/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/spf13/cobra/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,21 +1,29 @@ | ||||
| language: go | ||||
|  | ||||
| matrix: | ||||
|   include: | ||||
|     - go: 1.9.4 | ||||
|     - go: 1.10.0 | ||||
|     - go: tip | ||||
|   allow_failures: | ||||
|     - go: tip | ||||
| stages: | ||||
|   - diff | ||||
|   - test | ||||
|   - build | ||||
|  | ||||
| go: | ||||
|   - 1.12.x | ||||
|   - 1.13.x | ||||
|   - tip | ||||
|  | ||||
| before_install: | ||||
|   - mkdir -p bin | ||||
|   - curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck | ||||
|   - chmod +x bin/shellcheck | ||||
| script: | ||||
|   - PATH=$PATH:$PWD/bin go test -v ./... | ||||
|   - go build | ||||
|   - diff -u <(echo -n) <(gofmt -d -s .) | ||||
|   - if [ -z $NOVET ]; then | ||||
|       diff -u <(echo -n) <(go tool vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); | ||||
|     fi | ||||
|   - go get -u github.com/kyoh86/richgo | ||||
|   - go get -u github.com/mitchellh/gox | ||||
|  | ||||
| matrix: | ||||
|   allow_failures: | ||||
|     - go: tip | ||||
|   include: | ||||
|     - stage: diff | ||||
|       go: 1.13.x | ||||
|       script: make fmt | ||||
|     - stage: build | ||||
|       go: 1.13.x | ||||
|       script: make cobra_generator | ||||
|  | ||||
| script:  | ||||
|  - make test | ||||
|   | ||||
							
								
								
									
										36
									
								
								vendor/github.com/spf13/cobra/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								vendor/github.com/spf13/cobra/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| BIN="./bin" | ||||
| SRC=$(shell find . -name "*.go") | ||||
|  | ||||
| ifeq (, $(shell which richgo)) | ||||
| $(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo") | ||||
| endif | ||||
|  | ||||
| .PHONY: fmt vet test cobra_generator install_deps clean | ||||
|  | ||||
| default: all | ||||
|  | ||||
| all: fmt vet test cobra_generator	 | ||||
|  | ||||
| fmt: | ||||
| 	$(info ******************** checking formatting ********************) | ||||
| 	@test -z $(shell gofmt -l $(SRC)) || (gofmt -d $(SRC); exit 1) | ||||
|  | ||||
| test: install_deps vet | ||||
| 	$(info ******************** running tests ********************) | ||||
| 	richgo test -v ./... | ||||
|  | ||||
| cobra_generator: install_deps | ||||
| 	$(info ******************** building generator ********************) | ||||
| 	mkdir -p $(BIN) | ||||
| 	make -C cobra all | ||||
|  | ||||
| install_deps: | ||||
| 	$(info ******************** downloading dependencies ********************) | ||||
| 	go get -v ./... | ||||
|  | ||||
| vet: | ||||
| 	$(info ******************** vetting ********************) | ||||
| 	go vet ./... | ||||
|  | ||||
| clean: | ||||
| 	rm -rf $(BIN) | ||||
							
								
								
									
										166
									
								
								vendor/github.com/spf13/cobra/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										166
									
								
								vendor/github.com/spf13/cobra/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,29 +2,35 @@ | ||||
|  | ||||
| Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. | ||||
|  | ||||
| Many of the most widely used Go projects are built using Cobra including: | ||||
|  | ||||
| * [Kubernetes](http://kubernetes.io/) | ||||
| * [Hugo](http://gohugo.io) | ||||
| * [rkt](https://github.com/coreos/rkt) | ||||
| * [etcd](https://github.com/coreos/etcd) | ||||
| * [Moby (former Docker)](https://github.com/moby/moby) | ||||
| * [Docker (distribution)](https://github.com/docker/distribution) | ||||
| * [OpenShift](https://www.openshift.com/) | ||||
| * [Delve](https://github.com/derekparker/delve) | ||||
| * [GopherJS](http://www.gopherjs.org/) | ||||
| * [CockroachDB](http://www.cockroachlabs.com/) | ||||
| * [Bleve](http://www.blevesearch.com/) | ||||
| * [ProjectAtomic (enterprise)](http://www.projectatomic.io/) | ||||
| * [GiantSwarm's swarm](https://github.com/giantswarm/cli) | ||||
| * [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) | ||||
| * [rclone](http://rclone.org/) | ||||
| * [nehm](https://github.com/bogem/nehm) | ||||
| * [Pouch](https://github.com/alibaba/pouch) | ||||
| Many of the most widely used Go projects are built using Cobra, such as: | ||||
| [Kubernetes](http://kubernetes.io/), | ||||
| [Hugo](http://gohugo.io), | ||||
| [rkt](https://github.com/coreos/rkt), | ||||
| [etcd](https://github.com/coreos/etcd), | ||||
| [Moby (former Docker)](https://github.com/moby/moby), | ||||
| [Docker (distribution)](https://github.com/docker/distribution), | ||||
| [OpenShift](https://www.openshift.com/), | ||||
| [Delve](https://github.com/derekparker/delve), | ||||
| [GopherJS](http://www.gopherjs.org/), | ||||
| [CockroachDB](http://www.cockroachlabs.com/), | ||||
| [Bleve](http://www.blevesearch.com/), | ||||
| [ProjectAtomic (enterprise)](http://www.projectatomic.io/), | ||||
| [Giant Swarm's gsctl](https://github.com/giantswarm/gsctl), | ||||
| [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack), | ||||
| [rclone](http://rclone.org/), | ||||
| [nehm](https://github.com/bogem/nehm), | ||||
| [Pouch](https://github.com/alibaba/pouch), | ||||
| [Istio](https://istio.io), | ||||
| [Prototool](https://github.com/uber/prototool), | ||||
| [mattermost-server](https://github.com/mattermost/mattermost-server), | ||||
| [Gardener](https://github.com/gardener/gardenctl), | ||||
| [Linkerd](https://linkerd.io/), | ||||
| [Github CLI](https://github.com/cli/cli) | ||||
| etc. | ||||
|  | ||||
| [](https://travis-ci.org/spf13/cobra) | ||||
| [](https://circleci.com/gh/spf13/cobra) | ||||
| [](https://godoc.org/github.com/spf13/cobra) | ||||
| [](https://goreportcard.com/report/github.com/spf13/cobra) | ||||
|  | ||||
| # Table of Contents | ||||
|  | ||||
| @@ -45,6 +51,7 @@ Many of the most widely used Go projects are built using Cobra including: | ||||
|   * [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens) | ||||
|   * [Generating documentation for your command](#generating-documentation-for-your-command) | ||||
|   * [Generating bash completions](#generating-bash-completions) | ||||
|   * [Generating zsh completions](#generating-zsh-completions) | ||||
| - [Contributing](#contributing) | ||||
| - [License](#license) | ||||
|  | ||||
| @@ -152,9 +159,6 @@ In a Cobra app, typically the main.go file is very bare. It serves one purpose: | ||||
| package main | ||||
|  | ||||
| import ( | ||||
|   "fmt" | ||||
|   "os" | ||||
|  | ||||
|   "{pathToYourApp}/cmd" | ||||
| ) | ||||
|  | ||||
| @@ -206,51 +210,78 @@ You will additionally define flags and handle configuration in your init() funct | ||||
| For example cmd/root.go: | ||||
|  | ||||
| ```go | ||||
| import ( | ||||
|   "fmt" | ||||
|   "os" | ||||
| package cmd | ||||
|  | ||||
|   homedir "github.com/mitchellh/go-homedir" | ||||
|   "github.com/spf13/cobra" | ||||
|   "github.com/spf13/viper" | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
|  | ||||
| 	homedir "github.com/mitchellh/go-homedir" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// Used for flags. | ||||
| 	cfgFile     string | ||||
| 	userLicense string | ||||
|  | ||||
| 	rootCmd = &cobra.Command{ | ||||
| 		Use:   "cobra", | ||||
| 		Short: "A generator for Cobra based Applications", | ||||
| 		Long: `Cobra is a CLI library for Go that empowers applications. | ||||
| This application is a tool to generate the needed files | ||||
| to quickly create a Cobra application.`, | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| // Execute executes the root command. | ||||
| func Execute() error { | ||||
| 	return rootCmd.Execute() | ||||
| } | ||||
|  | ||||
| func init() { | ||||
|   cobra.OnInitialize(initConfig) | ||||
|   rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") | ||||
|   rootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") | ||||
|   rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") | ||||
|   rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") | ||||
|   rootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") | ||||
|   viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) | ||||
|   viper.BindPFlag("projectbase", rootCmd.PersistentFlags().Lookup("projectbase")) | ||||
|   viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) | ||||
|   viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>") | ||||
|   viper.SetDefault("license", "apache") | ||||
| 	cobra.OnInitialize(initConfig) | ||||
|  | ||||
| 	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") | ||||
| 	rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") | ||||
| 	rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") | ||||
| 	rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") | ||||
| 	viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) | ||||
| 	viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) | ||||
| 	viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>") | ||||
| 	viper.SetDefault("license", "apache") | ||||
|  | ||||
| 	rootCmd.AddCommand(addCmd) | ||||
| 	rootCmd.AddCommand(initCmd) | ||||
| } | ||||
|  | ||||
| func er(msg interface{}) { | ||||
| 	fmt.Println("Error:", msg) | ||||
| 	os.Exit(1) | ||||
| } | ||||
|  | ||||
| func initConfig() { | ||||
|   // Don't forget to read config either from cfgFile or from home directory! | ||||
|   if cfgFile != "" { | ||||
|     // Use config file from the flag. | ||||
|     viper.SetConfigFile(cfgFile) | ||||
|   } else { | ||||
|     // Find home directory. | ||||
|     home, err := homedir.Dir() | ||||
|     if err != nil { | ||||
|       fmt.Println(err) | ||||
|       os.Exit(1) | ||||
|     } | ||||
| 	if cfgFile != "" { | ||||
| 		// Use config file from the flag. | ||||
| 		viper.SetConfigFile(cfgFile) | ||||
| 	} else { | ||||
| 		// Find home directory. | ||||
| 		home, err := homedir.Dir() | ||||
| 		if err != nil { | ||||
| 			er(err) | ||||
| 		} | ||||
|  | ||||
|     // Search config in home directory with name ".cobra" (without extension). | ||||
|     viper.AddConfigPath(home) | ||||
|     viper.SetConfigName(".cobra") | ||||
|   } | ||||
| 		// Search config in home directory with name ".cobra" (without extension). | ||||
| 		viper.AddConfigPath(home) | ||||
| 		viper.SetConfigName(".cobra") | ||||
| 	} | ||||
|  | ||||
|   if err := viper.ReadInConfig(); err != nil { | ||||
|     fmt.Println("Can't read config:", err) | ||||
|     os.Exit(1) | ||||
|   } | ||||
| 	viper.AutomaticEnv() | ||||
|  | ||||
| 	if err := viper.ReadInConfig(); err == nil { | ||||
| 		fmt.Println("Using config file:", viper.ConfigFileUsed()) | ||||
| 	} | ||||
| } | ||||
| ``` | ||||
|  | ||||
| @@ -265,9 +296,6 @@ In a Cobra app, typically the main.go file is very bare. It serves, one purpose, | ||||
| package main | ||||
|  | ||||
| import ( | ||||
|   "fmt" | ||||
|   "os" | ||||
|  | ||||
|   "{pathToYourApp}/cmd" | ||||
| ) | ||||
|  | ||||
| @@ -339,7 +367,7 @@ rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose out | ||||
| A flag can also be assigned locally which will only apply to that specific command. | ||||
|  | ||||
| ```go | ||||
| rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") | ||||
| localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") | ||||
| ``` | ||||
|  | ||||
| ### Local Flag on Parent Commands | ||||
| @@ -395,6 +423,7 @@ The following validators are built in: | ||||
| - `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args. | ||||
| - `MaximumNArgs(int)` - the command will report an error if there are more than N positional args. | ||||
| - `ExactArgs(int)` - the command will report an error if there are not exactly N positional args. | ||||
| - `ExactValidArgs(int)` - the command will report an error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command` | ||||
| - `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args. | ||||
|  | ||||
| An example of setting the custom validator: | ||||
| @@ -404,7 +433,7 @@ var cmd = &cobra.Command{ | ||||
|   Short: "hello", | ||||
|   Args: func(cmd *cobra.Command, args []string) error { | ||||
|     if len(args) < 1 { | ||||
|       return errors.New("requires at least one arg") | ||||
|       return errors.New("requires a color argument") | ||||
|     } | ||||
|     if myapp.IsValidColor(args[0]) { | ||||
|       return nil | ||||
| @@ -459,12 +488,12 @@ For many years people have printed back to the screen.`, | ||||
| Echo works a lot like print, except it has a child command.`, | ||||
|     Args: cobra.MinimumNArgs(1), | ||||
|     Run: func(cmd *cobra.Command, args []string) { | ||||
|       fmt.Println("Print: " + strings.Join(args, " ")) | ||||
|       fmt.Println("Echo: " + strings.Join(args, " ")) | ||||
|     }, | ||||
|   } | ||||
|  | ||||
|   var cmdTimes = &cobra.Command{ | ||||
|     Use:   "times [# times] [string to echo]", | ||||
|     Use:   "times [string to echo]", | ||||
|     Short: "Echo anything to the screen more times", | ||||
|     Long: `echo things multiple times back to the user by providing | ||||
| a count and a string.`, | ||||
| @@ -721,6 +750,11 @@ Cobra can generate documentation based on subcommands, flags, etc. in the follow | ||||
|  | ||||
| Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible.  Read more about it in [Bash Completions](bash_completions.md). | ||||
|  | ||||
| ## Generating zsh completions | ||||
|  | ||||
| Cobra can generate zsh-completion file. Read more about it in | ||||
| [Zsh Completions](zsh_completions.md). | ||||
|  | ||||
| # Contributing | ||||
|  | ||||
| 1. Fork it | ||||
|   | ||||
							
								
								
									
										22
									
								
								vendor/github.com/spf13/cobra/args.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/spf13/cobra/args.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,6 +2,7 @@ package cobra | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| type PositionalArgs func(cmd *Command, args []string) error | ||||
| @@ -34,8 +35,15 @@ func NoArgs(cmd *Command, args []string) error { | ||||
| // OnlyValidArgs returns an error if any args are not in the list of ValidArgs. | ||||
| func OnlyValidArgs(cmd *Command, args []string) error { | ||||
| 	if len(cmd.ValidArgs) > 0 { | ||||
| 		// Remove any description that may be included in ValidArgs. | ||||
| 		// A description is following a tab character. | ||||
| 		var validArgs []string | ||||
| 		for _, v := range cmd.ValidArgs { | ||||
| 			validArgs = append(validArgs, strings.Split(v, "\t")[0]) | ||||
| 		} | ||||
|  | ||||
| 		for _, v := range args { | ||||
| 			if !stringInSlice(v, cmd.ValidArgs) { | ||||
| 			if !stringInSlice(v, validArgs) { | ||||
| 				return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0])) | ||||
| 			} | ||||
| 		} | ||||
| @@ -78,6 +86,18 @@ func ExactArgs(n int) PositionalArgs { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ExactValidArgs returns an error if | ||||
| // there are not exactly N positional args OR | ||||
| // there are any positional args that are not in the `ValidArgs` field of `Command` | ||||
| func ExactValidArgs(n int) PositionalArgs { | ||||
| 	return func(cmd *Command, args []string) error { | ||||
| 		if err := ExactArgs(n)(cmd, args); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return OnlyValidArgs(cmd, args) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // RangeArgs returns an error if the number of args is not within the expected range. | ||||
| func RangeArgs(min int, max int) PositionalArgs { | ||||
| 	return func(cmd *Command, args []string) error { | ||||
|   | ||||
							
								
								
									
										167
									
								
								vendor/github.com/spf13/cobra/bash_completions.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										167
									
								
								vendor/github.com/spf13/cobra/bash_completions.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -58,9 +58,71 @@ __%[1]s_contains_word() | ||||
|     return 1 | ||||
| } | ||||
|  | ||||
| __%[1]s_handle_go_custom_completion() | ||||
| { | ||||
|     __%[1]s_debug "${FUNCNAME[0]}: cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}" | ||||
|  | ||||
|     local out requestComp lastParam lastChar comp directive args | ||||
|  | ||||
|     # Prepare the command to request completions for the program. | ||||
|     # Calling ${words[0]} instead of directly %[1]s allows to handle aliases | ||||
|     args=("${words[@]:1}") | ||||
|     requestComp="${words[0]} %[2]s ${args[*]}" | ||||
|  | ||||
|     lastParam=${words[$((${#words[@]}-1))]} | ||||
|     lastChar=${lastParam:$((${#lastParam}-1)):1} | ||||
|     __%[1]s_debug "${FUNCNAME[0]}: lastParam ${lastParam}, lastChar ${lastChar}" | ||||
|  | ||||
|     if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then | ||||
|         # If the last parameter is complete (there is a space following it) | ||||
|         # We add an extra empty parameter so we can indicate this to the go method. | ||||
|         __%[1]s_debug "${FUNCNAME[0]}: Adding extra empty parameter" | ||||
|         requestComp="${requestComp} \"\"" | ||||
|     fi | ||||
|  | ||||
|     __%[1]s_debug "${FUNCNAME[0]}: calling ${requestComp}" | ||||
|     # Use eval to handle any environment variables and such | ||||
|     out=$(eval "${requestComp}" 2>/dev/null) | ||||
|  | ||||
|     # Extract the directive integer at the very end of the output following a colon (:) | ||||
|     directive=${out##*:} | ||||
|     # Remove the directive | ||||
|     out=${out%%:*} | ||||
|     if [ "${directive}" = "${out}" ]; then | ||||
|         # There is not directive specified | ||||
|         directive=0 | ||||
|     fi | ||||
|     __%[1]s_debug "${FUNCNAME[0]}: the completion directive is: ${directive}" | ||||
|     __%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out[*]}" | ||||
|  | ||||
|     if [ $((directive & %[3]d)) -ne 0 ]; then | ||||
|         # Error code.  No completion. | ||||
|         __%[1]s_debug "${FUNCNAME[0]}: received error from custom completion go code" | ||||
|         return | ||||
|     else | ||||
|         if [ $((directive & %[4]d)) -ne 0 ]; then | ||||
|             if [[ $(type -t compopt) = "builtin" ]]; then | ||||
|                 __%[1]s_debug "${FUNCNAME[0]}: activating no space" | ||||
|                 compopt -o nospace | ||||
|             fi | ||||
|         fi | ||||
|         if [ $((directive & %[5]d)) -ne 0 ]; then | ||||
|             if [[ $(type -t compopt) = "builtin" ]]; then | ||||
|                 __%[1]s_debug "${FUNCNAME[0]}: activating no file completion" | ||||
|                 compopt +o default | ||||
|             fi | ||||
|         fi | ||||
|  | ||||
|         while IFS='' read -r comp; do | ||||
|             COMPREPLY+=("$comp") | ||||
|         done < <(compgen -W "${out[*]}" -- "$cur") | ||||
|     fi | ||||
| } | ||||
|  | ||||
| __%[1]s_handle_reply() | ||||
| { | ||||
|     __%[1]s_debug "${FUNCNAME[0]}" | ||||
|     local comp | ||||
|     case $cur in | ||||
|         -*) | ||||
|             if [[ $(type -t compopt) = "builtin" ]]; then | ||||
| @@ -72,7 +134,9 @@ __%[1]s_handle_reply() | ||||
|             else | ||||
|                 allflags=("${flags[*]} ${two_word_flags[*]}") | ||||
|             fi | ||||
|             COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) | ||||
|             while IFS='' read -r comp; do | ||||
|                 COMPREPLY+=("$comp") | ||||
|             done < <(compgen -W "${allflags[*]}" -- "$cur") | ||||
|             if [[ $(type -t compopt) = "builtin" ]]; then | ||||
|                 [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace | ||||
|             fi | ||||
| @@ -118,18 +182,32 @@ __%[1]s_handle_reply() | ||||
|     completions=("${commands[@]}") | ||||
|     if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then | ||||
|         completions=("${must_have_one_noun[@]}") | ||||
|     elif [[ -n "${has_completion_function}" ]]; then | ||||
|         # if a go completion function is provided, defer to that function | ||||
|         completions=() | ||||
|         __%[1]s_handle_go_custom_completion | ||||
|     fi | ||||
|     if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then | ||||
|         completions+=("${must_have_one_flag[@]}") | ||||
|     fi | ||||
|     COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) | ||||
|     while IFS='' read -r comp; do | ||||
|         COMPREPLY+=("$comp") | ||||
|     done < <(compgen -W "${completions[*]}" -- "$cur") | ||||
|  | ||||
|     if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then | ||||
|         COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) | ||||
|         while IFS='' read -r comp; do | ||||
|             COMPREPLY+=("$comp") | ||||
|         done < <(compgen -W "${noun_aliases[*]}" -- "$cur") | ||||
|     fi | ||||
|  | ||||
|     if [[ ${#COMPREPLY[@]} -eq 0 ]]; then | ||||
|         declare -F __custom_func >/dev/null && __custom_func | ||||
| 		if declare -F __%[1]s_custom_func >/dev/null; then | ||||
| 			# try command name qualified custom func | ||||
| 			__%[1]s_custom_func | ||||
| 		else | ||||
| 			# otherwise fall back to unqualified for compatibility | ||||
| 			declare -F __custom_func >/dev/null && __custom_func | ||||
| 		fi | ||||
|     fi | ||||
|  | ||||
|     # available in bash-completion >= 2, not always present on macOS | ||||
| @@ -154,7 +232,7 @@ __%[1]s_handle_filename_extension_flag() | ||||
| __%[1]s_handle_subdirs_in_dir_flag() | ||||
| { | ||||
|     local dir="$1" | ||||
|     pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 | ||||
|     pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return | ||||
| } | ||||
|  | ||||
| __%[1]s_handle_flag() | ||||
| @@ -193,7 +271,8 @@ __%[1]s_handle_flag() | ||||
|     fi | ||||
|  | ||||
|     # skip the argument to a two word flag | ||||
|     if __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then | ||||
|     if [[ ${words[c]} != *"="* ]] && __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then | ||||
| 			  __%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument" | ||||
|         c=$((c+1)) | ||||
|         # if we are looking for a flags value, don't show commands | ||||
|         if [[ $c -eq $cword ]]; then | ||||
| @@ -265,7 +344,7 @@ __%[1]s_handle_word() | ||||
|     __%[1]s_handle_word | ||||
| } | ||||
|  | ||||
| `, name)) | ||||
| `, name, ShellCompNoDescRequestCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp)) | ||||
| } | ||||
|  | ||||
| func writePostscript(buf *bytes.Buffer, name string) { | ||||
| @@ -290,6 +369,7 @@ func writePostscript(buf *bytes.Buffer, name string) { | ||||
|     local commands=("%[1]s") | ||||
|     local must_have_one_flag=() | ||||
|     local must_have_one_noun=() | ||||
|     local has_completion_function | ||||
|     local last_command | ||||
|     local nouns=() | ||||
|  | ||||
| @@ -373,6 +453,10 @@ func writeFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) { | ||||
| 	} | ||||
| 	format += "\")\n" | ||||
| 	buf.WriteString(fmt.Sprintf(format, name)) | ||||
| 	if len(flag.NoOptDefVal) == 0 { | ||||
| 		format = "    two_word_flags+=(\"--%s\")\n" | ||||
| 		buf.WriteString(fmt.Sprintf(format, name)) | ||||
| 	} | ||||
| 	writeFlagHandler(buf, "--"+name, flag.Annotations, cmd) | ||||
| } | ||||
|  | ||||
| @@ -386,7 +470,22 @@ func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) { | ||||
| 	buf.WriteString(fmt.Sprintf(format, name)) | ||||
| } | ||||
|  | ||||
| // Setup annotations for go completions for registered flags | ||||
| func prepareCustomAnnotationsForFlags(cmd *Command) { | ||||
| 	for flag := range flagCompletionFunctions { | ||||
| 		// Make sure the completion script calls the __*_go_custom_completion function for | ||||
| 		// every registered flag.  We need to do this here (and not when the flag was registered | ||||
| 		// for completion) so that we can know the root command name for the prefix | ||||
| 		// of __<prefix>_go_custom_completion | ||||
| 		if flag.Annotations == nil { | ||||
| 			flag.Annotations = map[string][]string{} | ||||
| 		} | ||||
| 		flag.Annotations[BashCompCustom] = []string{fmt.Sprintf("__%[1]s_handle_go_custom_completion", cmd.Root().Name())} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func writeFlags(buf *bytes.Buffer, cmd *Command) { | ||||
| 	prepareCustomAnnotationsForFlags(cmd) | ||||
| 	buf.WriteString(`    flags=() | ||||
|     two_word_flags=() | ||||
|     local_nonpersistent_flags=() | ||||
| @@ -449,8 +548,14 @@ func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) { | ||||
| 	buf.WriteString("    must_have_one_noun=()\n") | ||||
| 	sort.Sort(sort.StringSlice(cmd.ValidArgs)) | ||||
| 	for _, value := range cmd.ValidArgs { | ||||
| 		// Remove any description that may be included following a tab character. | ||||
| 		// Descriptions are not supported by bash completion. | ||||
| 		value = strings.Split(value, "\t")[0] | ||||
| 		buf.WriteString(fmt.Sprintf("    must_have_one_noun+=(%q)\n", value)) | ||||
| 	} | ||||
| 	if cmd.ValidArgsFunction != nil { | ||||
| 		buf.WriteString("    has_completion_function=1\n") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func writeCmdAliases(buf *bytes.Buffer, cmd *Command) { | ||||
| @@ -534,51 +639,3 @@ func (c *Command) GenBashCompletionFile(filename string) error { | ||||
|  | ||||
| 	return c.GenBashCompletion(outFile) | ||||
| } | ||||
|  | ||||
| // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists, | ||||
| // and causes your command to report an error if invoked without the flag. | ||||
| func (c *Command) MarkFlagRequired(name string) error { | ||||
| 	return MarkFlagRequired(c.Flags(), name) | ||||
| } | ||||
|  | ||||
| // MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists, | ||||
| // and causes your command to report an error if invoked without the flag. | ||||
| func (c *Command) MarkPersistentFlagRequired(name string) error { | ||||
| 	return MarkFlagRequired(c.PersistentFlags(), name) | ||||
| } | ||||
|  | ||||
| // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists, | ||||
| // and causes your command to report an error if invoked without the flag. | ||||
| func MarkFlagRequired(flags *pflag.FlagSet, name string) error { | ||||
| 	return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) | ||||
| } | ||||
|  | ||||
| // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. | ||||
| // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. | ||||
| func (c *Command) MarkFlagFilename(name string, extensions ...string) error { | ||||
| 	return MarkFlagFilename(c.Flags(), name, extensions...) | ||||
| } | ||||
|  | ||||
| // MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. | ||||
| // Generated bash autocompletion will call the bash function f for the flag. | ||||
| func (c *Command) MarkFlagCustom(name string, f string) error { | ||||
| 	return MarkFlagCustom(c.Flags(), name, f) | ||||
| } | ||||
|  | ||||
| // MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists. | ||||
| // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. | ||||
| func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { | ||||
| 	return MarkFlagFilename(c.PersistentFlags(), name, extensions...) | ||||
| } | ||||
|  | ||||
| // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists. | ||||
| // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. | ||||
| func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error { | ||||
| 	return flags.SetAnnotation(name, BashCompFilenameExt, extensions) | ||||
| } | ||||
|  | ||||
| // MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists. | ||||
| // Generated bash autocompletion will call the bash function f for the flag. | ||||
| func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error { | ||||
| 	return flags.SetAnnotation(name, BashCompCustom, []string{f}) | ||||
| } | ||||
|   | ||||
							
								
								
									
										278
									
								
								vendor/github.com/spf13/cobra/bash_completions.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										278
									
								
								vendor/github.com/spf13/cobra/bash_completions.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,5 +1,40 @@ | ||||
| # Generating Bash Completions For Your Own cobra.Command | ||||
|  | ||||
| If you are using the generator you can create a completion command by running | ||||
|  | ||||
| ```bash | ||||
| cobra add completion | ||||
| ``` | ||||
|  | ||||
| Update the help text show how to install the bash_completion Linux show here [Kubectl docs show mac options](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion) | ||||
|  | ||||
| Writing the shell script to stdout allows the most flexible use. | ||||
|  | ||||
| ```go | ||||
| // completionCmd represents the completion command | ||||
| var completionCmd = &cobra.Command{ | ||||
| 	Use:   "completion", | ||||
| 	Short: "Generates bash completion scripts", | ||||
| 	Long: `To load completion run | ||||
|  | ||||
| . <(bitbucket completion) | ||||
|  | ||||
| To configure your bash shell to load completions for each session add to your bashrc | ||||
|  | ||||
| # ~/.bashrc or ~/.profile | ||||
| . <(bitbucket completion) | ||||
| `, | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		rootCmd.GenBashCompletion(os.Stdout); | ||||
| 	}, | ||||
| } | ||||
| ``` | ||||
|  | ||||
| **Note:** The cobra generator may include messages printed to stdout for example if the config file is loaded, this will break the auto complete script | ||||
|  | ||||
|  | ||||
| ## Example from kubectl | ||||
|  | ||||
| Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows: | ||||
|  | ||||
| ```go | ||||
| @@ -21,7 +56,149 @@ func main() { | ||||
|  | ||||
| `out.sh` will get you completions of subcommands and flags. Copy it to `/etc/bash_completion.d/` as described [here](https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1) and reset your terminal to use autocompletion. If you make additional annotations to your code, you can get even more intelligent and flexible behavior. | ||||
|  | ||||
| ## Creating your own custom functions | ||||
| ## Have the completions code complete your 'nouns' | ||||
|  | ||||
| ### Static completion of nouns | ||||
|  | ||||
| This method allows you to provide a pre-defined list of completion choices for your nouns using the `validArgs` field. | ||||
| For example, if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like: | ||||
|  | ||||
| ```go | ||||
| validArgs []string = { "pod", "node", "service", "replicationcontroller" } | ||||
|  | ||||
| cmd := &cobra.Command{ | ||||
| 	Use:     "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", | ||||
| 	Short:   "Display one or many resources", | ||||
| 	Long:    get_long, | ||||
| 	Example: get_example, | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		err := RunGet(f, out, cmd, args) | ||||
| 		util.CheckErr(err) | ||||
| 	}, | ||||
| 	ValidArgs: validArgs, | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like | ||||
|  | ||||
| ```bash | ||||
| # kubectl get [tab][tab] | ||||
| node                 pod                    replicationcontroller  service | ||||
| ``` | ||||
|  | ||||
| ### Plural form and shortcuts for nouns | ||||
|  | ||||
| If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`: | ||||
|  | ||||
| ```go | ||||
| argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } | ||||
|  | ||||
| cmd := &cobra.Command{ | ||||
|     ... | ||||
| 	ValidArgs:  validArgs, | ||||
| 	ArgAliases: argAliases | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by | ||||
| the completion algorithm if entered manually, e.g. in: | ||||
|  | ||||
| ```bash | ||||
| # kubectl get rc [tab][tab] | ||||
| backend        frontend       database  | ||||
| ``` | ||||
|  | ||||
| Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns | ||||
| in this example again instead of the replication controllers. | ||||
|  | ||||
| ### Dynamic completion of nouns | ||||
|  | ||||
| In some cases it is not possible to provide a list of possible completions in advance.  Instead, the list of completions must be determined at execution-time.  Cobra provides two ways of defining such dynamic completion of nouns. Note that both these methods can be used along-side each other as long as they are not both used for the same command. | ||||
|  | ||||
| **Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion.  It is therefore recommended to use *Custom Completions written in Go*. | ||||
|  | ||||
| #### 1. Custom completions of nouns written in Go | ||||
|  | ||||
| In a similar fashion as for static completions, you can use the `ValidArgsFunction` field to provide a Go function that Cobra will execute when it needs the list of completion choices for the nouns of a command.  Note that either `ValidArgs` or `ValidArgsFunction` can be used for a single cobra command, but not both. | ||||
| Simplified code from `helm status` looks like: | ||||
|  | ||||
| ```go | ||||
| cmd := &cobra.Command{ | ||||
| 	Use:   "status RELEASE_NAME", | ||||
| 	Short: "Display the status of the named release", | ||||
| 	Long:  status_long, | ||||
| 	RunE: func(cmd *cobra.Command, args []string) { | ||||
| 		RunGet(args[0]) | ||||
| 	}, | ||||
| 	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||||
| 		if len(args) != 0 { | ||||
| 			return nil, cobra.ShellCompDirectiveNoFileComp | ||||
| 		} | ||||
| 		return getReleasesFromCluster(toComplete), cobra.ShellCompDirectiveNoFileComp | ||||
| 	}, | ||||
| } | ||||
| ``` | ||||
| Where `getReleasesFromCluster()` is a Go function that obtains the list of current Helm releases running on the Kubernetes cluster. | ||||
| Notice we put the `ValidArgsFunction` on the `status` subcommand. Let's assume the Helm releases on the cluster are: `harbor`, `notary`, `rook` and `thanos` then this dynamic completion will give results like | ||||
|  | ||||
| ```bash | ||||
| # helm status [tab][tab] | ||||
| harbor notary rook thanos | ||||
| ``` | ||||
| You may have noticed the use of `cobra.ShellCompDirective`.  These directives are bit fields allowing to control some shell completion behaviors for your particular completion.  You can combine them with the bit-or operator such as `cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp` | ||||
| ```go | ||||
| // Indicates an error occurred and completions should be ignored. | ||||
| ShellCompDirectiveError | ||||
| // Indicates that the shell should not add a space after the completion, | ||||
| // even if there is a single completion provided. | ||||
| ShellCompDirectiveNoSpace | ||||
| // Indicates that the shell should not provide file completion even when | ||||
| // no completion is provided. | ||||
| // This currently does not work for zsh or bash < 4 | ||||
| ShellCompDirectiveNoFileComp | ||||
| // Indicates that the shell will perform its default behavior after completions | ||||
| // have been provided (this implies !ShellCompDirectiveNoSpace && !ShellCompDirectiveNoFileComp). | ||||
| ShellCompDirectiveDefault | ||||
| ``` | ||||
|  | ||||
| When using the `ValidArgsFunction`, Cobra will call your registered function after having parsed all flags and arguments provided in the command-line.  You therefore don't need to do this parsing yourself.  For example, when a user calls `helm status --namespace my-rook-ns [tab][tab]`, Cobra will call your registered `ValidArgsFunction` after having parsed the `--namespace` flag, as it would have done when calling the `RunE` function. | ||||
|  | ||||
| ##### Debugging | ||||
|  | ||||
| Cobra achieves dynamic completions written in Go through the use of a hidden command called by the completion script.  To debug your Go completion code, you can call this hidden command directly: | ||||
| ```bash | ||||
| # helm __complete status har<ENTER> | ||||
| harbor | ||||
| :4 | ||||
| Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr | ||||
| ``` | ||||
| ***Important:*** If the noun to complete is empty, you must pass an empty parameter to the `__complete` command: | ||||
| ```bash | ||||
| # helm __complete status ""<ENTER> | ||||
| harbor | ||||
| notary | ||||
| rook | ||||
| thanos | ||||
| :4 | ||||
| Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr | ||||
| ``` | ||||
| Calling the `__complete` command directly allows you to run the Go debugger to troubleshoot your code.  You can also add printouts to your code; Cobra provides the following functions to use for printouts in Go completion code: | ||||
| ```go | ||||
| // Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE | ||||
| // is set to a file path) and optionally prints to stderr. | ||||
| cobra.CompDebug(msg string, printToStdErr bool) { | ||||
| cobra.CompDebugln(msg string, printToStdErr bool) | ||||
|  | ||||
| // Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE | ||||
| // is set to a file path) and to stderr. | ||||
| cobra.CompError(msg string) | ||||
| cobra.CompErrorln(msg string) | ||||
| ``` | ||||
| ***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script.  Instead, use the cobra-provided debugging traces functions mentioned above. | ||||
|  | ||||
| #### 2. Custom completions of nouns written in Bash | ||||
|  | ||||
| This method allows you to inject bash functions into the completion script.  Those bash functions are responsible for providing the completion choices for your own completions. | ||||
|  | ||||
| Some more actual code that works in kubernetes: | ||||
|  | ||||
| @@ -47,7 +224,7 @@ __kubectl_get_resource() | ||||
|     fi | ||||
| } | ||||
|  | ||||
| __custom_func() { | ||||
| __kubectl_custom_func() { | ||||
|     case ${last_command} in | ||||
|         kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) | ||||
|             __kubectl_get_resource | ||||
| @@ -74,59 +251,7 @@ Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`, | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__custom_func()` to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`.  `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`.  So it will call `__kubectl_parse_get pod`.  `__kubectl_parse_get` will actually call out to kubernetes and get any pods.  It will then set `COMPREPLY` to valid pods! | ||||
|  | ||||
| ## Have the completions code complete your 'nouns' | ||||
|  | ||||
| In the above example "pod" was assumed to already be typed. But if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like: | ||||
|  | ||||
| ```go | ||||
| validArgs []string = { "pod", "node", "service", "replicationcontroller" } | ||||
|  | ||||
| cmd := &cobra.Command{ | ||||
| 	Use:     "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", | ||||
| 	Short:   "Display one or many resources", | ||||
| 	Long:    get_long, | ||||
| 	Example: get_example, | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		err := RunGet(f, out, cmd, args) | ||||
| 		util.CheckErr(err) | ||||
| 	}, | ||||
| 	ValidArgs: validArgs, | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like | ||||
|  | ||||
| ```bash | ||||
| # kubectl get [tab][tab] | ||||
| node                 pod                    replicationcontroller  service | ||||
| ``` | ||||
|  | ||||
| ## Plural form and shortcuts for nouns | ||||
|  | ||||
| If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`: | ||||
|  | ||||
| ```go | ||||
| argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } | ||||
|  | ||||
| cmd := &cobra.Command{ | ||||
|     ... | ||||
| 	ValidArgs:  validArgs, | ||||
| 	ArgAliases: argAliases | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by | ||||
| the completion algorithm if entered manually, e.g. in: | ||||
|  | ||||
| ```bash | ||||
| # kubectl get rc [tab][tab] | ||||
| backend        frontend       database  | ||||
| ``` | ||||
|  | ||||
| Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns | ||||
| in this example again instead of the replication controllers. | ||||
| The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__kubectl_custom_func()` (`__<command-use>_custom_func()`) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__kubectl_customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__kubectl_custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`.  `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`.  So it will call `__kubectl_parse_get pod`.  `__kubectl_parse_get` will actually call out to kubernetes and get any pods.  It will then set `COMPREPLY` to valid pods! | ||||
|  | ||||
| ## Mark flags as required | ||||
|  | ||||
| @@ -176,8 +301,45 @@ So while there are many other files in the CWD it only shows me subdirs and thos | ||||
|  | ||||
| # Specify custom flag completion | ||||
|  | ||||
| Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specify | ||||
| a custom flag completion function with cobra.BashCompCustom: | ||||
| As for nouns, Cobra provides two ways of defining dynamic completion of flags.  Note that both these methods can be used along-side each other as long as they are not both used for the same flag. | ||||
|  | ||||
| **Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion.  It is therefore recommended to use *Custom Completions written in Go*. | ||||
|  | ||||
| ## 1. Custom completions of flags written in Go | ||||
|  | ||||
| To provide a Go function that Cobra will execute when it needs the list of completion choices for a flag, you must register the function in the following manner: | ||||
|  | ||||
| ```go | ||||
| flagName := "output" | ||||
| cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||||
| 	return []string{"json", "table", "yaml"}, cobra.ShellCompDirectiveDefault | ||||
| }) | ||||
| ``` | ||||
| Notice that calling `RegisterFlagCompletionFunc()` is done through the `command` with which the flag is associated.  In our example this dynamic completion will give results like so: | ||||
|  | ||||
| ```bash | ||||
| # helm status --output [tab][tab] | ||||
| json table yaml | ||||
| ``` | ||||
|  | ||||
| ### Debugging | ||||
|  | ||||
| You can also easily debug your Go completion code for flags: | ||||
| ```bash | ||||
| # helm __complete status --output "" | ||||
| json | ||||
| table | ||||
| yaml | ||||
| :4 | ||||
| Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr | ||||
| ``` | ||||
| ***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script.  Instead, use the cobra-provided debugging traces functions mentioned in the above section. | ||||
|  | ||||
| ## 2. Custom completions of flags written in Bash | ||||
|  | ||||
| Alternatively, you can use bash code for flag custom completion. Similar to the filename | ||||
| completion and filtering using `cobra.BashCompFilenameExt`, you can specify | ||||
| a custom flag completion bash function with `cobra.BashCompCustom`: | ||||
|  | ||||
| ```go | ||||
| 	annotation := make(map[string][]string) | ||||
| @@ -191,7 +353,7 @@ a custom flag completion function with cobra.BashCompCustom: | ||||
| 	cmd.Flags().AddFlag(flag) | ||||
| ``` | ||||
|  | ||||
| In addition add the `__handle_namespace_flag` implementation in the `BashCompletionFunction` | ||||
| In addition add the `__kubectl_get_namespaces` implementation in the `BashCompletionFunction` | ||||
| value, e.g.: | ||||
|  | ||||
| ```bash | ||||
|   | ||||
							
								
								
									
										9
									
								
								vendor/github.com/spf13/cobra/cobra.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/spf13/cobra/cobra.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -23,6 +23,7 @@ import ( | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
| 	"time" | ||||
| 	"unicode" | ||||
| ) | ||||
|  | ||||
| @@ -51,11 +52,17 @@ var EnableCommandSorting = true | ||||
| // if the CLI is started from explorer.exe. | ||||
| // To disable the mousetrap, just set this variable to blank string (""). | ||||
| // Works only on Microsoft Windows. | ||||
| var MousetrapHelpText string = `This is a command line tool. | ||||
| var MousetrapHelpText = `This is a command line tool. | ||||
|  | ||||
| You need to open cmd.exe and run it from there. | ||||
| ` | ||||
|  | ||||
| // MousetrapDisplayDuration controls how long the MousetrapHelpText message is displayed on Windows | ||||
| // if the CLI is started from explorer.exe. Set to 0 to wait for the return key to be pressed. | ||||
| // To disable the mousetrap, just set MousetrapHelpText to blank string (""). | ||||
| // Works only on Microsoft Windows. | ||||
| var MousetrapDisplayDuration = 5 * time.Second | ||||
|  | ||||
| // AddTemplateFunc adds a template function that's available to Usage and Help | ||||
| // template generation. | ||||
| func AddTemplateFunc(name string, tmplFunc interface{}) { | ||||
|   | ||||
							
								
								
									
										151
									
								
								vendor/github.com/spf13/cobra/command.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										151
									
								
								vendor/github.com/spf13/cobra/command.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,6 +17,7 @@ package cobra | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| @@ -56,6 +57,10 @@ type Command struct { | ||||
|  | ||||
| 	// ValidArgs is list of all valid non-flag arguments that are accepted in bash completions | ||||
| 	ValidArgs []string | ||||
| 	// ValidArgsFunction is an optional function that provides valid non-flag arguments for bash completion. | ||||
| 	// It is a dynamic version of using ValidArgs. | ||||
| 	// Only one of ValidArgs and ValidArgsFunction can be used for a command. | ||||
| 	ValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) | ||||
|  | ||||
| 	// Expected arguments | ||||
| 	Args PositionalArgs | ||||
| @@ -80,7 +85,8 @@ type Command struct { | ||||
|  | ||||
| 	// Version defines the version for this command. If this value is non-empty and the command does not | ||||
| 	// define a "version" flag, a "version" boolean flag will be added to the command and, if specified, | ||||
| 	// will print content of the "Version" variable. | ||||
| 	// will print content of the "Version" variable. A shorthand "v" flag will also be added if the | ||||
| 	// command does not define one. | ||||
| 	Version string | ||||
|  | ||||
| 	// The *Run functions are executed in the following order: | ||||
| @@ -140,9 +146,11 @@ type Command struct { | ||||
| 	// TraverseChildren parses flags on all parents before executing child command. | ||||
| 	TraverseChildren bool | ||||
|  | ||||
| 	//FParseErrWhitelist flag parse errors to be ignored | ||||
| 	// FParseErrWhitelist flag parse errors to be ignored | ||||
| 	FParseErrWhitelist FParseErrWhitelist | ||||
|  | ||||
| 	ctx context.Context | ||||
|  | ||||
| 	// commands is the list of commands supported by this program. | ||||
| 	commands []*Command | ||||
| 	// parent is a parent command for this command. | ||||
| @@ -177,8 +185,6 @@ type Command struct { | ||||
| 	// that we can use on every pflag set and children commands | ||||
| 	globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName | ||||
|  | ||||
| 	// output is an output writer defined by user. | ||||
| 	output io.Writer | ||||
| 	// usageFunc is usage func defined by user. | ||||
| 	usageFunc func(*Command) error | ||||
| 	// usageTemplate is usage template defined by user. | ||||
| @@ -195,6 +201,19 @@ type Command struct { | ||||
| 	helpCommand *Command | ||||
| 	// versionTemplate is the version template defined by user. | ||||
| 	versionTemplate string | ||||
|  | ||||
| 	// inReader is a reader defined by the user that replaces stdin | ||||
| 	inReader io.Reader | ||||
| 	// outWriter is a writer defined by the user that replaces stdout | ||||
| 	outWriter io.Writer | ||||
| 	// errWriter is a writer defined by the user that replaces stderr | ||||
| 	errWriter io.Writer | ||||
| } | ||||
|  | ||||
| // Context returns underlying command context. If command wasn't | ||||
| // executed with ExecuteContext Context returns Background context. | ||||
| func (c *Command) Context() context.Context { | ||||
| 	return c.ctx | ||||
| } | ||||
|  | ||||
| // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden | ||||
| @@ -205,8 +224,28 @@ func (c *Command) SetArgs(a []string) { | ||||
|  | ||||
| // SetOutput sets the destination for usage and error messages. | ||||
| // If output is nil, os.Stderr is used. | ||||
| // Deprecated: Use SetOut and/or SetErr instead | ||||
| func (c *Command) SetOutput(output io.Writer) { | ||||
| 	c.output = output | ||||
| 	c.outWriter = output | ||||
| 	c.errWriter = output | ||||
| } | ||||
|  | ||||
| // SetOut sets the destination for usage messages. | ||||
| // If newOut is nil, os.Stdout is used. | ||||
| func (c *Command) SetOut(newOut io.Writer) { | ||||
| 	c.outWriter = newOut | ||||
| } | ||||
|  | ||||
| // SetErr sets the destination for error messages. | ||||
| // If newErr is nil, os.Stderr is used. | ||||
| func (c *Command) SetErr(newErr io.Writer) { | ||||
| 	c.errWriter = newErr | ||||
| } | ||||
|  | ||||
| // SetIn sets the source for input data | ||||
| // If newIn is nil, os.Stdin is used. | ||||
| func (c *Command) SetIn(newIn io.Reader) { | ||||
| 	c.inReader = newIn | ||||
| } | ||||
|  | ||||
| // SetUsageFunc sets usage function. Usage can be defined by application. | ||||
| @@ -267,9 +306,19 @@ func (c *Command) OutOrStderr() io.Writer { | ||||
| 	return c.getOut(os.Stderr) | ||||
| } | ||||
|  | ||||
| // ErrOrStderr returns output to stderr | ||||
| func (c *Command) ErrOrStderr() io.Writer { | ||||
| 	return c.getErr(os.Stderr) | ||||
| } | ||||
|  | ||||
| // InOrStdin returns input to stdin | ||||
| func (c *Command) InOrStdin() io.Reader { | ||||
| 	return c.getIn(os.Stdin) | ||||
| } | ||||
|  | ||||
| func (c *Command) getOut(def io.Writer) io.Writer { | ||||
| 	if c.output != nil { | ||||
| 		return c.output | ||||
| 	if c.outWriter != nil { | ||||
| 		return c.outWriter | ||||
| 	} | ||||
| 	if c.HasParent() { | ||||
| 		return c.parent.getOut(def) | ||||
| @@ -277,6 +326,26 @@ func (c *Command) getOut(def io.Writer) io.Writer { | ||||
| 	return def | ||||
| } | ||||
|  | ||||
| func (c *Command) getErr(def io.Writer) io.Writer { | ||||
| 	if c.errWriter != nil { | ||||
| 		return c.errWriter | ||||
| 	} | ||||
| 	if c.HasParent() { | ||||
| 		return c.parent.getErr(def) | ||||
| 	} | ||||
| 	return def | ||||
| } | ||||
|  | ||||
| func (c *Command) getIn(def io.Reader) io.Reader { | ||||
| 	if c.inReader != nil { | ||||
| 		return c.inReader | ||||
| 	} | ||||
| 	if c.HasParent() { | ||||
| 		return c.parent.getIn(def) | ||||
| 	} | ||||
| 	return def | ||||
| } | ||||
|  | ||||
| // UsageFunc returns either the function set by SetUsageFunc for this command | ||||
| // or a parent, or it returns a default usage function. | ||||
| func (c *Command) UsageFunc() (f func(*Command) error) { | ||||
| @@ -314,6 +383,8 @@ func (c *Command) HelpFunc() func(*Command, []string) { | ||||
| 	} | ||||
| 	return func(c *Command, a []string) { | ||||
| 		c.mergePersistentFlags() | ||||
| 		// The help should be sent to stdout | ||||
| 		// See https://github.com/spf13/cobra/issues/1002 | ||||
| 		err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) | ||||
| 		if err != nil { | ||||
| 			c.Println(err) | ||||
| @@ -329,13 +400,22 @@ func (c *Command) Help() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // UsageString return usage string. | ||||
| // UsageString returns usage string. | ||||
| func (c *Command) UsageString() string { | ||||
| 	tmpOutput := c.output | ||||
| 	// Storing normal writers | ||||
| 	tmpOutput := c.outWriter | ||||
| 	tmpErr := c.errWriter | ||||
|  | ||||
| 	bb := new(bytes.Buffer) | ||||
| 	c.SetOutput(bb) | ||||
| 	c.outWriter = bb | ||||
| 	c.errWriter = bb | ||||
|  | ||||
| 	c.Usage() | ||||
| 	c.output = tmpOutput | ||||
|  | ||||
| 	// Setting things back to normal | ||||
| 	c.outWriter = tmpOutput | ||||
| 	c.errWriter = tmpErr | ||||
|  | ||||
| 	return bb.String() | ||||
| } | ||||
|  | ||||
| @@ -793,6 +873,13 @@ func (c *Command) preRun() { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ExecuteContext is the same as Execute(), but sets the ctx on the command. | ||||
| // Retrieve ctx by calling cmd.Context() inside your *Run lifecycle functions. | ||||
| func (c *Command) ExecuteContext(ctx context.Context) error { | ||||
| 	c.ctx = ctx | ||||
| 	return c.Execute() | ||||
| } | ||||
|  | ||||
| // Execute uses the args (os.Args[1:] by default) | ||||
| // and run through the command tree finding appropriate matches | ||||
| // for commands and then corresponding flags. | ||||
| @@ -803,6 +890,10 @@ func (c *Command) Execute() error { | ||||
|  | ||||
| // ExecuteC executes the command. | ||||
| func (c *Command) ExecuteC() (cmd *Command, err error) { | ||||
| 	if c.ctx == nil { | ||||
| 		c.ctx = context.Background() | ||||
| 	} | ||||
|  | ||||
| 	// Regardless of what command execute is called on, run on Root only | ||||
| 	if c.HasParent() { | ||||
| 		return c.Root().ExecuteC() | ||||
| @@ -817,15 +908,16 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { | ||||
| 	// overriding | ||||
| 	c.InitDefaultHelpCmd() | ||||
|  | ||||
| 	var args []string | ||||
| 	args := c.args | ||||
|  | ||||
| 	// Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 | ||||
| 	if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { | ||||
| 		args = os.Args[1:] | ||||
| 	} else { | ||||
| 		args = c.args | ||||
| 	} | ||||
|  | ||||
| 	// initialize the hidden command to be used for bash completion | ||||
| 	c.initCompleteCmd(args) | ||||
|  | ||||
| 	var flags []string | ||||
| 	if c.TraverseChildren { | ||||
| 		cmd, flags, err = c.Traverse(args) | ||||
| @@ -849,6 +941,12 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { | ||||
| 		cmd.commandCalledAs.name = cmd.Name() | ||||
| 	} | ||||
|  | ||||
| 	// We have to pass global context to children command | ||||
| 	// if context is present on the parent command. | ||||
| 	if cmd.ctx == nil { | ||||
| 		cmd.ctx = c.ctx | ||||
| 	} | ||||
|  | ||||
| 	err = cmd.execute(flags) | ||||
| 	if err != nil { | ||||
| 		// Always show help if requested, even if SilenceErrors is in | ||||
| @@ -932,7 +1030,11 @@ func (c *Command) InitDefaultVersionFlag() { | ||||
| 		} else { | ||||
| 			usage += c.Name() | ||||
| 		} | ||||
| 		c.Flags().Bool("version", false, usage) | ||||
| 		if c.Flags().ShorthandLookup("v") == nil { | ||||
| 			c.Flags().BoolP("version", "v", false, usage) | ||||
| 		} else { | ||||
| 			c.Flags().Bool("version", false, usage) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -1070,6 +1172,21 @@ func (c *Command) Printf(format string, i ...interface{}) { | ||||
| 	c.Print(fmt.Sprintf(format, i...)) | ||||
| } | ||||
|  | ||||
| // PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set. | ||||
| func (c *Command) PrintErr(i ...interface{}) { | ||||
| 	fmt.Fprint(c.ErrOrStderr(), i...) | ||||
| } | ||||
|  | ||||
| // PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set. | ||||
| func (c *Command) PrintErrln(i ...interface{}) { | ||||
| 	c.Print(fmt.Sprintln(i...)) | ||||
| } | ||||
|  | ||||
| // PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set. | ||||
| func (c *Command) PrintErrf(format string, i ...interface{}) { | ||||
| 	c.Print(fmt.Sprintf(format, i...)) | ||||
| } | ||||
|  | ||||
| // CommandPath returns the full path to this command. | ||||
| func (c *Command) CommandPath() string { | ||||
| 	if c.HasParent() { | ||||
| @@ -1335,7 +1452,7 @@ func (c *Command) LocalFlags() *flag.FlagSet { | ||||
| 	return c.lflags | ||||
| } | ||||
|  | ||||
| // InheritedFlags returns all flags which were inherited from parents commands. | ||||
| // InheritedFlags returns all flags which were inherited from parent commands. | ||||
| func (c *Command) InheritedFlags() *flag.FlagSet { | ||||
| 	c.mergePersistentFlags() | ||||
|  | ||||
| @@ -1470,7 +1587,7 @@ func (c *Command) ParseFlags(args []string) error { | ||||
| 	beforeErrorBufLen := c.flagErrorBuf.Len() | ||||
| 	c.mergePersistentFlags() | ||||
|  | ||||
| 	//do it here after merging all flags and just before parse | ||||
| 	// do it here after merging all flags and just before parse | ||||
| 	c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist) | ||||
|  | ||||
| 	err := c.Flags().Parse(args) | ||||
|   | ||||
							
								
								
									
										8
									
								
								vendor/github.com/spf13/cobra/command_win.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/spf13/cobra/command_win.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,6 +3,7 @@ | ||||
| package cobra | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"time" | ||||
|  | ||||
| @@ -14,7 +15,12 @@ var preExecHookFn = preExecHook | ||||
| func preExecHook(c *Command) { | ||||
| 	if MousetrapHelpText != "" && mousetrap.StartedByExplorer() { | ||||
| 		c.Print(MousetrapHelpText) | ||||
| 		time.Sleep(5 * time.Second) | ||||
| 		if MousetrapDisplayDuration > 0 { | ||||
| 			time.Sleep(MousetrapDisplayDuration) | ||||
| 		} else { | ||||
| 			c.Println("Press return to continue...") | ||||
| 			fmt.Scanln() | ||||
| 		} | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										384
									
								
								vendor/github.com/spf13/cobra/custom_completions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								vendor/github.com/spf13/cobra/custom_completions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,384 @@ | ||||
| package cobra | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/spf13/pflag" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// ShellCompRequestCmd is the name of the hidden command that is used to request | ||||
| 	// completion results from the program.  It is used by the shell completion scripts. | ||||
| 	ShellCompRequestCmd = "__complete" | ||||
| 	// ShellCompNoDescRequestCmd is the name of the hidden command that is used to request | ||||
| 	// completion results without their description.  It is used by the shell completion scripts. | ||||
| 	ShellCompNoDescRequestCmd = "__completeNoDesc" | ||||
| ) | ||||
|  | ||||
| // Global map of flag completion functions. | ||||
| var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){} | ||||
|  | ||||
| // ShellCompDirective is a bit map representing the different behaviors the shell | ||||
| // can be instructed to have once completions have been provided. | ||||
| type ShellCompDirective int | ||||
|  | ||||
| const ( | ||||
| 	// ShellCompDirectiveError indicates an error occurred and completions should be ignored. | ||||
| 	ShellCompDirectiveError ShellCompDirective = 1 << iota | ||||
|  | ||||
| 	// ShellCompDirectiveNoSpace indicates that the shell should not add a space | ||||
| 	// after the completion even if there is a single completion provided. | ||||
| 	ShellCompDirectiveNoSpace | ||||
|  | ||||
| 	// ShellCompDirectiveNoFileComp indicates that the shell should not provide | ||||
| 	// file completion even when no completion is provided. | ||||
| 	// This currently does not work for zsh or bash < 4 | ||||
| 	ShellCompDirectiveNoFileComp | ||||
|  | ||||
| 	// ShellCompDirectiveDefault indicates to let the shell perform its default | ||||
| 	// behavior after completions have been provided. | ||||
| 	ShellCompDirectiveDefault ShellCompDirective = 0 | ||||
| ) | ||||
|  | ||||
| // RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag. | ||||
| func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error { | ||||
| 	flag := c.Flag(flagName) | ||||
| 	if flag == nil { | ||||
| 		return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName) | ||||
| 	} | ||||
| 	if _, exists := flagCompletionFunctions[flag]; exists { | ||||
| 		return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' already registered", flagName) | ||||
| 	} | ||||
| 	flagCompletionFunctions[flag] = f | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Returns a string listing the different directive enabled in the specified parameter | ||||
| func (d ShellCompDirective) string() string { | ||||
| 	var directives []string | ||||
| 	if d&ShellCompDirectiveError != 0 { | ||||
| 		directives = append(directives, "ShellCompDirectiveError") | ||||
| 	} | ||||
| 	if d&ShellCompDirectiveNoSpace != 0 { | ||||
| 		directives = append(directives, "ShellCompDirectiveNoSpace") | ||||
| 	} | ||||
| 	if d&ShellCompDirectiveNoFileComp != 0 { | ||||
| 		directives = append(directives, "ShellCompDirectiveNoFileComp") | ||||
| 	} | ||||
| 	if len(directives) == 0 { | ||||
| 		directives = append(directives, "ShellCompDirectiveDefault") | ||||
| 	} | ||||
|  | ||||
| 	if d > ShellCompDirectiveError+ShellCompDirectiveNoSpace+ShellCompDirectiveNoFileComp { | ||||
| 		return fmt.Sprintf("ERROR: unexpected ShellCompDirective value: %d", d) | ||||
| 	} | ||||
| 	return strings.Join(directives, ", ") | ||||
| } | ||||
|  | ||||
| // Adds a special hidden command that can be used to request custom completions. | ||||
| func (c *Command) initCompleteCmd(args []string) { | ||||
| 	completeCmd := &Command{ | ||||
| 		Use:                   fmt.Sprintf("%s [command-line]", ShellCompRequestCmd), | ||||
| 		Aliases:               []string{ShellCompNoDescRequestCmd}, | ||||
| 		DisableFlagsInUseLine: true, | ||||
| 		Hidden:                true, | ||||
| 		DisableFlagParsing:    true, | ||||
| 		Args:                  MinimumNArgs(1), | ||||
| 		Short:                 "Request shell completion choices for the specified command-line", | ||||
| 		Long: fmt.Sprintf("%[2]s is a special command that is used by the shell completion logic\n%[1]s", | ||||
| 			"to request completion choices for the specified command-line.", ShellCompRequestCmd), | ||||
| 		Run: func(cmd *Command, args []string) { | ||||
| 			finalCmd, completions, directive, err := cmd.getCompletions(args) | ||||
| 			if err != nil { | ||||
| 				CompErrorln(err.Error()) | ||||
| 				// Keep going for multiple reasons: | ||||
| 				// 1- There could be some valid completions even though there was an error | ||||
| 				// 2- Even without completions, we need to print the directive | ||||
| 			} | ||||
|  | ||||
| 			noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd) | ||||
| 			for _, comp := range completions { | ||||
| 				if noDescriptions { | ||||
| 					// Remove any description that may be included following a tab character. | ||||
| 					comp = strings.Split(comp, "\t")[0] | ||||
| 				} | ||||
| 				// Print each possible completion to stdout for the completion script to consume. | ||||
| 				fmt.Fprintln(finalCmd.OutOrStdout(), comp) | ||||
| 			} | ||||
|  | ||||
| 			if directive > ShellCompDirectiveError+ShellCompDirectiveNoSpace+ShellCompDirectiveNoFileComp { | ||||
| 				directive = ShellCompDirectiveDefault | ||||
| 			} | ||||
|  | ||||
| 			// As the last printout, print the completion directive for the completion script to parse. | ||||
| 			// The directive integer must be that last character following a single colon (:). | ||||
| 			// The completion script expects :<directive> | ||||
| 			fmt.Fprintf(finalCmd.OutOrStdout(), ":%d\n", directive) | ||||
|  | ||||
| 			// Print some helpful info to stderr for the user to understand. | ||||
| 			// Output from stderr must be ignored by the completion script. | ||||
| 			fmt.Fprintf(finalCmd.ErrOrStderr(), "Completion ended with directive: %s\n", directive.string()) | ||||
| 		}, | ||||
| 	} | ||||
| 	c.AddCommand(completeCmd) | ||||
| 	subCmd, _, err := c.Find(args) | ||||
| 	if err != nil || subCmd.Name() != ShellCompRequestCmd { | ||||
| 		// Only create this special command if it is actually being called. | ||||
| 		// This reduces possible side-effects of creating such a command; | ||||
| 		// for example, having this command would cause problems to a | ||||
| 		// cobra program that only consists of the root command, since this | ||||
| 		// command would cause the root command to suddenly have a subcommand. | ||||
| 		c.RemoveCommand(completeCmd) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDirective, error) { | ||||
| 	var completions []string | ||||
|  | ||||
| 	// The last argument, which is not completely typed by the user, | ||||
| 	// should not be part of the list of arguments | ||||
| 	toComplete := args[len(args)-1] | ||||
| 	trimmedArgs := args[:len(args)-1] | ||||
|  | ||||
| 	// Find the real command for which completion must be performed | ||||
| 	finalCmd, finalArgs, err := c.Root().Find(trimmedArgs) | ||||
| 	if err != nil { | ||||
| 		// Unable to find the real command. E.g., <program> someInvalidCmd <TAB> | ||||
| 		return c, completions, ShellCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs) | ||||
| 	} | ||||
|  | ||||
| 	// When doing completion of a flag name, as soon as an argument starts with | ||||
| 	// a '-' we know it is a flag.  We cannot use isFlagArg() here as it requires | ||||
| 	// the flag to be complete | ||||
| 	if len(toComplete) > 0 && toComplete[0] == '-' && !strings.Contains(toComplete, "=") { | ||||
| 		// We are completing a flag name | ||||
| 		finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { | ||||
| 			completions = append(completions, getFlagNameCompletions(flag, toComplete)...) | ||||
| 		}) | ||||
| 		finalCmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { | ||||
| 			completions = append(completions, getFlagNameCompletions(flag, toComplete)...) | ||||
| 		}) | ||||
|  | ||||
| 		directive := ShellCompDirectiveDefault | ||||
| 		if len(completions) > 0 { | ||||
| 			if strings.HasSuffix(completions[0], "=") { | ||||
| 				directive = ShellCompDirectiveNoSpace | ||||
| 			} | ||||
| 		} | ||||
| 		return finalCmd, completions, directive, nil | ||||
| 	} | ||||
|  | ||||
| 	var flag *pflag.Flag | ||||
| 	if !finalCmd.DisableFlagParsing { | ||||
| 		// We only do flag completion if we are allowed to parse flags | ||||
| 		// This is important for commands which have requested to do their own flag completion. | ||||
| 		flag, finalArgs, toComplete, err = checkIfFlagCompletion(finalCmd, finalArgs, toComplete) | ||||
| 		if err != nil { | ||||
| 			// Error while attempting to parse flags | ||||
| 			return finalCmd, completions, ShellCompDirectiveDefault, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if flag == nil { | ||||
| 		// Complete subcommand names | ||||
| 		for _, subCmd := range finalCmd.Commands() { | ||||
| 			if subCmd.IsAvailableCommand() && strings.HasPrefix(subCmd.Name(), toComplete) { | ||||
| 				completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short)) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if len(finalCmd.ValidArgs) > 0 { | ||||
| 			// Always complete ValidArgs, even if we are completing a subcommand name. | ||||
| 			// This is for commands that have both subcommands and ValidArgs. | ||||
| 			for _, validArg := range finalCmd.ValidArgs { | ||||
| 				if strings.HasPrefix(validArg, toComplete) { | ||||
| 					completions = append(completions, validArg) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			// If there are ValidArgs specified (even if they don't match), we stop completion. | ||||
| 			// Only one of ValidArgs or ValidArgsFunction can be used for a single command. | ||||
| 			return finalCmd, completions, ShellCompDirectiveNoFileComp, nil | ||||
| 		} | ||||
|  | ||||
| 		// Always let the logic continue so as to add any ValidArgsFunction completions, | ||||
| 		// even if we already found sub-commands. | ||||
| 		// This is for commands that have subcommands but also specify a ValidArgsFunction. | ||||
| 	} | ||||
|  | ||||
| 	// Parse the flags and extract the arguments to prepare for calling the completion function | ||||
| 	if err = finalCmd.ParseFlags(finalArgs); err != nil { | ||||
| 		return finalCmd, completions, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	// We only remove the flags from the arguments if DisableFlagParsing is not set. | ||||
| 	// This is important for commands which have requested to do their own flag completion. | ||||
| 	if !finalCmd.DisableFlagParsing { | ||||
| 		finalArgs = finalCmd.Flags().Args() | ||||
| 	} | ||||
|  | ||||
| 	// Find the completion function for the flag or command | ||||
| 	var completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) | ||||
| 	if flag != nil { | ||||
| 		completionFn = flagCompletionFunctions[flag] | ||||
| 	} else { | ||||
| 		completionFn = finalCmd.ValidArgsFunction | ||||
| 	} | ||||
| 	if completionFn == nil { | ||||
| 		// Go custom completion not supported/needed for this flag or command | ||||
| 		return finalCmd, completions, ShellCompDirectiveDefault, nil | ||||
| 	} | ||||
|  | ||||
| 	// Call the registered completion function to get the completions | ||||
| 	comps, directive := completionFn(finalCmd, finalArgs, toComplete) | ||||
| 	completions = append(completions, comps...) | ||||
| 	return finalCmd, completions, directive, nil | ||||
| } | ||||
|  | ||||
| func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string { | ||||
| 	if nonCompletableFlag(flag) { | ||||
| 		return []string{} | ||||
| 	} | ||||
|  | ||||
| 	var completions []string | ||||
| 	flagName := "--" + flag.Name | ||||
| 	if strings.HasPrefix(flagName, toComplete) { | ||||
| 		// Flag without the = | ||||
| 		completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) | ||||
|  | ||||
| 		if len(flag.NoOptDefVal) == 0 { | ||||
| 			// Flag requires a value, so it can be suffixed with = | ||||
| 			flagName += "=" | ||||
| 			completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	flagName = "-" + flag.Shorthand | ||||
| 	if len(flag.Shorthand) > 0 && strings.HasPrefix(flagName, toComplete) { | ||||
| 		completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) | ||||
| 	} | ||||
|  | ||||
| 	return completions | ||||
| } | ||||
|  | ||||
| func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*pflag.Flag, []string, string, error) { | ||||
| 	var flagName string | ||||
| 	trimmedArgs := args | ||||
| 	flagWithEqual := false | ||||
| 	if isFlagArg(lastArg) { | ||||
| 		if index := strings.Index(lastArg, "="); index >= 0 { | ||||
| 			flagName = strings.TrimLeft(lastArg[:index], "-") | ||||
| 			lastArg = lastArg[index+1:] | ||||
| 			flagWithEqual = true | ||||
| 		} else { | ||||
| 			return nil, nil, "", errors.New("Unexpected completion request for flag") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(flagName) == 0 { | ||||
| 		if len(args) > 0 { | ||||
| 			prevArg := args[len(args)-1] | ||||
| 			if isFlagArg(prevArg) { | ||||
| 				// Only consider the case where the flag does not contain an =. | ||||
| 				// If the flag contains an = it means it has already been fully processed, | ||||
| 				// so we don't need to deal with it here. | ||||
| 				if index := strings.Index(prevArg, "="); index < 0 { | ||||
| 					flagName = strings.TrimLeft(prevArg, "-") | ||||
|  | ||||
| 					// Remove the uncompleted flag or else there could be an error created | ||||
| 					// for an invalid value for that flag | ||||
| 					trimmedArgs = args[:len(args)-1] | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(flagName) == 0 { | ||||
| 		// Not doing flag completion | ||||
| 		return nil, trimmedArgs, lastArg, nil | ||||
| 	} | ||||
|  | ||||
| 	flag := findFlag(finalCmd, flagName) | ||||
| 	if flag == nil { | ||||
| 		// Flag not supported by this command, nothing to complete | ||||
| 		err := fmt.Errorf("Subcommand '%s' does not support flag '%s'", finalCmd.Name(), flagName) | ||||
| 		return nil, nil, "", err | ||||
| 	} | ||||
|  | ||||
| 	if !flagWithEqual { | ||||
| 		if len(flag.NoOptDefVal) != 0 { | ||||
| 			// We had assumed dealing with a two-word flag but the flag is a boolean flag. | ||||
| 			// In that case, there is no value following it, so we are not really doing flag completion. | ||||
| 			// Reset everything to do noun completion. | ||||
| 			trimmedArgs = args | ||||
| 			flag = nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return flag, trimmedArgs, lastArg, nil | ||||
| } | ||||
|  | ||||
| func findFlag(cmd *Command, name string) *pflag.Flag { | ||||
| 	flagSet := cmd.Flags() | ||||
| 	if len(name) == 1 { | ||||
| 		// First convert the short flag into a long flag | ||||
| 		// as the cmd.Flag() search only accepts long flags | ||||
| 		if short := flagSet.ShorthandLookup(name); short != nil { | ||||
| 			name = short.Name | ||||
| 		} else { | ||||
| 			set := cmd.InheritedFlags() | ||||
| 			if short = set.ShorthandLookup(name); short != nil { | ||||
| 				name = short.Name | ||||
| 			} else { | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return cmd.Flag(name) | ||||
| } | ||||
|  | ||||
| // CompDebug prints the specified string to the same file as where the | ||||
| // completion script prints its logs. | ||||
| // Note that completion printouts should never be on stdout as they would | ||||
| // be wrongly interpreted as actual completion choices by the completion script. | ||||
| func CompDebug(msg string, printToStdErr bool) { | ||||
| 	msg = fmt.Sprintf("[Debug] %s", msg) | ||||
|  | ||||
| 	// Such logs are only printed when the user has set the environment | ||||
| 	// variable BASH_COMP_DEBUG_FILE to the path of some file to be used. | ||||
| 	if path := os.Getenv("BASH_COMP_DEBUG_FILE"); path != "" { | ||||
| 		f, err := os.OpenFile(path, | ||||
| 			os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | ||||
| 		if err == nil { | ||||
| 			defer f.Close() | ||||
| 			f.WriteString(msg) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if printToStdErr { | ||||
| 		// Must print to stderr for this not to be read by the completion script. | ||||
| 		fmt.Fprintf(os.Stderr, msg) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // CompDebugln prints the specified string with a newline at the end | ||||
| // to the same file as where the completion script prints its logs. | ||||
| // Such logs are only printed when the user has set the environment | ||||
| // variable BASH_COMP_DEBUG_FILE to the path of some file to be used. | ||||
| func CompDebugln(msg string, printToStdErr bool) { | ||||
| 	CompDebug(fmt.Sprintf("%s\n", msg), printToStdErr) | ||||
| } | ||||
|  | ||||
| // CompError prints the specified completion message to stderr. | ||||
| func CompError(msg string) { | ||||
| 	msg = fmt.Sprintf("[Error] %s", msg) | ||||
| 	CompDebug(msg, true) | ||||
| } | ||||
|  | ||||
| // CompErrorln prints the specified completion message to stderr with a newline at the end. | ||||
| func CompErrorln(msg string) { | ||||
| 	CompError(fmt.Sprintf("%s\n", msg)) | ||||
| } | ||||
							
								
								
									
										172
									
								
								vendor/github.com/spf13/cobra/fish_completions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								vendor/github.com/spf13/cobra/fish_completions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | ||||
| package cobra | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) { | ||||
| 	compCmd := ShellCompRequestCmd | ||||
| 	if !includeDesc { | ||||
| 		compCmd = ShellCompNoDescRequestCmd | ||||
| 	} | ||||
| 	buf.WriteString(fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name)) | ||||
| 	buf.WriteString(fmt.Sprintf(` | ||||
| function __%[1]s_debug | ||||
|     set file "$BASH_COMP_DEBUG_FILE" | ||||
|     if test -n "$file" | ||||
|         echo "$argv" >> $file | ||||
|     end | ||||
| end | ||||
|  | ||||
| function __%[1]s_perform_completion | ||||
|     __%[1]s_debug "Starting __%[1]s_perform_completion with: $argv" | ||||
|  | ||||
|     set args (string split -- " " "$argv") | ||||
|     set lastArg "$args[-1]" | ||||
|  | ||||
|     __%[1]s_debug "args: $args" | ||||
|     __%[1]s_debug "last arg: $lastArg" | ||||
|  | ||||
|     set emptyArg "" | ||||
|     if test -z "$lastArg" | ||||
|         __%[1]s_debug "Setting emptyArg" | ||||
|         set emptyArg \"\" | ||||
|     end | ||||
|     __%[1]s_debug "emptyArg: $emptyArg" | ||||
|  | ||||
|     set requestComp "$args[1] %[2]s $args[2..-1] $emptyArg" | ||||
|     __%[1]s_debug "Calling $requestComp" | ||||
|  | ||||
|     set results (eval $requestComp 2> /dev/null) | ||||
|     set comps $results[1..-2] | ||||
|     set directiveLine $results[-1] | ||||
|  | ||||
|     # For Fish, when completing a flag with an = (e.g., <program> -n=<TAB>) | ||||
|     # completions must be prefixed with the flag | ||||
|     set flagPrefix (string match -r -- '-.*=' "$lastArg") | ||||
|  | ||||
|     __%[1]s_debug "Comps: $comps" | ||||
|     __%[1]s_debug "DirectiveLine: $directiveLine" | ||||
|     __%[1]s_debug "flagPrefix: $flagPrefix" | ||||
|  | ||||
|     for comp in $comps | ||||
|         printf "%%s%%s\n" "$flagPrefix" "$comp" | ||||
|     end | ||||
|  | ||||
|     printf "%%s\n" "$directiveLine" | ||||
| end | ||||
|  | ||||
| # This function does three things: | ||||
| # 1- Obtain the completions and store them in the global __%[1]s_comp_results | ||||
| # 2- Set the __%[1]s_comp_do_file_comp flag if file completion should be performed | ||||
| #    and unset it otherwise | ||||
| # 3- Return true if the completion results are not empty | ||||
| function __%[1]s_prepare_completions | ||||
|     # Start fresh | ||||
|     set --erase __%[1]s_comp_do_file_comp | ||||
|     set --erase __%[1]s_comp_results | ||||
|  | ||||
|     # Check if the command-line is already provided.  This is useful for testing. | ||||
|     if not set --query __%[1]s_comp_commandLine | ||||
|         set __%[1]s_comp_commandLine (commandline) | ||||
|     end | ||||
|     __%[1]s_debug "commandLine is: $__%[1]s_comp_commandLine" | ||||
|  | ||||
|     set results (__%[1]s_perform_completion "$__%[1]s_comp_commandLine") | ||||
|     set --erase __%[1]s_comp_commandLine | ||||
|     __%[1]s_debug "Completion results: $results" | ||||
|  | ||||
|     if test -z "$results" | ||||
|         __%[1]s_debug "No completion, probably due to a failure" | ||||
|         # Might as well do file completion, in case it helps | ||||
|         set --global __%[1]s_comp_do_file_comp 1 | ||||
|         return 0 | ||||
|     end | ||||
|  | ||||
|     set directive (string sub --start 2 $results[-1]) | ||||
|     set --global __%[1]s_comp_results $results[1..-2] | ||||
|  | ||||
|     __%[1]s_debug "Completions are: $__%[1]s_comp_results" | ||||
|     __%[1]s_debug "Directive is: $directive" | ||||
|  | ||||
|     if test -z "$directive" | ||||
|         set directive 0 | ||||
|     end | ||||
|  | ||||
|     set compErr (math (math --scale 0 $directive / %[3]d) %% 2) | ||||
|     if test $compErr -eq 1 | ||||
|         __%[1]s_debug "Received error directive: aborting." | ||||
|         # Might as well do file completion, in case it helps | ||||
|         set --global __%[1]s_comp_do_file_comp 1 | ||||
|         return 0 | ||||
|     end | ||||
|  | ||||
|     set nospace (math (math --scale 0 $directive / %[4]d) %% 2) | ||||
|     set nofiles (math (math --scale 0 $directive / %[5]d) %% 2) | ||||
|  | ||||
|     __%[1]s_debug "nospace: $nospace, nofiles: $nofiles" | ||||
|  | ||||
|     # Important not to quote the variable for count to work | ||||
|     set numComps (count $__%[1]s_comp_results) | ||||
|     __%[1]s_debug "numComps: $numComps" | ||||
|  | ||||
|     if test $numComps -eq 1; and test $nospace -ne 0 | ||||
|         # To support the "nospace" directive we trick the shell | ||||
|         # by outputting an extra, longer completion. | ||||
|         __%[1]s_debug "Adding second completion to perform nospace directive" | ||||
|         set --append __%[1]s_comp_results $__%[1]s_comp_results[1]. | ||||
|     end | ||||
|  | ||||
|     if test $numComps -eq 0; and test $nofiles -eq 0 | ||||
|         __%[1]s_debug "Requesting file completion" | ||||
|         set --global __%[1]s_comp_do_file_comp 1 | ||||
|     end | ||||
|  | ||||
|     # If we don't want file completion, we must return true even if there | ||||
|     # are no completions found.  This is because fish will perform the last | ||||
|     # completion command, even if its condition is false, if no other | ||||
|     # completion command was triggered | ||||
|     return (not set --query __%[1]s_comp_do_file_comp) | ||||
| end | ||||
|  | ||||
| # Remove any pre-existing completions for the program since we will be handling all of them | ||||
| # TODO this cleanup is not sufficient.  Fish completions are only loaded once the user triggers | ||||
| # them, so the below deletion will not work as it is run too early.  What else can we do? | ||||
| complete -c %[1]s -e | ||||
|  | ||||
| # The order in which the below two lines are defined is very important so that __%[1]s_prepare_completions | ||||
| # is called first.  It is __%[1]s_prepare_completions that sets up the __%[1]s_comp_do_file_comp variable. | ||||
| # | ||||
| # This completion will be run second as complete commands are added FILO. | ||||
| # It triggers file completion choices when __%[1]s_comp_do_file_comp is set. | ||||
| complete -c %[1]s -n 'set --query __%[1]s_comp_do_file_comp' | ||||
|  | ||||
| # This completion will be run first as complete commands are added FILO. | ||||
| # The call to __%[1]s_prepare_completions will setup both __%[1]s_comp_results abd __%[1]s_comp_do_file_comp. | ||||
| # It provides the program's completion choices. | ||||
| complete -c %[1]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' | ||||
|  | ||||
| `, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp)) | ||||
| } | ||||
|  | ||||
| // GenFishCompletion generates fish completion file and writes to the passed writer. | ||||
| func (c *Command) GenFishCompletion(w io.Writer, includeDesc bool) error { | ||||
| 	buf := new(bytes.Buffer) | ||||
| 	genFishComp(buf, c.Name(), includeDesc) | ||||
| 	_, err := buf.WriteTo(w) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // GenFishCompletionFile generates fish completion file. | ||||
| func (c *Command) GenFishCompletionFile(filename string, includeDesc bool) error { | ||||
| 	outFile, err := os.Create(filename) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer outFile.Close() | ||||
|  | ||||
| 	return c.GenFishCompletion(outFile, includeDesc) | ||||
| } | ||||
							
								
								
									
										7
									
								
								vendor/github.com/spf13/cobra/fish_completions.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/spf13/cobra/fish_completions.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| ## Generating Fish Completions for your own cobra.Command | ||||
|  | ||||
| Cobra supports native Fish completions generated from the root `cobra.Command`.  You can use the `command.GenFishCompletion()` or `command.GenFishCompletionFile()` functions. You must provide these functions with a parameter indicating if the completions should be annotated with a description; Cobra will provide the description automatically based on usage information.  You can choose to make this option configurable by your users. | ||||
|  | ||||
| ### Limitations | ||||
|  | ||||
| * Custom completions implemented using the `ValidArgsFunction` and `RegisterFlagCompletionFunc()` are supported automatically but the ones implemented in Bash scripting are not. | ||||
							
								
								
									
										12
									
								
								vendor/github.com/spf13/cobra/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/spf13/cobra/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| module github.com/spf13/cobra | ||||
|  | ||||
| go 1.12 | ||||
|  | ||||
| require ( | ||||
| 	github.com/cpuguy83/go-md2man/v2 v2.0.0 | ||||
| 	github.com/inconshreveable/mousetrap v1.0.0 | ||||
| 	github.com/mitchellh/go-homedir v1.1.0 | ||||
| 	github.com/spf13/pflag v1.0.3 | ||||
| 	github.com/spf13/viper v1.4.0 | ||||
| 	gopkg.in/yaml.v2 v2.2.2 | ||||
| ) | ||||
							
								
								
									
										149
									
								
								vendor/github.com/spf13/cobra/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								vendor/github.com/spf13/cobra/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,149 @@ | ||||
| cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | ||||
| github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | ||||
| github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||||
| github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= | ||||
| github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | ||||
| github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= | ||||
| github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= | ||||
| github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= | ||||
| github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= | ||||
| github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= | ||||
| github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||||
| github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= | ||||
| github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= | ||||
| github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= | ||||
| github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | ||||
| github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= | ||||
| github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= | ||||
| github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | ||||
| github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= | ||||
| github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= | ||||
| github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | ||||
| github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | ||||
| github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= | ||||
| github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= | ||||
| github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= | ||||
| github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= | ||||
| github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||
| github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= | ||||
| github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||||
| github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | ||||
| github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | ||||
| github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||
| github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||
| github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | ||||
| github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | ||||
| github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | ||||
| github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= | ||||
| github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= | ||||
| github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= | ||||
| github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= | ||||
| github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= | ||||
| github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= | ||||
| github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= | ||||
| github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= | ||||
| github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= | ||||
| github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= | ||||
| github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | ||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||||
| github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= | ||||
| github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= | ||||
| github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||||
| github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||
| github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= | ||||
| github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||||
| github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= | ||||
| github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | ||||
| github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | ||||
| github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= | ||||
| github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= | ||||
| github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= | ||||
| github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||||
| github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= | ||||
| github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= | ||||
| github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= | ||||
| github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= | ||||
| github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= | ||||
| github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= | ||||
| github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= | ||||
| github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||||
| github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= | ||||
| github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= | ||||
| github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= | ||||
| github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= | ||||
| github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= | ||||
| github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= | ||||
| github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= | ||||
| github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||||
| github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= | ||||
| github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= | ||||
| github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= | ||||
| github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= | ||||
| github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= | ||||
| github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= | ||||
| github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= | ||||
| github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= | ||||
| github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= | ||||
| github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= | ||||
| github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= | ||||
| github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= | ||||
| github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= | ||||
| github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= | ||||
| github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= | ||||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= | ||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||
| github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= | ||||
| github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= | ||||
| github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= | ||||
| github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= | ||||
| go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= | ||||
| go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | ||||
| go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= | ||||
| go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= | ||||
| golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||
| golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||||
| golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | ||||
| golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | ||||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= | ||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | ||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||||
| google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | ||||
| google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | ||||
| google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | ||||
| gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= | ||||
| gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= | ||||
| gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= | ||||
| gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||
| gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | ||||
| gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||
| honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
							
								
								
									
										100
									
								
								vendor/github.com/spf13/cobra/powershell_completions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								vendor/github.com/spf13/cobra/powershell_completions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| // PowerShell completions are based on the amazing work from clap: | ||||
| // https://github.com/clap-rs/clap/blob/3294d18efe5f264d12c9035f404c7d189d4824e1/src/completions/powershell.rs | ||||
| // | ||||
| // The generated scripts require PowerShell v5.0+ (which comes Windows 10, but | ||||
| // can be downloaded separately for windows 7 or 8.1). | ||||
|  | ||||
| package cobra | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/spf13/pflag" | ||||
| ) | ||||
|  | ||||
| var powerShellCompletionTemplate = `using namespace System.Management.Automation | ||||
| using namespace System.Management.Automation.Language | ||||
| Register-ArgumentCompleter -Native -CommandName '%s' -ScriptBlock { | ||||
|     param($wordToComplete, $commandAst, $cursorPosition) | ||||
|     $commandElements = $commandAst.CommandElements | ||||
|     $command = @( | ||||
|         '%s' | ||||
|         for ($i = 1; $i -lt $commandElements.Count; $i++) { | ||||
|             $element = $commandElements[$i] | ||||
|             if ($element -isnot [StringConstantExpressionAst] -or | ||||
|                 $element.StringConstantType -ne [StringConstantType]::BareWord -or | ||||
|                 $element.Value.StartsWith('-')) { | ||||
|                 break | ||||
|             } | ||||
|             $element.Value | ||||
|         } | ||||
|     ) -join ';' | ||||
|     $completions = @(switch ($command) {%s | ||||
|     }) | ||||
|     $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | | ||||
|         Sort-Object -Property ListItemText | ||||
| }` | ||||
|  | ||||
| func generatePowerShellSubcommandCases(out io.Writer, cmd *Command, previousCommandName string) { | ||||
| 	var cmdName string | ||||
| 	if previousCommandName == "" { | ||||
| 		cmdName = cmd.Name() | ||||
| 	} else { | ||||
| 		cmdName = fmt.Sprintf("%s;%s", previousCommandName, cmd.Name()) | ||||
| 	} | ||||
|  | ||||
| 	fmt.Fprintf(out, "\n        '%s' {", cmdName) | ||||
|  | ||||
| 	cmd.Flags().VisitAll(func(flag *pflag.Flag) { | ||||
| 		if nonCompletableFlag(flag) { | ||||
| 			return | ||||
| 		} | ||||
| 		usage := escapeStringForPowerShell(flag.Usage) | ||||
| 		if len(flag.Shorthand) > 0 { | ||||
| 			fmt.Fprintf(out, "\n            [CompletionResult]::new('-%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Shorthand, flag.Shorthand, usage) | ||||
| 		} | ||||
| 		fmt.Fprintf(out, "\n            [CompletionResult]::new('--%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Name, flag.Name, usage) | ||||
| 	}) | ||||
|  | ||||
| 	for _, subCmd := range cmd.Commands() { | ||||
| 		usage := escapeStringForPowerShell(subCmd.Short) | ||||
| 		fmt.Fprintf(out, "\n            [CompletionResult]::new('%s', '%s', [CompletionResultType]::ParameterValue, '%s')", subCmd.Name(), subCmd.Name(), usage) | ||||
| 	} | ||||
|  | ||||
| 	fmt.Fprint(out, "\n            break\n        }") | ||||
|  | ||||
| 	for _, subCmd := range cmd.Commands() { | ||||
| 		generatePowerShellSubcommandCases(out, subCmd, cmdName) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func escapeStringForPowerShell(s string) string { | ||||
| 	return strings.Replace(s, "'", "''", -1) | ||||
| } | ||||
|  | ||||
| // GenPowerShellCompletion generates PowerShell completion file and writes to the passed writer. | ||||
| func (c *Command) GenPowerShellCompletion(w io.Writer) error { | ||||
| 	buf := new(bytes.Buffer) | ||||
|  | ||||
| 	var subCommandCases bytes.Buffer | ||||
| 	generatePowerShellSubcommandCases(&subCommandCases, c, "") | ||||
| 	fmt.Fprintf(buf, powerShellCompletionTemplate, c.Name(), c.Name(), subCommandCases.String()) | ||||
|  | ||||
| 	_, err := buf.WriteTo(w) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // GenPowerShellCompletionFile generates PowerShell completion file. | ||||
| func (c *Command) GenPowerShellCompletionFile(filename string) error { | ||||
| 	outFile, err := os.Create(filename) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer outFile.Close() | ||||
|  | ||||
| 	return c.GenPowerShellCompletion(outFile) | ||||
| } | ||||
							
								
								
									
										14
									
								
								vendor/github.com/spf13/cobra/powershell_completions.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/spf13/cobra/powershell_completions.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| # Generating PowerShell Completions For Your Own cobra.Command | ||||
|  | ||||
| Cobra can generate PowerShell completion scripts. Users need PowerShell version 5.0 or above, which comes with Windows 10 and can be downloaded separately for Windows 7 or 8.1. They can then write the completions to a file and source this file from their PowerShell profile, which is referenced by the `$Profile` environment variable. See `Get-Help about_Profiles` for more info about PowerShell profiles. | ||||
|  | ||||
| # What's supported | ||||
|  | ||||
| - Completion for subcommands using their `.Short` description | ||||
| - Completion for non-hidden flags using their `.Name` and `.Shorthand` | ||||
|  | ||||
| # What's not yet supported | ||||
|  | ||||
| - Command aliases | ||||
| - Required, filename or custom flags (they will work like normal flags) | ||||
| - Custom completion scripts | ||||
							
								
								
									
										85
									
								
								vendor/github.com/spf13/cobra/shell_completions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								vendor/github.com/spf13/cobra/shell_completions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| package cobra | ||||
|  | ||||
| import ( | ||||
| 	"github.com/spf13/pflag" | ||||
| ) | ||||
|  | ||||
| // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists, | ||||
| // and causes your command to report an error if invoked without the flag. | ||||
| func (c *Command) MarkFlagRequired(name string) error { | ||||
| 	return MarkFlagRequired(c.Flags(), name) | ||||
| } | ||||
|  | ||||
| // MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists, | ||||
| // and causes your command to report an error if invoked without the flag. | ||||
| func (c *Command) MarkPersistentFlagRequired(name string) error { | ||||
| 	return MarkFlagRequired(c.PersistentFlags(), name) | ||||
| } | ||||
|  | ||||
| // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists, | ||||
| // and causes your command to report an error if invoked without the flag. | ||||
| func MarkFlagRequired(flags *pflag.FlagSet, name string) error { | ||||
| 	return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) | ||||
| } | ||||
|  | ||||
| // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. | ||||
| // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. | ||||
| func (c *Command) MarkFlagFilename(name string, extensions ...string) error { | ||||
| 	return MarkFlagFilename(c.Flags(), name, extensions...) | ||||
| } | ||||
|  | ||||
| // MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. | ||||
| // Generated bash autocompletion will call the bash function f for the flag. | ||||
| func (c *Command) MarkFlagCustom(name string, f string) error { | ||||
| 	return MarkFlagCustom(c.Flags(), name, f) | ||||
| } | ||||
|  | ||||
| // MarkPersistentFlagFilename instructs the various shell completion | ||||
| // implementations to limit completions for this persistent flag to the | ||||
| // specified extensions (patterns). | ||||
| // | ||||
| // Shell Completion compatibility matrix: bash, zsh | ||||
| func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { | ||||
| 	return MarkFlagFilename(c.PersistentFlags(), name, extensions...) | ||||
| } | ||||
|  | ||||
| // MarkFlagFilename instructs the various shell completion implementations to | ||||
| // limit completions for this flag to the specified extensions (patterns). | ||||
| // | ||||
| // Shell Completion compatibility matrix: bash, zsh | ||||
| func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error { | ||||
| 	return flags.SetAnnotation(name, BashCompFilenameExt, extensions) | ||||
| } | ||||
|  | ||||
| // MarkFlagCustom instructs the various shell completion implementations to | ||||
| // limit completions for this flag to the specified extensions (patterns). | ||||
| // | ||||
| // Shell Completion compatibility matrix: bash, zsh | ||||
| func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error { | ||||
| 	return flags.SetAnnotation(name, BashCompCustom, []string{f}) | ||||
| } | ||||
|  | ||||
| // MarkFlagDirname instructs the various shell completion implementations to | ||||
| // complete only directories with this named flag. | ||||
| // | ||||
| // Shell Completion compatibility matrix: zsh | ||||
| func (c *Command) MarkFlagDirname(name string) error { | ||||
| 	return MarkFlagDirname(c.Flags(), name) | ||||
| } | ||||
|  | ||||
| // MarkPersistentFlagDirname instructs the various shell completion | ||||
| // implementations to complete only directories with this persistent named flag. | ||||
| // | ||||
| // Shell Completion compatibility matrix: zsh | ||||
| func (c *Command) MarkPersistentFlagDirname(name string) error { | ||||
| 	return MarkFlagDirname(c.PersistentFlags(), name) | ||||
| } | ||||
|  | ||||
| // MarkFlagDirname instructs the various shell completion implementations to | ||||
| // complete only directories with this specified flag. | ||||
| // | ||||
| // Shell Completion compatibility matrix: zsh | ||||
| func MarkFlagDirname(flags *pflag.FlagSet, name string) error { | ||||
| 	zshPattern := "-(/)" | ||||
| 	return flags.SetAnnotation(name, zshCompDirname, []string{zshPattern}) | ||||
| } | ||||
							
								
								
									
										400
									
								
								vendor/github.com/spf13/cobra/zsh_completions.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										400
									
								
								vendor/github.com/spf13/cobra/zsh_completions.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,13 +1,102 @@ | ||||
| package cobra | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
|  | ||||
| 	"github.com/spf13/pflag" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	zshCompArgumentAnnotation   = "cobra_annotations_zsh_completion_argument_annotation" | ||||
| 	zshCompArgumentFilenameComp = "cobra_annotations_zsh_completion_argument_file_completion" | ||||
| 	zshCompArgumentWordComp     = "cobra_annotations_zsh_completion_argument_word_completion" | ||||
| 	zshCompDirname              = "cobra_annotations_zsh_dirname" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	zshCompFuncMap = template.FuncMap{ | ||||
| 		"genZshFuncName":              zshCompGenFuncName, | ||||
| 		"extractFlags":                zshCompExtractFlag, | ||||
| 		"genFlagEntryForZshArguments": zshCompGenFlagEntryForArguments, | ||||
| 		"extractArgsCompletions":      zshCompExtractArgumentCompletionHintsForRendering, | ||||
| 	} | ||||
| 	zshCompletionText = ` | ||||
| {{/* should accept Command (that contains subcommands) as parameter */}} | ||||
| {{define "argumentsC" -}} | ||||
| {{ $cmdPath := genZshFuncName .}} | ||||
| function {{$cmdPath}} { | ||||
|   local -a commands | ||||
|  | ||||
|   _arguments -C \{{- range extractFlags .}} | ||||
|     {{genFlagEntryForZshArguments .}} \{{- end}} | ||||
|     "1: :->cmnds" \ | ||||
|     "*::arg:->args" | ||||
|  | ||||
|   case $state in | ||||
|   cmnds) | ||||
|     commands=({{range .Commands}}{{if not .Hidden}} | ||||
|       "{{.Name}}:{{.Short}}"{{end}}{{end}} | ||||
|     ) | ||||
|     _describe "command" commands | ||||
|     ;; | ||||
|   esac | ||||
|  | ||||
|   case "$words[1]" in {{- range .Commands}}{{if not .Hidden}} | ||||
|   {{.Name}}) | ||||
|     {{$cmdPath}}_{{.Name}} | ||||
|     ;;{{end}}{{end}} | ||||
|   esac | ||||
| } | ||||
| {{range .Commands}}{{if not .Hidden}} | ||||
| {{template "selectCmdTemplate" .}} | ||||
| {{- end}}{{end}} | ||||
| {{- end}} | ||||
|  | ||||
| {{/* should accept Command without subcommands as parameter */}} | ||||
| {{define "arguments" -}} | ||||
| function {{genZshFuncName .}} { | ||||
| {{"  _arguments"}}{{range extractFlags .}} \ | ||||
|     {{genFlagEntryForZshArguments . -}} | ||||
| {{end}}{{range extractArgsCompletions .}} \ | ||||
|     {{.}}{{end}} | ||||
| } | ||||
| {{end}} | ||||
|  | ||||
| {{/* dispatcher for commands with or without subcommands */}} | ||||
| {{define "selectCmdTemplate" -}} | ||||
| {{if .Hidden}}{{/* ignore hidden*/}}{{else -}} | ||||
| {{if .Commands}}{{template "argumentsC" .}}{{else}}{{template "arguments" .}}{{end}} | ||||
| {{- end}} | ||||
| {{- end}} | ||||
|  | ||||
| {{/* template entry point */}} | ||||
| {{define "Main" -}} | ||||
| #compdef _{{.Name}} {{.Name}} | ||||
|  | ||||
| {{template "selectCmdTemplate" .}} | ||||
| {{end}} | ||||
| ` | ||||
| ) | ||||
|  | ||||
| // zshCompArgsAnnotation is used to encode/decode zsh completion for | ||||
| // arguments to/from Command.Annotations. | ||||
| type zshCompArgsAnnotation map[int]zshCompArgHint | ||||
|  | ||||
| type zshCompArgHint struct { | ||||
| 	// Indicates the type of the completion to use. One of: | ||||
| 	// zshCompArgumentFilenameComp or zshCompArgumentWordComp | ||||
| 	Tipe string `json:"type"` | ||||
|  | ||||
| 	// A value for the type above (globs for file completion or words) | ||||
| 	Options []string `json:"options"` | ||||
| } | ||||
|  | ||||
| // GenZshCompletionFile generates zsh completion file. | ||||
| func (c *Command) GenZshCompletionFile(filename string) error { | ||||
| 	outFile, err := os.Create(filename) | ||||
| @@ -19,108 +108,229 @@ func (c *Command) GenZshCompletionFile(filename string) error { | ||||
| 	return c.GenZshCompletion(outFile) | ||||
| } | ||||
|  | ||||
| // GenZshCompletion generates a zsh completion file and writes to the passed writer. | ||||
| // GenZshCompletion generates a zsh completion file and writes to the passed | ||||
| // writer. The completion always run on the root command regardless of the | ||||
| // command it was called from. | ||||
| func (c *Command) GenZshCompletion(w io.Writer) error { | ||||
| 	buf := new(bytes.Buffer) | ||||
|  | ||||
| 	writeHeader(buf, c) | ||||
| 	maxDepth := maxDepth(c) | ||||
| 	writeLevelMapping(buf, maxDepth) | ||||
| 	writeLevelCases(buf, maxDepth, c) | ||||
|  | ||||
| 	_, err := buf.WriteTo(w) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func writeHeader(w io.Writer, cmd *Command) { | ||||
| 	fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name()) | ||||
| } | ||||
|  | ||||
| func maxDepth(c *Command) int { | ||||
| 	if len(c.Commands()) == 0 { | ||||
| 		return 0 | ||||
| 	tmpl, err := template.New("Main").Funcs(zshCompFuncMap).Parse(zshCompletionText) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("error creating zsh completion template: %v", err) | ||||
| 	} | ||||
| 	maxDepthSub := 0 | ||||
| 	for _, s := range c.Commands() { | ||||
| 		subDepth := maxDepth(s) | ||||
| 		if subDepth > maxDepthSub { | ||||
| 			maxDepthSub = subDepth | ||||
| 	return tmpl.Execute(w, c.Root()) | ||||
| } | ||||
|  | ||||
| // MarkZshCompPositionalArgumentFile marks the specified argument (first | ||||
| // argument is 1) as completed by file selection. patterns (e.g. "*.txt") are | ||||
| // optional - if not provided the completion will search for all files. | ||||
| func (c *Command) MarkZshCompPositionalArgumentFile(argPosition int, patterns ...string) error { | ||||
| 	if argPosition < 1 { | ||||
| 		return fmt.Errorf("Invalid argument position (%d)", argPosition) | ||||
| 	} | ||||
| 	annotation, err := c.zshCompGetArgsAnnotations() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if c.zshcompArgsAnnotationnIsDuplicatePosition(annotation, argPosition) { | ||||
| 		return fmt.Errorf("Duplicate annotation for positional argument at index %d", argPosition) | ||||
| 	} | ||||
| 	annotation[argPosition] = zshCompArgHint{ | ||||
| 		Tipe:    zshCompArgumentFilenameComp, | ||||
| 		Options: patterns, | ||||
| 	} | ||||
| 	return c.zshCompSetArgsAnnotations(annotation) | ||||
| } | ||||
|  | ||||
| // MarkZshCompPositionalArgumentWords marks the specified positional argument | ||||
| // (first argument is 1) as completed by the provided words. At east one word | ||||
| // must be provided, spaces within words will be offered completion with | ||||
| // "word\ word". | ||||
| func (c *Command) MarkZshCompPositionalArgumentWords(argPosition int, words ...string) error { | ||||
| 	if argPosition < 1 { | ||||
| 		return fmt.Errorf("Invalid argument position (%d)", argPosition) | ||||
| 	} | ||||
| 	if len(words) == 0 { | ||||
| 		return fmt.Errorf("Trying to set empty word list for positional argument %d", argPosition) | ||||
| 	} | ||||
| 	annotation, err := c.zshCompGetArgsAnnotations() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if c.zshcompArgsAnnotationnIsDuplicatePosition(annotation, argPosition) { | ||||
| 		return fmt.Errorf("Duplicate annotation for positional argument at index %d", argPosition) | ||||
| 	} | ||||
| 	annotation[argPosition] = zshCompArgHint{ | ||||
| 		Tipe:    zshCompArgumentWordComp, | ||||
| 		Options: words, | ||||
| 	} | ||||
| 	return c.zshCompSetArgsAnnotations(annotation) | ||||
| } | ||||
|  | ||||
| func zshCompExtractArgumentCompletionHintsForRendering(c *Command) ([]string, error) { | ||||
| 	var result []string | ||||
| 	annotation, err := c.zshCompGetArgsAnnotations() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for k, v := range annotation { | ||||
| 		s, err := zshCompRenderZshCompArgHint(k, v) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		result = append(result, s) | ||||
| 	} | ||||
| 	if len(c.ValidArgs) > 0 { | ||||
| 		if _, positionOneExists := annotation[1]; !positionOneExists { | ||||
| 			s, err := zshCompRenderZshCompArgHint(1, zshCompArgHint{ | ||||
| 				Tipe:    zshCompArgumentWordComp, | ||||
| 				Options: c.ValidArgs, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			result = append(result, s) | ||||
| 		} | ||||
| 	} | ||||
| 	return 1 + maxDepthSub | ||||
| 	sort.Strings(result) | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| func writeLevelMapping(w io.Writer, numLevels int) { | ||||
| 	fmt.Fprintln(w, `_arguments \`) | ||||
| 	for i := 1; i <= numLevels; i++ { | ||||
| 		fmt.Fprintf(w, `  '%d: :->level%d' \`, i, i) | ||||
| 		fmt.Fprintln(w) | ||||
| 	} | ||||
| 	fmt.Fprintf(w, `  '%d: :%s'`, numLevels+1, "_files") | ||||
| 	fmt.Fprintln(w) | ||||
| } | ||||
|  | ||||
| func writeLevelCases(w io.Writer, maxDepth int, root *Command) { | ||||
| 	fmt.Fprintln(w, "case $state in") | ||||
| 	defer fmt.Fprintln(w, "esac") | ||||
|  | ||||
| 	for i := 1; i <= maxDepth; i++ { | ||||
| 		fmt.Fprintf(w, "  level%d)\n", i) | ||||
| 		writeLevel(w, root, i) | ||||
| 		fmt.Fprintln(w, "  ;;") | ||||
| 	} | ||||
| 	fmt.Fprintln(w, "  *)") | ||||
| 	fmt.Fprintln(w, "    _arguments '*: :_files'") | ||||
| 	fmt.Fprintln(w, "  ;;") | ||||
| } | ||||
|  | ||||
| func writeLevel(w io.Writer, root *Command, i int) { | ||||
| 	fmt.Fprintf(w, "    case $words[%d] in\n", i) | ||||
| 	defer fmt.Fprintln(w, "    esac") | ||||
|  | ||||
| 	commands := filterByLevel(root, i) | ||||
| 	byParent := groupByParent(commands) | ||||
|  | ||||
| 	for p, c := range byParent { | ||||
| 		names := names(c) | ||||
| 		fmt.Fprintf(w, "      %s)\n", p) | ||||
| 		fmt.Fprintf(w, "        _arguments '%d: :(%s)'\n", i, strings.Join(names, " ")) | ||||
| 		fmt.Fprintln(w, "      ;;") | ||||
| 	} | ||||
| 	fmt.Fprintln(w, "      *)") | ||||
| 	fmt.Fprintln(w, "        _arguments '*: :_files'") | ||||
| 	fmt.Fprintln(w, "      ;;") | ||||
|  | ||||
| } | ||||
|  | ||||
| func filterByLevel(c *Command, l int) []*Command { | ||||
| 	cs := make([]*Command, 0) | ||||
| 	if l == 0 { | ||||
| 		cs = append(cs, c) | ||||
| 		return cs | ||||
| 	} | ||||
| 	for _, s := range c.Commands() { | ||||
| 		cs = append(cs, filterByLevel(s, l-1)...) | ||||
| 	} | ||||
| 	return cs | ||||
| } | ||||
|  | ||||
| func groupByParent(commands []*Command) map[string][]*Command { | ||||
| 	m := make(map[string][]*Command) | ||||
| 	for _, c := range commands { | ||||
| 		parent := c.Parent() | ||||
| 		if parent == nil { | ||||
| 			continue | ||||
| func zshCompRenderZshCompArgHint(i int, z zshCompArgHint) (string, error) { | ||||
| 	switch t := z.Tipe; t { | ||||
| 	case zshCompArgumentFilenameComp: | ||||
| 		var globs []string | ||||
| 		for _, g := range z.Options { | ||||
| 			globs = append(globs, fmt.Sprintf(`-g "%s"`, g)) | ||||
| 		} | ||||
| 		m[parent.Name()] = append(m[parent.Name()], c) | ||||
| 		return fmt.Sprintf(`'%d: :_files %s'`, i, strings.Join(globs, " ")), nil | ||||
| 	case zshCompArgumentWordComp: | ||||
| 		var words []string | ||||
| 		for _, w := range z.Options { | ||||
| 			words = append(words, fmt.Sprintf("%q", w)) | ||||
| 		} | ||||
| 		return fmt.Sprintf(`'%d: :(%s)'`, i, strings.Join(words, " ")), nil | ||||
| 	default: | ||||
| 		return "", fmt.Errorf("Invalid zsh argument completion annotation: %s", t) | ||||
| 	} | ||||
| 	return m | ||||
| } | ||||
|  | ||||
| func names(commands []*Command) []string { | ||||
| 	ns := make([]string, len(commands)) | ||||
| 	for i, c := range commands { | ||||
| 		ns[i] = c.Name() | ||||
| 	} | ||||
| 	return ns | ||||
| func (c *Command) zshcompArgsAnnotationnIsDuplicatePosition(annotation zshCompArgsAnnotation, position int) bool { | ||||
| 	_, dup := annotation[position] | ||||
| 	return dup | ||||
| } | ||||
|  | ||||
| func (c *Command) zshCompGetArgsAnnotations() (zshCompArgsAnnotation, error) { | ||||
| 	annotation := make(zshCompArgsAnnotation) | ||||
| 	annotationString, ok := c.Annotations[zshCompArgumentAnnotation] | ||||
| 	if !ok { | ||||
| 		return annotation, nil | ||||
| 	} | ||||
| 	err := json.Unmarshal([]byte(annotationString), &annotation) | ||||
| 	if err != nil { | ||||
| 		return annotation, fmt.Errorf("Error unmarshaling zsh argument annotation: %v", err) | ||||
| 	} | ||||
| 	return annotation, nil | ||||
| } | ||||
|  | ||||
| func (c *Command) zshCompSetArgsAnnotations(annotation zshCompArgsAnnotation) error { | ||||
| 	jsn, err := json.Marshal(annotation) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("Error marshaling zsh argument annotation: %v", err) | ||||
| 	} | ||||
| 	if c.Annotations == nil { | ||||
| 		c.Annotations = make(map[string]string) | ||||
| 	} | ||||
| 	c.Annotations[zshCompArgumentAnnotation] = string(jsn) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func zshCompGenFuncName(c *Command) string { | ||||
| 	if c.HasParent() { | ||||
| 		return zshCompGenFuncName(c.Parent()) + "_" + c.Name() | ||||
| 	} | ||||
| 	return "_" + c.Name() | ||||
| } | ||||
|  | ||||
| func zshCompExtractFlag(c *Command) []*pflag.Flag { | ||||
| 	var flags []*pflag.Flag | ||||
| 	c.LocalFlags().VisitAll(func(f *pflag.Flag) { | ||||
| 		if !f.Hidden { | ||||
| 			flags = append(flags, f) | ||||
| 		} | ||||
| 	}) | ||||
| 	c.InheritedFlags().VisitAll(func(f *pflag.Flag) { | ||||
| 		if !f.Hidden { | ||||
| 			flags = append(flags, f) | ||||
| 		} | ||||
| 	}) | ||||
| 	return flags | ||||
| } | ||||
|  | ||||
| // zshCompGenFlagEntryForArguments returns an entry that matches _arguments | ||||
| // zsh-completion parameters. It's too complicated to generate in a template. | ||||
| func zshCompGenFlagEntryForArguments(f *pflag.Flag) string { | ||||
| 	if f.Name == "" || f.Shorthand == "" { | ||||
| 		return zshCompGenFlagEntryForSingleOptionFlag(f) | ||||
| 	} | ||||
| 	return zshCompGenFlagEntryForMultiOptionFlag(f) | ||||
| } | ||||
|  | ||||
| func zshCompGenFlagEntryForSingleOptionFlag(f *pflag.Flag) string { | ||||
| 	var option, multiMark, extras string | ||||
|  | ||||
| 	if zshCompFlagCouldBeSpecifiedMoreThenOnce(f) { | ||||
| 		multiMark = "*" | ||||
| 	} | ||||
|  | ||||
| 	option = "--" + f.Name | ||||
| 	if option == "--" { | ||||
| 		option = "-" + f.Shorthand | ||||
| 	} | ||||
| 	extras = zshCompGenFlagEntryExtras(f) | ||||
|  | ||||
| 	return fmt.Sprintf(`'%s%s[%s]%s'`, multiMark, option, zshCompQuoteFlagDescription(f.Usage), extras) | ||||
| } | ||||
|  | ||||
| func zshCompGenFlagEntryForMultiOptionFlag(f *pflag.Flag) string { | ||||
| 	var options, parenMultiMark, curlyMultiMark, extras string | ||||
|  | ||||
| 	if zshCompFlagCouldBeSpecifiedMoreThenOnce(f) { | ||||
| 		parenMultiMark = "*" | ||||
| 		curlyMultiMark = "\\*" | ||||
| 	} | ||||
|  | ||||
| 	options = fmt.Sprintf(`'(%s-%s %s--%s)'{%s-%s,%s--%s}`, | ||||
| 		parenMultiMark, f.Shorthand, parenMultiMark, f.Name, curlyMultiMark, f.Shorthand, curlyMultiMark, f.Name) | ||||
| 	extras = zshCompGenFlagEntryExtras(f) | ||||
|  | ||||
| 	return fmt.Sprintf(`%s'[%s]%s'`, options, zshCompQuoteFlagDescription(f.Usage), extras) | ||||
| } | ||||
|  | ||||
| func zshCompGenFlagEntryExtras(f *pflag.Flag) string { | ||||
| 	if f.NoOptDefVal != "" { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	extras := ":" // allow options for flag (even without assistance) | ||||
| 	for key, values := range f.Annotations { | ||||
| 		switch key { | ||||
| 		case zshCompDirname: | ||||
| 			extras = fmt.Sprintf(":filename:_files -g %q", values[0]) | ||||
| 		case BashCompFilenameExt: | ||||
| 			extras = ":filename:_files" | ||||
| 			for _, pattern := range values { | ||||
| 				extras = extras + fmt.Sprintf(` -g "%s"`, pattern) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return extras | ||||
| } | ||||
|  | ||||
| func zshCompFlagCouldBeSpecifiedMoreThenOnce(f *pflag.Flag) bool { | ||||
| 	return strings.Contains(f.Value.Type(), "Slice") || | ||||
| 		strings.Contains(f.Value.Type(), "Array") | ||||
| } | ||||
|  | ||||
| func zshCompQuoteFlagDescription(s string) string { | ||||
| 	return strings.Replace(s, "'", `'\''`, -1) | ||||
| } | ||||
|   | ||||
							
								
								
									
										39
									
								
								vendor/github.com/spf13/cobra/zsh_completions.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/spf13/cobra/zsh_completions.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| ## Generating Zsh Completion for your cobra.Command | ||||
|  | ||||
| Cobra supports native Zsh completion generated from the root `cobra.Command`. | ||||
| The generated completion script should be put somewhere in your `$fpath` named | ||||
| `_<YOUR COMMAND>`. | ||||
|  | ||||
| ### What's Supported | ||||
|  | ||||
| * Completion for all non-hidden subcommands using their `.Short` description. | ||||
| * Completion for all non-hidden flags using the following rules: | ||||
|   * Filename completion works by marking the flag with `cmd.MarkFlagFilename...` | ||||
|     family of commands. | ||||
|   * The requirement for argument to the flag is decided by the `.NoOptDefVal` | ||||
|     flag value - if it's empty then completion will expect an argument. | ||||
|   * Flags of one of the various `*Array` and `*Slice` types supports multiple | ||||
|     specifications (with or without argument depending on the specific type). | ||||
| * Completion of positional arguments using the following rules: | ||||
|   * Argument position for all options below starts at `1`. If argument position | ||||
|     `0` is requested it will raise an error. | ||||
|   * Use `command.MarkZshCompPositionalArgumentFile` to complete filenames. Glob | ||||
|     patterns (e.g. `"*.log"`) are optional - if not specified it will offer to | ||||
|     complete all file types. | ||||
|   * Use `command.MarkZshCompPositionalArgumentWords` to offer specific words for | ||||
|     completion. At least one word is required. | ||||
|   * It's possible to specify completion for some arguments and leave some | ||||
|     unspecified (e.g. offer words for second argument but nothing for first | ||||
|     argument). This will cause no completion for first argument but words | ||||
|     completion for second argument. | ||||
|   * If no argument completion was specified for 1st argument (but optionally was | ||||
|     specified for 2nd) and the command has `ValidArgs` it will be used as | ||||
|     completion options for 1st argument. | ||||
|   * Argument completions only offered for commands with no subcommands. | ||||
|  | ||||
| ### What's not yet Supported | ||||
|  | ||||
| * Custom completion scripts are not supported yet (We should probably create zsh | ||||
|   specific one, doesn't make sense to re-use the bash one as the functions will | ||||
|   be different). | ||||
| * Whatever other feature you're looking for and doesn't exist :) | ||||
							
								
								
									
										9
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							| @@ -32,7 +32,7 @@ github.com/agl/ed25519 | ||||
| github.com/agl/ed25519/edwards25519 | ||||
| # github.com/apparentlymart/go-textseg/v12 v12.0.0 | ||||
| github.com/apparentlymart/go-textseg/v12/textseg | ||||
| # github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 | ||||
| # github.com/beorn7/perks v1.0.0 | ||||
| github.com/beorn7/perks/quantile | ||||
| # github.com/containerd/cgroups v0.0.0-20200217135630-d732e370d46d | ||||
| github.com/containerd/cgroups/stats/v1 | ||||
| @@ -291,12 +291,13 @@ github.com/opentracing/opentracing-go/log | ||||
| github.com/pkg/errors | ||||
| # github.com/pmezard/go-difflib v1.0.0 | ||||
| github.com/pmezard/go-difflib/difflib | ||||
| # github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06 | ||||
| # github.com/prometheus/client_golang v0.9.3 | ||||
| github.com/prometheus/client_golang/prometheus | ||||
| github.com/prometheus/client_golang/prometheus/internal | ||||
| github.com/prometheus/client_golang/prometheus/promhttp | ||||
| # github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 | ||||
| github.com/prometheus/client_model/go | ||||
| # github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 | ||||
| # github.com/prometheus/common v0.4.0 | ||||
| github.com/prometheus/common/expfmt | ||||
| github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg | ||||
| github.com/prometheus/common/model | ||||
| @@ -308,7 +309,7 @@ github.com/prometheus/procfs/internal/util | ||||
| github.com/serialx/hashring | ||||
| # github.com/sirupsen/logrus v1.4.2 | ||||
| github.com/sirupsen/logrus | ||||
| # github.com/spf13/cobra v0.0.3 | ||||
| # github.com/spf13/cobra v1.0.0 | ||||
| github.com/spf13/cobra | ||||
| # github.com/spf13/pflag v1.0.5 | ||||
| github.com/spf13/pflag | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sebastiaan van Stijn
					Sebastiaan van Stijn