diff --git a/vendor/github.com/Sirupsen/logrus/.gitignore b/vendor/github.com/Sirupsen/logrus/.gitignore
new file mode 100644
index 0000000..66be63a
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/.gitignore
@@ -0,0 +1 @@
+logrus
diff --git a/vendor/github.com/Sirupsen/logrus/.travis.yml b/vendor/github.com/Sirupsen/logrus/.travis.yml
new file mode 100644
index 0000000..dee4eb2
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+go:
+ - 1.3
+ - 1.4
+ - 1.5
+ - 1.6
+ - tip
+install:
+ - go get -t ./...
+script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...
diff --git a/vendor/github.com/Sirupsen/logrus/CHANGELOG.md b/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
new file mode 100644
index 0000000..f2c2bc2
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
@@ -0,0 +1,66 @@
+# 0.10.0
+
+* feature: Add a test hook (#180)
+* feature: `ParseLevel` is now case-insensitive (#326)
+* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
+* performance: avoid re-allocations on `WithFields` (#335)
+
+# 0.9.0
+
+* logrus/text_formatter: don't emit empty msg
+* logrus/hooks/airbrake: move out of main repository
+* logrus/hooks/sentry: move out of main repository
+* logrus/hooks/papertrail: move out of main repository
+* logrus/hooks/bugsnag: move out of main repository
+* logrus/core: run tests with `-race`
+* logrus/core: detect TTY based on `stderr`
+* logrus/core: support `WithError` on logger
+* logrus/core: Solaris support
+
+# 0.8.7
+
+* logrus/core: fix possible race (#216)
+* logrus/doc: small typo fixes and doc improvements
+
+
+# 0.8.6
+
+* hooks/raven: allow passing an initialized client
+
+# 0.8.5
+
+* logrus/core: revert #208
+
+# 0.8.4
+
+* formatter/text: fix data race (#218)
+
+# 0.8.3
+
+* logrus/core: fix entry log level (#208)
+* logrus/core: improve performance of text formatter by 40%
+* logrus/core: expose `LevelHooks` type
+* logrus/core: add support for DragonflyBSD and NetBSD
+* formatter/text: print structs more verbosely
+
+# 0.8.2
+
+* logrus: fix more Fatal family functions
+
+# 0.8.1
+
+* logrus: fix not exiting on `Fatalf` and `Fatalln`
+
+# 0.8.0
+
+* logrus: defaults to stderr instead of stdout
+* hooks/sentry: add special field for `*http.Request`
+* formatter/text: ignore Windows for colors
+
+# 0.7.3
+
+* formatter/\*: allow configuration of timestamp layout
+
+# 0.7.2
+
+* formatter/text: Add configuration option for time format (#158)
diff --git a/vendor/github.com/Sirupsen/logrus/LICENSE b/vendor/github.com/Sirupsen/logrus/LICENSE
new file mode 100644
index 0000000..f090cb4
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Simon Eskildsen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/Sirupsen/logrus/README.md b/vendor/github.com/Sirupsen/logrus/README.md
new file mode 100644
index 0000000..6f04c8a
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/README.md
@@ -0,0 +1,390 @@
+# Logrus
[](https://travis-ci.org/Sirupsen/logrus) [](https://godoc.org/github.com/Sirupsen/logrus)
+
+Logrus is a structured logger for Go (golang), completely API compatible with
+the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
+yet stable (pre 1.0). Logrus itself is completely stable and has been used in
+many large deployments. The core API is unlikely to change much but please
+version control your Logrus to make sure you aren't fetching latest `master` on
+every build.**
+
+Nicely color-coded in development (when a TTY is attached, otherwise just
+plain text):
+
+
+
+With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
+or Splunk:
+
+```json
+{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
+ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
+
+{"level":"warning","msg":"The group's number increased tremendously!",
+"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
+
+{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
+"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
+
+{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
+"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
+
+{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
+"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
+```
+
+With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
+attached, the output is compatible with the
+[logfmt](http://godoc.org/github.com/kr/logfmt) format:
+
+```text
+time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
+time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
+time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
+time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
+time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
+time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
+exit status 1
+```
+
+#### Example
+
+The simplest way to use Logrus is simply the package-level exported logger:
+
+```go
+package main
+
+import (
+ log "github.com/Sirupsen/logrus"
+)
+
+func main() {
+ log.WithFields(log.Fields{
+ "animal": "walrus",
+ }).Info("A walrus appears")
+}
+```
+
+Note that it's completely api-compatible with the stdlib logger, so you can
+replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
+and you'll now have the flexibility of Logrus. You can customize it all you
+want:
+
+```go
+package main
+
+import (
+ "os"
+ log "github.com/Sirupsen/logrus"
+)
+
+func init() {
+ // Log as JSON instead of the default ASCII formatter.
+ log.SetFormatter(&log.JSONFormatter{})
+
+ // Output to stderr instead of stdout, could also be a file.
+ log.SetOutput(os.Stderr)
+
+ // Only log the warning severity or above.
+ log.SetLevel(log.WarnLevel)
+}
+
+func main() {
+ log.WithFields(log.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+
+ log.WithFields(log.Fields{
+ "omg": true,
+ "number": 122,
+ }).Warn("The group's number increased tremendously!")
+
+ log.WithFields(log.Fields{
+ "omg": true,
+ "number": 100,
+ }).Fatal("The ice breaks!")
+
+ // A common pattern is to re-use fields between logging statements by re-using
+ // the logrus.Entry returned from WithFields()
+ contextLogger := log.WithFields(log.Fields{
+ "common": "this is a common field",
+ "other": "I also should be logged always",
+ })
+
+ contextLogger.Info("I'll be logged with common and other field")
+ contextLogger.Info("Me too")
+}
+```
+
+For more advanced usage such as logging to multiple locations from the same
+application, you can also create an instance of the `logrus` Logger:
+
+```go
+package main
+
+import (
+ "github.com/Sirupsen/logrus"
+)
+
+// Create a new instance of the logger. You can have any number of instances.
+var log = logrus.New()
+
+func main() {
+ // The API for setting attributes is a little different than the package level
+ // exported logger. See Godoc.
+ log.Out = os.Stderr
+
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+}
+```
+
+#### Fields
+
+Logrus encourages careful, structured logging though logging fields instead of
+long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
+to send event %s to topic %s with key %d")`, you should log the much more
+discoverable:
+
+```go
+log.WithFields(log.Fields{
+ "event": event,
+ "topic": topic,
+ "key": key,
+}).Fatal("Failed to send event")
+```
+
+We've found this API forces you to think about logging in a way that produces
+much more useful logging messages. We've been in countless situations where just
+a single added field to a log statement that was already there would've saved us
+hours. The `WithFields` call is optional.
+
+In general, with Logrus using any of the `printf`-family functions should be
+seen as a hint you should add a field, however, you can still use the
+`printf`-family functions with Logrus.
+
+#### Hooks
+
+You can add hooks for logging levels. For example to send errors to an exception
+tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
+multiple places simultaneously, e.g. syslog.
+
+Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
+`init`:
+
+```go
+import (
+ log "github.com/Sirupsen/logrus"
+ "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+ "log/syslog"
+)
+
+func init() {
+
+ // Use the Airbrake hook to report errors that have Error severity or above to
+ // an exception tracker. You can create custom hooks, see the Hooks section.
+ log.AddHook(airbrake.NewHook(123, "xyz", "production"))
+
+ hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+ if err != nil {
+ log.Error("Unable to connect to local syslog daemon")
+ } else {
+ log.AddHook(hook)
+ }
+}
+```
+Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
+
+| Hook | Description |
+| ----- | ----------- |
+| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
+| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
+| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
+| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
+| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
+| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
+| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
+| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
+| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
+| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
+| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
+| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
+| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
+| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
+| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
+| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
+| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
+| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
+| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) |
+| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
+| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
+| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
+| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
+| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
+| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
+| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
+| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
+| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
+| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
+
+#### Level logging
+
+Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
+
+```go
+log.Debug("Useful debugging information.")
+log.Info("Something noteworthy happened!")
+log.Warn("You should probably take a look at this.")
+log.Error("Something failed but I'm not quitting.")
+// Calls os.Exit(1) after logging
+log.Fatal("Bye.")
+// Calls panic() after logging
+log.Panic("I'm bailing.")
+```
+
+You can set the logging level on a `Logger`, then it will only log entries with
+that severity or anything above it:
+
+```go
+// Will log anything that is info or above (warn, error, fatal, panic). Default.
+log.SetLevel(log.InfoLevel)
+```
+
+It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
+environment if your application has that.
+
+#### Entries
+
+Besides the fields added with `WithField` or `WithFields` some fields are
+automatically added to all logging events:
+
+1. `time`. The timestamp when the entry was created.
+2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
+ the `AddFields` call. E.g. `Failed to send event.`
+3. `level`. The logging level. E.g. `info`.
+
+#### Environments
+
+Logrus has no notion of environment.
+
+If you wish for hooks and formatters to only be used in specific environments,
+you should handle that yourself. For example, if your application has a global
+variable `Environment`, which is a string representation of the environment you
+could do:
+
+```go
+import (
+ log "github.com/Sirupsen/logrus"
+)
+
+init() {
+ // do something here to set environment depending on an environment variable
+ // or command-line flag
+ if Environment == "production" {
+ log.SetFormatter(&log.JSONFormatter{})
+ } else {
+ // The TextFormatter is default, you don't actually have to do this.
+ log.SetFormatter(&log.TextFormatter{})
+ }
+}
+```
+
+This configuration is how `logrus` was intended to be used, but JSON in
+production is mostly only useful if you do log aggregation with tools like
+Splunk or Logstash.
+
+#### Formatters
+
+The built-in logging formatters are:
+
+* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
+ without colors.
+ * *Note:* to force colored output when there is no TTY, set the `ForceColors`
+ field to `true`. To force no colored output even if there is a TTY set the
+ `DisableColors` field to `true`
+* `logrus.JSONFormatter`. Logs fields as JSON.
+* `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events.
+
+ ```go
+ logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"})
+ ```
+
+Third party logging formatters:
+
+* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
+* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
+
+You can define your formatter by implementing the `Formatter` interface,
+requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
+`Fields` type (`map[string]interface{}`) with all your fields as well as the
+default ones (see Entries section above):
+
+```go
+type MyJSONFormatter struct {
+}
+
+log.SetFormatter(new(MyJSONFormatter))
+
+func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
+ // Note this doesn't include Time, Level and Message which are available on
+ // the Entry. Consult `godoc` on information about those fields or read the
+ // source of the official loggers.
+ serialized, err := json.Marshal(entry.Data)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+ }
+ return append(serialized, '\n'), nil
+}
+```
+
+#### Logger as an `io.Writer`
+
+Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
+
+```go
+w := logger.Writer()
+defer w.Close()
+
+srv := http.Server{
+ // create a stdlib log.Logger that writes to
+ // logrus.Logger.
+ ErrorLog: log.New(w, "", 0),
+}
+```
+
+Each line written to that writer will be printed the usual way, using formatters
+and hooks. The level for those entries is `info`.
+
+#### Rotation
+
+Log rotation is not provided with Logrus. Log rotation should be done by an
+external program (like `logrotate(8)`) that can compress and delete old log
+entries. It should not be a feature of the application-level logger.
+
+#### Tools
+
+| Tool | Description |
+| ---- | ----------- |
+|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
+
+#### Testing
+
+Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
+
+* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
+* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
+
+```go
+logger, hook := NewNullLogger()
+logger.Error("Hello error")
+
+assert.Equal(1, len(hook.Entries))
+assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+assert.Equal("Hello error", hook.LastEntry().Message)
+
+hook.Reset()
+assert.Nil(hook.LastEntry())
+```
diff --git a/vendor/github.com/Sirupsen/logrus/doc.go b/vendor/github.com/Sirupsen/logrus/doc.go
new file mode 100644
index 0000000..dddd5f8
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/doc.go
@@ -0,0 +1,26 @@
+/*
+Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
+
+
+The simplest way to use Logrus is simply the package-level exported logger:
+
+ package main
+
+ import (
+ log "github.com/Sirupsen/logrus"
+ )
+
+ func main() {
+ log.WithFields(log.Fields{
+ "animal": "walrus",
+ "number": 1,
+ "size": 10,
+ }).Info("A walrus appears")
+ }
+
+Output:
+ time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
+
+For a full guide visit https://github.com/Sirupsen/logrus
+*/
+package logrus
diff --git a/vendor/github.com/Sirupsen/logrus/entry.go b/vendor/github.com/Sirupsen/logrus/entry.go
new file mode 100644
index 0000000..89e966e
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/entry.go
@@ -0,0 +1,264 @@
+package logrus
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "time"
+)
+
+// Defines the key when adding errors using WithError.
+var ErrorKey = "error"
+
+// An entry is the final or intermediate Logrus logging entry. It contains all
+// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
+// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
+// passed around as much as you wish to avoid field duplication.
+type Entry struct {
+ Logger *Logger
+
+ // Contains all the fields set by the user.
+ Data Fields
+
+ // Time at which the log entry was created
+ Time time.Time
+
+ // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
+ Level Level
+
+ // Message passed to Debug, Info, Warn, Error, Fatal or Panic
+ Message string
+}
+
+func NewEntry(logger *Logger) *Entry {
+ return &Entry{
+ Logger: logger,
+ // Default is three fields, give a little extra room
+ Data: make(Fields, 5),
+ }
+}
+
+// Returns a reader for the entry, which is a proxy to the formatter.
+func (entry *Entry) Reader() (*bytes.Buffer, error) {
+ serialized, err := entry.Logger.Formatter.Format(entry)
+ return bytes.NewBuffer(serialized), err
+}
+
+// Returns the string representation from the reader and ultimately the
+// formatter.
+func (entry *Entry) String() (string, error) {
+ reader, err := entry.Reader()
+ if err != nil {
+ return "", err
+ }
+
+ return reader.String(), err
+}
+
+// Add an error as single field (using the key defined in ErrorKey) to the Entry.
+func (entry *Entry) WithError(err error) *Entry {
+ return entry.WithField(ErrorKey, err)
+}
+
+// Add a single field to the Entry.
+func (entry *Entry) WithField(key string, value interface{}) *Entry {
+ return entry.WithFields(Fields{key: value})
+}
+
+// Add a map of fields to the Entry.
+func (entry *Entry) WithFields(fields Fields) *Entry {
+ data := make(Fields, len(entry.Data)+len(fields))
+ for k, v := range entry.Data {
+ data[k] = v
+ }
+ for k, v := range fields {
+ data[k] = v
+ }
+ return &Entry{Logger: entry.Logger, Data: data}
+}
+
+// This function is not declared with a pointer value because otherwise
+// race conditions will occur when using multiple goroutines
+func (entry Entry) log(level Level, msg string) {
+ entry.Time = time.Now()
+ entry.Level = level
+ entry.Message = msg
+
+ if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
+ entry.Logger.mu.Lock()
+ fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
+ entry.Logger.mu.Unlock()
+ }
+
+ reader, err := entry.Reader()
+ if err != nil {
+ entry.Logger.mu.Lock()
+ fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
+ entry.Logger.mu.Unlock()
+ }
+
+ entry.Logger.mu.Lock()
+ defer entry.Logger.mu.Unlock()
+
+ _, err = io.Copy(entry.Logger.Out, reader)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
+ }
+
+ // To avoid Entry#log() returning a value that only would make sense for
+ // panic() to use in Entry#Panic(), we avoid the allocation by checking
+ // directly here.
+ if level <= PanicLevel {
+ panic(&entry)
+ }
+}
+
+func (entry *Entry) Debug(args ...interface{}) {
+ if entry.Logger.Level >= DebugLevel {
+ entry.log(DebugLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Print(args ...interface{}) {
+ entry.Info(args...)
+}
+
+func (entry *Entry) Info(args ...interface{}) {
+ if entry.Logger.Level >= InfoLevel {
+ entry.log(InfoLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Warn(args ...interface{}) {
+ if entry.Logger.Level >= WarnLevel {
+ entry.log(WarnLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Warning(args ...interface{}) {
+ entry.Warn(args...)
+}
+
+func (entry *Entry) Error(args ...interface{}) {
+ if entry.Logger.Level >= ErrorLevel {
+ entry.log(ErrorLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Fatal(args ...interface{}) {
+ if entry.Logger.Level >= FatalLevel {
+ entry.log(FatalLevel, fmt.Sprint(args...))
+ }
+ os.Exit(1)
+}
+
+func (entry *Entry) Panic(args ...interface{}) {
+ if entry.Logger.Level >= PanicLevel {
+ entry.log(PanicLevel, fmt.Sprint(args...))
+ }
+ panic(fmt.Sprint(args...))
+}
+
+// Entry Printf family functions
+
+func (entry *Entry) Debugf(format string, args ...interface{}) {
+ if entry.Logger.Level >= DebugLevel {
+ entry.Debug(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Infof(format string, args ...interface{}) {
+ if entry.Logger.Level >= InfoLevel {
+ entry.Info(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Printf(format string, args ...interface{}) {
+ entry.Infof(format, args...)
+}
+
+func (entry *Entry) Warnf(format string, args ...interface{}) {
+ if entry.Logger.Level >= WarnLevel {
+ entry.Warn(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Warningf(format string, args ...interface{}) {
+ entry.Warnf(format, args...)
+}
+
+func (entry *Entry) Errorf(format string, args ...interface{}) {
+ if entry.Logger.Level >= ErrorLevel {
+ entry.Error(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Fatalf(format string, args ...interface{}) {
+ if entry.Logger.Level >= FatalLevel {
+ entry.Fatal(fmt.Sprintf(format, args...))
+ }
+ os.Exit(1)
+}
+
+func (entry *Entry) Panicf(format string, args ...interface{}) {
+ if entry.Logger.Level >= PanicLevel {
+ entry.Panic(fmt.Sprintf(format, args...))
+ }
+}
+
+// Entry Println family functions
+
+func (entry *Entry) Debugln(args ...interface{}) {
+ if entry.Logger.Level >= DebugLevel {
+ entry.Debug(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Infoln(args ...interface{}) {
+ if entry.Logger.Level >= InfoLevel {
+ entry.Info(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Println(args ...interface{}) {
+ entry.Infoln(args...)
+}
+
+func (entry *Entry) Warnln(args ...interface{}) {
+ if entry.Logger.Level >= WarnLevel {
+ entry.Warn(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Warningln(args ...interface{}) {
+ entry.Warnln(args...)
+}
+
+func (entry *Entry) Errorln(args ...interface{}) {
+ if entry.Logger.Level >= ErrorLevel {
+ entry.Error(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Fatalln(args ...interface{}) {
+ if entry.Logger.Level >= FatalLevel {
+ entry.Fatal(entry.sprintlnn(args...))
+ }
+ os.Exit(1)
+}
+
+func (entry *Entry) Panicln(args ...interface{}) {
+ if entry.Logger.Level >= PanicLevel {
+ entry.Panic(entry.sprintlnn(args...))
+ }
+}
+
+// Sprintlnn => Sprint no newline. This is to get the behavior of how
+// fmt.Sprintln where spaces are always added between operands, regardless of
+// their type. Instead of vendoring the Sprintln implementation to spare a
+// string allocation, we do the simplest thing.
+func (entry *Entry) sprintlnn(args ...interface{}) string {
+ msg := fmt.Sprintln(args...)
+ return msg[:len(msg)-1]
+}
diff --git a/vendor/github.com/Sirupsen/logrus/entry_test.go b/vendor/github.com/Sirupsen/logrus/entry_test.go
new file mode 100644
index 0000000..99c3b41
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/entry_test.go
@@ -0,0 +1,77 @@
+package logrus
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestEntryWithError(t *testing.T) {
+
+ assert := assert.New(t)
+
+ defer func() {
+ ErrorKey = "error"
+ }()
+
+ err := fmt.Errorf("kaboom at layer %d", 4711)
+
+ assert.Equal(err, WithError(err).Data["error"])
+
+ logger := New()
+ logger.Out = &bytes.Buffer{}
+ entry := NewEntry(logger)
+
+ assert.Equal(err, entry.WithError(err).Data["error"])
+
+ ErrorKey = "err"
+
+ assert.Equal(err, entry.WithError(err).Data["err"])
+
+}
+
+func TestEntryPanicln(t *testing.T) {
+ errBoom := fmt.Errorf("boom time")
+
+ defer func() {
+ p := recover()
+ assert.NotNil(t, p)
+
+ switch pVal := p.(type) {
+ case *Entry:
+ assert.Equal(t, "kaboom", pVal.Message)
+ assert.Equal(t, errBoom, pVal.Data["err"])
+ default:
+ t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
+ }
+ }()
+
+ logger := New()
+ logger.Out = &bytes.Buffer{}
+ entry := NewEntry(logger)
+ entry.WithField("err", errBoom).Panicln("kaboom")
+}
+
+func TestEntryPanicf(t *testing.T) {
+ errBoom := fmt.Errorf("boom again")
+
+ defer func() {
+ p := recover()
+ assert.NotNil(t, p)
+
+ switch pVal := p.(type) {
+ case *Entry:
+ assert.Equal(t, "kaboom true", pVal.Message)
+ assert.Equal(t, errBoom, pVal.Data["err"])
+ default:
+ t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
+ }
+ }()
+
+ logger := New()
+ logger.Out = &bytes.Buffer{}
+ entry := NewEntry(logger)
+ entry.WithField("err", errBoom).Panicf("kaboom %v", true)
+}
diff --git a/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go b/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
new file mode 100644
index 0000000..a1623ec
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+ "github.com/Sirupsen/logrus"
+)
+
+var log = logrus.New()
+
+func init() {
+ log.Formatter = new(logrus.JSONFormatter)
+ log.Formatter = new(logrus.TextFormatter) // default
+ log.Level = logrus.DebugLevel
+}
+
+func main() {
+ defer func() {
+ err := recover()
+ if err != nil {
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "err": err,
+ "number": 100,
+ }).Fatal("The ice breaks!")
+ }
+ }()
+
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "number": 8,
+ }).Debug("Started observing beach")
+
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "number": 122,
+ }).Warn("The group's number increased tremendously!")
+
+ log.WithFields(logrus.Fields{
+ "temperature": -4,
+ }).Debug("Temperature changes")
+
+ log.WithFields(logrus.Fields{
+ "animal": "orca",
+ "size": 9009,
+ }).Panic("It's over 9000!")
+}
diff --git a/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go b/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
new file mode 100644
index 0000000..3187f6d
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+ "github.com/Sirupsen/logrus"
+ "gopkg.in/gemnasium/logrus-airbrake-hook.v2"
+)
+
+var log = logrus.New()
+
+func init() {
+ log.Formatter = new(logrus.TextFormatter) // default
+ log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
+}
+
+func main() {
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "number": 122,
+ }).Warn("The group's number increased tremendously!")
+
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "number": 100,
+ }).Fatal("The ice breaks!")
+}
diff --git a/vendor/github.com/Sirupsen/logrus/exported.go b/vendor/github.com/Sirupsen/logrus/exported.go
new file mode 100644
index 0000000..9a0120a
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/exported.go
@@ -0,0 +1,193 @@
+package logrus
+
+import (
+ "io"
+)
+
+var (
+ // std is the name of the standard logger in stdlib `log`
+ std = New()
+)
+
+func StandardLogger() *Logger {
+ return std
+}
+
+// SetOutput sets the standard logger output.
+func SetOutput(out io.Writer) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Out = out
+}
+
+// SetFormatter sets the standard logger formatter.
+func SetFormatter(formatter Formatter) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Formatter = formatter
+}
+
+// SetLevel sets the standard logger level.
+func SetLevel(level Level) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Level = level
+}
+
+// GetLevel returns the standard logger level.
+func GetLevel() Level {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ return std.Level
+}
+
+// AddHook adds a hook to the standard logger hooks.
+func AddHook(hook Hook) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Hooks.Add(hook)
+}
+
+// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
+func WithError(err error) *Entry {
+ return std.WithField(ErrorKey, err)
+}
+
+// WithField creates an entry from the standard logger and adds a field to
+// it. If you want multiple fields, use `WithFields`.
+//
+// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
+// or Panic on the Entry it returns.
+func WithField(key string, value interface{}) *Entry {
+ return std.WithField(key, value)
+}
+
+// WithFields creates an entry from the standard logger and adds multiple
+// fields to it. This is simply a helper for `WithField`, invoking it
+// once for each field.
+//
+// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
+// or Panic on the Entry it returns.
+func WithFields(fields Fields) *Entry {
+ return std.WithFields(fields)
+}
+
+// Debug logs a message at level Debug on the standard logger.
+func Debug(args ...interface{}) {
+ std.Debug(args...)
+}
+
+// Print logs a message at level Info on the standard logger.
+func Print(args ...interface{}) {
+ std.Print(args...)
+}
+
+// Info logs a message at level Info on the standard logger.
+func Info(args ...interface{}) {
+ std.Info(args...)
+}
+
+// Warn logs a message at level Warn on the standard logger.
+func Warn(args ...interface{}) {
+ std.Warn(args...)
+}
+
+// Warning logs a message at level Warn on the standard logger.
+func Warning(args ...interface{}) {
+ std.Warning(args...)
+}
+
+// Error logs a message at level Error on the standard logger.
+func Error(args ...interface{}) {
+ std.Error(args...)
+}
+
+// Panic logs a message at level Panic on the standard logger.
+func Panic(args ...interface{}) {
+ std.Panic(args...)
+}
+
+// Fatal logs a message at level Fatal on the standard logger.
+func Fatal(args ...interface{}) {
+ std.Fatal(args...)
+}
+
+// Debugf logs a message at level Debug on the standard logger.
+func Debugf(format string, args ...interface{}) {
+ std.Debugf(format, args...)
+}
+
+// Printf logs a message at level Info on the standard logger.
+func Printf(format string, args ...interface{}) {
+ std.Printf(format, args...)
+}
+
+// Infof logs a message at level Info on the standard logger.
+func Infof(format string, args ...interface{}) {
+ std.Infof(format, args...)
+}
+
+// Warnf logs a message at level Warn on the standard logger.
+func Warnf(format string, args ...interface{}) {
+ std.Warnf(format, args...)
+}
+
+// Warningf logs a message at level Warn on the standard logger.
+func Warningf(format string, args ...interface{}) {
+ std.Warningf(format, args...)
+}
+
+// Errorf logs a message at level Error on the standard logger.
+func Errorf(format string, args ...interface{}) {
+ std.Errorf(format, args...)
+}
+
+// Panicf logs a message at level Panic on the standard logger.
+func Panicf(format string, args ...interface{}) {
+ std.Panicf(format, args...)
+}
+
+// Fatalf logs a message at level Fatal on the standard logger.
+func Fatalf(format string, args ...interface{}) {
+ std.Fatalf(format, args...)
+}
+
+// Debugln logs a message at level Debug on the standard logger.
+func Debugln(args ...interface{}) {
+ std.Debugln(args...)
+}
+
+// Println logs a message at level Info on the standard logger.
+func Println(args ...interface{}) {
+ std.Println(args...)
+}
+
+// Infoln logs a message at level Info on the standard logger.
+func Infoln(args ...interface{}) {
+ std.Infoln(args...)
+}
+
+// Warnln logs a message at level Warn on the standard logger.
+func Warnln(args ...interface{}) {
+ std.Warnln(args...)
+}
+
+// Warningln logs a message at level Warn on the standard logger.
+func Warningln(args ...interface{}) {
+ std.Warningln(args...)
+}
+
+// Errorln logs a message at level Error on the standard logger.
+func Errorln(args ...interface{}) {
+ std.Errorln(args...)
+}
+
+// Panicln logs a message at level Panic on the standard logger.
+func Panicln(args ...interface{}) {
+ std.Panicln(args...)
+}
+
+// Fatalln logs a message at level Fatal on the standard logger.
+func Fatalln(args ...interface{}) {
+ std.Fatalln(args...)
+}
diff --git a/vendor/github.com/Sirupsen/logrus/formatter.go b/vendor/github.com/Sirupsen/logrus/formatter.go
new file mode 100644
index 0000000..b5fbe93
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/formatter.go
@@ -0,0 +1,45 @@
+package logrus
+
+import "time"
+
+const DefaultTimestampFormat = time.RFC3339
+
+// The Formatter interface is used to implement a custom Formatter. It takes an
+// `Entry`. It exposes all the fields, including the default ones:
+//
+// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
+// * `entry.Data["time"]`. The timestamp.
+// * `entry.Data["level"]. The level the entry was logged at.
+//
+// Any additional fields added with `WithField` or `WithFields` are also in
+// `entry.Data`. Format is expected to return an array of bytes which are then
+// logged to `logger.Out`.
+type Formatter interface {
+ Format(*Entry) ([]byte, error)
+}
+
+// This is to not silently overwrite `time`, `msg` and `level` fields when
+// dumping it. If this code wasn't there doing:
+//
+// logrus.WithField("level", 1).Info("hello")
+//
+// Would just silently drop the user provided level. Instead with this code
+// it'll logged as:
+//
+// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
+//
+// It's not exported because it's still using Data in an opinionated way. It's to
+// avoid code duplication between the two default formatters.
+func prefixFieldClashes(data Fields) {
+ if t, ok := data["time"]; ok {
+ data["fields.time"] = t
+ }
+
+ if m, ok := data["msg"]; ok {
+ data["fields.msg"] = m
+ }
+
+ if l, ok := data["level"]; ok {
+ data["fields.level"] = l
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go b/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
new file mode 100644
index 0000000..c6d290c
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
@@ -0,0 +1,98 @@
+package logrus
+
+import (
+ "fmt"
+ "testing"
+ "time"
+)
+
+// smallFields is a small size data set for benchmarking
+var smallFields = Fields{
+ "foo": "bar",
+ "baz": "qux",
+ "one": "two",
+ "three": "four",
+}
+
+// largeFields is a large size data set for benchmarking
+var largeFields = Fields{
+ "foo": "bar",
+ "baz": "qux",
+ "one": "two",
+ "three": "four",
+ "five": "six",
+ "seven": "eight",
+ "nine": "ten",
+ "eleven": "twelve",
+ "thirteen": "fourteen",
+ "fifteen": "sixteen",
+ "seventeen": "eighteen",
+ "nineteen": "twenty",
+ "a": "b",
+ "c": "d",
+ "e": "f",
+ "g": "h",
+ "i": "j",
+ "k": "l",
+ "m": "n",
+ "o": "p",
+ "q": "r",
+ "s": "t",
+ "u": "v",
+ "w": "x",
+ "y": "z",
+ "this": "will",
+ "make": "thirty",
+ "entries": "yeah",
+}
+
+var errorFields = Fields{
+ "foo": fmt.Errorf("bar"),
+ "baz": fmt.Errorf("qux"),
+}
+
+func BenchmarkErrorTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields)
+}
+
+func BenchmarkSmallTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
+}
+
+func BenchmarkLargeTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
+}
+
+func BenchmarkSmallColoredTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
+}
+
+func BenchmarkLargeColoredTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
+}
+
+func BenchmarkSmallJSONFormatter(b *testing.B) {
+ doBenchmark(b, &JSONFormatter{}, smallFields)
+}
+
+func BenchmarkLargeJSONFormatter(b *testing.B) {
+ doBenchmark(b, &JSONFormatter{}, largeFields)
+}
+
+func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
+ entry := &Entry{
+ Time: time.Time{},
+ Level: InfoLevel,
+ Message: "message",
+ Data: fields,
+ }
+ var d []byte
+ var err error
+ for i := 0; i < b.N; i++ {
+ d, err = formatter.Format(entry)
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.SetBytes(int64(len(d)))
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go b/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
new file mode 100644
index 0000000..2793af8
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
@@ -0,0 +1,63 @@
+package logstash
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/Sirupsen/logrus"
+)
+
+// Formatter generates json in logstash format.
+// Logstash site: http://logstash.net/
+type LogstashFormatter struct {
+ Type string // if not empty use for logstash type field.
+
+ // TimestampFormat sets the format used for timestamps.
+ TimestampFormat string
+}
+
+func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) {
+ fields := make(logrus.Fields)
+ for k, v := range entry.Data {
+ fields[k] = v
+ }
+
+ fields["@version"] = 1
+
+ timeStampFormat := f.TimestampFormat
+
+ if timeStampFormat == "" {
+ timeStampFormat = logrus.DefaultTimestampFormat
+ }
+
+ fields["@timestamp"] = entry.Time.Format(timeStampFormat)
+
+ // set message field
+ v, ok := entry.Data["message"]
+ if ok {
+ fields["fields.message"] = v
+ }
+ fields["message"] = entry.Message
+
+ // set level field
+ v, ok = entry.Data["level"]
+ if ok {
+ fields["fields.level"] = v
+ }
+ fields["level"] = entry.Level.String()
+
+ // set type field
+ if f.Type != "" {
+ v, ok = entry.Data["type"]
+ if ok {
+ fields["fields.type"] = v
+ }
+ fields["type"] = f.Type
+ }
+
+ serialized, err := json.Marshal(fields)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+ }
+ return append(serialized, '\n'), nil
+}
diff --git a/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go b/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go
new file mode 100644
index 0000000..d8814a0
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go
@@ -0,0 +1,52 @@
+package logstash
+
+import (
+ "bytes"
+ "encoding/json"
+ "github.com/Sirupsen/logrus"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestLogstashFormatter(t *testing.T) {
+ assert := assert.New(t)
+
+ lf := LogstashFormatter{Type: "abc"}
+
+ fields := logrus.Fields{
+ "message": "def",
+ "level": "ijk",
+ "type": "lmn",
+ "one": 1,
+ "pi": 3.14,
+ "bool": true,
+ }
+
+ entry := logrus.WithFields(fields)
+ entry.Message = "msg"
+ entry.Level = logrus.InfoLevel
+
+ b, _ := lf.Format(entry)
+
+ var data map[string]interface{}
+ dec := json.NewDecoder(bytes.NewReader(b))
+ dec.UseNumber()
+ dec.Decode(&data)
+
+ // base fields
+ assert.Equal(json.Number("1"), data["@version"])
+ assert.NotEmpty(data["@timestamp"])
+ assert.Equal("abc", data["type"])
+ assert.Equal("msg", data["message"])
+ assert.Equal("info", data["level"])
+
+ // substituted fields
+ assert.Equal("def", data["fields.message"])
+ assert.Equal("ijk", data["fields.level"])
+ assert.Equal("lmn", data["fields.type"])
+
+ // formats
+ assert.Equal(json.Number("1"), data["one"])
+ assert.Equal(json.Number("3.14"), data["pi"])
+ assert.Equal(true, data["bool"])
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hook_test.go b/vendor/github.com/Sirupsen/logrus/hook_test.go
new file mode 100644
index 0000000..13f34cb
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hook_test.go
@@ -0,0 +1,122 @@
+package logrus
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+type TestHook struct {
+ Fired bool
+}
+
+func (hook *TestHook) Fire(entry *Entry) error {
+ hook.Fired = true
+ return nil
+}
+
+func (hook *TestHook) Levels() []Level {
+ return []Level{
+ DebugLevel,
+ InfoLevel,
+ WarnLevel,
+ ErrorLevel,
+ FatalLevel,
+ PanicLevel,
+ }
+}
+
+func TestHookFires(t *testing.T) {
+ hook := new(TestHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ assert.Equal(t, hook.Fired, false)
+
+ log.Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, hook.Fired, true)
+ })
+}
+
+type ModifyHook struct {
+}
+
+func (hook *ModifyHook) Fire(entry *Entry) error {
+ entry.Data["wow"] = "whale"
+ return nil
+}
+
+func (hook *ModifyHook) Levels() []Level {
+ return []Level{
+ DebugLevel,
+ InfoLevel,
+ WarnLevel,
+ ErrorLevel,
+ FatalLevel,
+ PanicLevel,
+ }
+}
+
+func TestHookCanModifyEntry(t *testing.T) {
+ hook := new(ModifyHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ log.WithField("wow", "elephant").Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["wow"], "whale")
+ })
+}
+
+func TestCanFireMultipleHooks(t *testing.T) {
+ hook1 := new(ModifyHook)
+ hook2 := new(TestHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook1)
+ log.Hooks.Add(hook2)
+
+ log.WithField("wow", "elephant").Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["wow"], "whale")
+ assert.Equal(t, hook2.Fired, true)
+ })
+}
+
+type ErrorHook struct {
+ Fired bool
+}
+
+func (hook *ErrorHook) Fire(entry *Entry) error {
+ hook.Fired = true
+ return nil
+}
+
+func (hook *ErrorHook) Levels() []Level {
+ return []Level{
+ ErrorLevel,
+ }
+}
+
+func TestErrorHookShouldntFireOnInfo(t *testing.T) {
+ hook := new(ErrorHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ log.Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, hook.Fired, false)
+ })
+}
+
+func TestErrorHookShouldFireOnError(t *testing.T) {
+ hook := new(ErrorHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ log.Error("test")
+ }, func(fields Fields) {
+ assert.Equal(t, hook.Fired, true)
+ })
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks.go b/vendor/github.com/Sirupsen/logrus/hooks.go
new file mode 100644
index 0000000..3f151cd
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks.go
@@ -0,0 +1,34 @@
+package logrus
+
+// A hook to be fired when logging on the logging levels returned from
+// `Levels()` on your implementation of the interface. Note that this is not
+// fired in a goroutine or a channel with workers, you should handle such
+// functionality yourself if your call is non-blocking and you don't wish for
+// the logging calls for levels returned from `Levels()` to block.
+type Hook interface {
+ Levels() []Level
+ Fire(*Entry) error
+}
+
+// Internal type for storing the hooks on a logger instance.
+type LevelHooks map[Level][]Hook
+
+// Add a hook to an instance of logger. This is called with
+// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
+func (hooks LevelHooks) Add(hook Hook) {
+ for _, level := range hook.Levels() {
+ hooks[level] = append(hooks[level], hook)
+ }
+}
+
+// Fire all the hooks for the passed level. Used by `entry.log` to fire
+// appropriate hooks for a log entry.
+func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
+ for _, hook := range hooks[level] {
+ if err := hook.Fire(entry); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md b/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
new file mode 100644
index 0000000..066704b
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
@@ -0,0 +1,39 @@
+# Syslog Hooks for Logrus
+
+## Usage
+
+```go
+import (
+ "log/syslog"
+ "github.com/Sirupsen/logrus"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
+
+If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSyslogHook`. It should look like the following.
+
+```go
+import (
+ "log/syslog"
+ "github.com/Sirupsen/logrus"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
\ No newline at end of file
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go b/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
new file mode 100644
index 0000000..a36e200
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
@@ -0,0 +1,54 @@
+// +build !windows,!nacl,!plan9
+
+package logrus_syslog
+
+import (
+ "fmt"
+ "github.com/Sirupsen/logrus"
+ "log/syslog"
+ "os"
+)
+
+// SyslogHook to send logs via syslog.
+type SyslogHook struct {
+ Writer *syslog.Writer
+ SyslogNetwork string
+ SyslogRaddr string
+}
+
+// Creates a hook to be added to an instance of logger. This is called with
+// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
+// `if err == nil { log.Hooks.Add(hook) }`
+func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
+ w, err := syslog.Dial(network, raddr, priority, tag)
+ return &SyslogHook{w, network, raddr}, err
+}
+
+func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
+ line, err := entry.String()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
+ return err
+ }
+
+ switch entry.Level {
+ case logrus.PanicLevel:
+ return hook.Writer.Crit(line)
+ case logrus.FatalLevel:
+ return hook.Writer.Crit(line)
+ case logrus.ErrorLevel:
+ return hook.Writer.Err(line)
+ case logrus.WarnLevel:
+ return hook.Writer.Warning(line)
+ case logrus.InfoLevel:
+ return hook.Writer.Info(line)
+ case logrus.DebugLevel:
+ return hook.Writer.Debug(line)
+ default:
+ return nil
+ }
+}
+
+func (hook *SyslogHook) Levels() []logrus.Level {
+ return logrus.AllLevels
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go b/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
new file mode 100644
index 0000000..42762dc
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
@@ -0,0 +1,26 @@
+package logrus_syslog
+
+import (
+ "github.com/Sirupsen/logrus"
+ "log/syslog"
+ "testing"
+)
+
+func TestLocalhostAddAndPrint(t *testing.T) {
+ log := logrus.New()
+ hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+
+ if err != nil {
+ t.Errorf("Unable to connect to local syslog.")
+ }
+
+ log.Hooks.Add(hook)
+
+ for _, level := range hook.Levels() {
+ if len(log.Hooks[level]) != 1 {
+ t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
+ }
+ }
+
+ log.Info("Congratulations!")
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/test/test.go b/vendor/github.com/Sirupsen/logrus/hooks/test/test.go
new file mode 100644
index 0000000..0688125
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/test/test.go
@@ -0,0 +1,67 @@
+package test
+
+import (
+ "io/ioutil"
+
+ "github.com/Sirupsen/logrus"
+)
+
+// test.Hook is a hook designed for dealing with logs in test scenarios.
+type Hook struct {
+ Entries []*logrus.Entry
+}
+
+// Installs a test hook for the global logger.
+func NewGlobal() *Hook {
+
+ hook := new(Hook)
+ logrus.AddHook(hook)
+
+ return hook
+
+}
+
+// Installs a test hook for a given local logger.
+func NewLocal(logger *logrus.Logger) *Hook {
+
+ hook := new(Hook)
+ logger.Hooks.Add(hook)
+
+ return hook
+
+}
+
+// Creates a discarding logger and installs the test hook.
+func NewNullLogger() (*logrus.Logger, *Hook) {
+
+ logger := logrus.New()
+ logger.Out = ioutil.Discard
+
+ return logger, NewLocal(logger)
+
+}
+
+func (t *Hook) Fire(e *logrus.Entry) error {
+ t.Entries = append(t.Entries, e)
+ return nil
+}
+
+func (t *Hook) Levels() []logrus.Level {
+ return logrus.AllLevels
+}
+
+// LastEntry returns the last entry that was logged or nil.
+func (t *Hook) LastEntry() (l *logrus.Entry) {
+
+ if i := len(t.Entries) - 1; i < 0 {
+ return nil
+ } else {
+ return t.Entries[i]
+ }
+
+}
+
+// Reset removes all Entries from this test hook.
+func (t *Hook) Reset() {
+ t.Entries = make([]*logrus.Entry, 0)
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go b/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
new file mode 100644
index 0000000..d69455b
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
@@ -0,0 +1,39 @@
+package test
+
+import (
+ "testing"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAllHooks(t *testing.T) {
+
+ assert := assert.New(t)
+
+ logger, hook := NewNullLogger()
+ assert.Nil(hook.LastEntry())
+ assert.Equal(0, len(hook.Entries))
+
+ logger.Error("Hello error")
+ assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+ assert.Equal("Hello error", hook.LastEntry().Message)
+ assert.Equal(1, len(hook.Entries))
+
+ logger.Warn("Hello warning")
+ assert.Equal(logrus.WarnLevel, hook.LastEntry().Level)
+ assert.Equal("Hello warning", hook.LastEntry().Message)
+ assert.Equal(2, len(hook.Entries))
+
+ hook.Reset()
+ assert.Nil(hook.LastEntry())
+ assert.Equal(0, len(hook.Entries))
+
+ hook = NewGlobal()
+
+ logrus.Error("Hello error")
+ assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+ assert.Equal("Hello error", hook.LastEntry().Message)
+ assert.Equal(1, len(hook.Entries))
+
+}
diff --git a/vendor/github.com/Sirupsen/logrus/json_formatter.go b/vendor/github.com/Sirupsen/logrus/json_formatter.go
new file mode 100644
index 0000000..2ad6dc5
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/json_formatter.go
@@ -0,0 +1,41 @@
+package logrus
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+type JSONFormatter struct {
+ // TimestampFormat sets the format used for marshaling timestamps.
+ TimestampFormat string
+}
+
+func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
+ data := make(Fields, len(entry.Data)+3)
+ for k, v := range entry.Data {
+ switch v := v.(type) {
+ case error:
+ // Otherwise errors are ignored by `encoding/json`
+ // https://github.com/Sirupsen/logrus/issues/137
+ data[k] = v.Error()
+ default:
+ data[k] = v
+ }
+ }
+ prefixFieldClashes(data)
+
+ timestampFormat := f.TimestampFormat
+ if timestampFormat == "" {
+ timestampFormat = DefaultTimestampFormat
+ }
+
+ data["time"] = entry.Time.Format(timestampFormat)
+ data["msg"] = entry.Message
+ data["level"] = entry.Level.String()
+
+ serialized, err := json.Marshal(data)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+ }
+ return append(serialized, '\n'), nil
+}
diff --git a/vendor/github.com/Sirupsen/logrus/json_formatter_test.go b/vendor/github.com/Sirupsen/logrus/json_formatter_test.go
new file mode 100644
index 0000000..1d70873
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/json_formatter_test.go
@@ -0,0 +1,120 @@
+package logrus
+
+import (
+ "encoding/json"
+ "errors"
+
+ "testing"
+)
+
+func TestErrorNotLost(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("error", errors.New("wild walrus")))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["error"] != "wild walrus" {
+ t.Fatal("Error field not set")
+ }
+}
+
+func TestErrorNotLostOnFieldNotNamedError(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("omg", errors.New("wild walrus")))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["omg"] != "wild walrus" {
+ t.Fatal("Error field not set")
+ }
+}
+
+func TestFieldClashWithTime(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("time", "right now!"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["fields.time"] != "right now!" {
+ t.Fatal("fields.time not set to original time field")
+ }
+
+ if entry["time"] != "0001-01-01T00:00:00Z" {
+ t.Fatal("time field not set to current time, was: ", entry["time"])
+ }
+}
+
+func TestFieldClashWithMsg(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("msg", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["fields.msg"] != "something" {
+ t.Fatal("fields.msg not set to original msg field")
+ }
+}
+
+func TestFieldClashWithLevel(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("level", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["fields.level"] != "something" {
+ t.Fatal("fields.level not set to original level field")
+ }
+}
+
+func TestJSONEntryEndsWithNewline(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("level", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ if b[len(b)-1] != '\n' {
+ t.Fatal("Expected JSON log entry to end with a newline")
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/logger.go b/vendor/github.com/Sirupsen/logrus/logger.go
new file mode 100644
index 0000000..2fdb231
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/logger.go
@@ -0,0 +1,212 @@
+package logrus
+
+import (
+ "io"
+ "os"
+ "sync"
+)
+
+type Logger struct {
+ // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
+ // file, or leave it default which is `os.Stderr`. You can also set this to
+ // something more adventorous, such as logging to Kafka.
+ Out io.Writer
+ // Hooks for the logger instance. These allow firing events based on logging
+ // levels and log entries. For example, to send errors to an error tracking
+ // service, log to StatsD or dump the core on fatal errors.
+ Hooks LevelHooks
+ // All log entries pass through the formatter before logged to Out. The
+ // included formatters are `TextFormatter` and `JSONFormatter` for which
+ // TextFormatter is the default. In development (when a TTY is attached) it
+ // logs with colors, but to a file it wouldn't. You can easily implement your
+ // own that implements the `Formatter` interface, see the `README` or included
+ // formatters for examples.
+ Formatter Formatter
+ // The logging level the logger should log at. This is typically (and defaults
+ // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
+ // logged. `logrus.Debug` is useful in
+ Level Level
+ // Used to sync writing to the log.
+ mu sync.Mutex
+}
+
+// Creates a new logger. Configuration should be set by changing `Formatter`,
+// `Out` and `Hooks` directly on the default logger instance. You can also just
+// instantiate your own:
+//
+// var log = &Logger{
+// Out: os.Stderr,
+// Formatter: new(JSONFormatter),
+// Hooks: make(LevelHooks),
+// Level: logrus.DebugLevel,
+// }
+//
+// It's recommended to make this a global instance called `log`.
+func New() *Logger {
+ return &Logger{
+ Out: os.Stderr,
+ Formatter: new(TextFormatter),
+ Hooks: make(LevelHooks),
+ Level: InfoLevel,
+ }
+}
+
+// Adds a field to the log entry, note that you it doesn't log until you call
+// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
+// If you want multiple fields, use `WithFields`.
+func (logger *Logger) WithField(key string, value interface{}) *Entry {
+ return NewEntry(logger).WithField(key, value)
+}
+
+// Adds a struct of fields to the log entry. All it does is call `WithField` for
+// each `Field`.
+func (logger *Logger) WithFields(fields Fields) *Entry {
+ return NewEntry(logger).WithFields(fields)
+}
+
+// Add an error as single field to the log entry. All it does is call
+// `WithError` for the given `error`.
+func (logger *Logger) WithError(err error) *Entry {
+ return NewEntry(logger).WithError(err)
+}
+
+func (logger *Logger) Debugf(format string, args ...interface{}) {
+ if logger.Level >= DebugLevel {
+ NewEntry(logger).Debugf(format, args...)
+ }
+}
+
+func (logger *Logger) Infof(format string, args ...interface{}) {
+ if logger.Level >= InfoLevel {
+ NewEntry(logger).Infof(format, args...)
+ }
+}
+
+func (logger *Logger) Printf(format string, args ...interface{}) {
+ NewEntry(logger).Printf(format, args...)
+}
+
+func (logger *Logger) Warnf(format string, args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warnf(format, args...)
+ }
+}
+
+func (logger *Logger) Warningf(format string, args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warnf(format, args...)
+ }
+}
+
+func (logger *Logger) Errorf(format string, args ...interface{}) {
+ if logger.Level >= ErrorLevel {
+ NewEntry(logger).Errorf(format, args...)
+ }
+}
+
+func (logger *Logger) Fatalf(format string, args ...interface{}) {
+ if logger.Level >= FatalLevel {
+ NewEntry(logger).Fatalf(format, args...)
+ }
+ os.Exit(1)
+}
+
+func (logger *Logger) Panicf(format string, args ...interface{}) {
+ if logger.Level >= PanicLevel {
+ NewEntry(logger).Panicf(format, args...)
+ }
+}
+
+func (logger *Logger) Debug(args ...interface{}) {
+ if logger.Level >= DebugLevel {
+ NewEntry(logger).Debug(args...)
+ }
+}
+
+func (logger *Logger) Info(args ...interface{}) {
+ if logger.Level >= InfoLevel {
+ NewEntry(logger).Info(args...)
+ }
+}
+
+func (logger *Logger) Print(args ...interface{}) {
+ NewEntry(logger).Info(args...)
+}
+
+func (logger *Logger) Warn(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warn(args...)
+ }
+}
+
+func (logger *Logger) Warning(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warn(args...)
+ }
+}
+
+func (logger *Logger) Error(args ...interface{}) {
+ if logger.Level >= ErrorLevel {
+ NewEntry(logger).Error(args...)
+ }
+}
+
+func (logger *Logger) Fatal(args ...interface{}) {
+ if logger.Level >= FatalLevel {
+ NewEntry(logger).Fatal(args...)
+ }
+ os.Exit(1)
+}
+
+func (logger *Logger) Panic(args ...interface{}) {
+ if logger.Level >= PanicLevel {
+ NewEntry(logger).Panic(args...)
+ }
+}
+
+func (logger *Logger) Debugln(args ...interface{}) {
+ if logger.Level >= DebugLevel {
+ NewEntry(logger).Debugln(args...)
+ }
+}
+
+func (logger *Logger) Infoln(args ...interface{}) {
+ if logger.Level >= InfoLevel {
+ NewEntry(logger).Infoln(args...)
+ }
+}
+
+func (logger *Logger) Println(args ...interface{}) {
+ NewEntry(logger).Println(args...)
+}
+
+func (logger *Logger) Warnln(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warnln(args...)
+ }
+}
+
+func (logger *Logger) Warningln(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ NewEntry(logger).Warnln(args...)
+ }
+}
+
+func (logger *Logger) Errorln(args ...interface{}) {
+ if logger.Level >= ErrorLevel {
+ NewEntry(logger).Errorln(args...)
+ }
+}
+
+func (logger *Logger) Fatalln(args ...interface{}) {
+ if logger.Level >= FatalLevel {
+ NewEntry(logger).Fatalln(args...)
+ }
+ os.Exit(1)
+}
+
+func (logger *Logger) Panicln(args ...interface{}) {
+ if logger.Level >= PanicLevel {
+ NewEntry(logger).Panicln(args...)
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/logrus.go b/vendor/github.com/Sirupsen/logrus/logrus.go
new file mode 100644
index 0000000..e596691
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/logrus.go
@@ -0,0 +1,143 @@
+package logrus
+
+import (
+ "fmt"
+ "log"
+ "strings"
+)
+
+// Fields type, used to pass to `WithFields`.
+type Fields map[string]interface{}
+
+// Level type
+type Level uint8
+
+// Convert the Level to a string. E.g. PanicLevel becomes "panic".
+func (level Level) String() string {
+ switch level {
+ case DebugLevel:
+ return "debug"
+ case InfoLevel:
+ return "info"
+ case WarnLevel:
+ return "warning"
+ case ErrorLevel:
+ return "error"
+ case FatalLevel:
+ return "fatal"
+ case PanicLevel:
+ return "panic"
+ }
+
+ return "unknown"
+}
+
+// ParseLevel takes a string level and returns the Logrus log level constant.
+func ParseLevel(lvl string) (Level, error) {
+ switch strings.ToLower(lvl) {
+ case "panic":
+ return PanicLevel, nil
+ case "fatal":
+ return FatalLevel, nil
+ case "error":
+ return ErrorLevel, nil
+ case "warn", "warning":
+ return WarnLevel, nil
+ case "info":
+ return InfoLevel, nil
+ case "debug":
+ return DebugLevel, nil
+ }
+
+ var l Level
+ return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
+}
+
+// A constant exposing all logging levels
+var AllLevels = []Level{
+ PanicLevel,
+ FatalLevel,
+ ErrorLevel,
+ WarnLevel,
+ InfoLevel,
+ DebugLevel,
+}
+
+// These are the different logging levels. You can set the logging level to log
+// on your instance of logger, obtained with `logrus.New()`.
+const (
+ // PanicLevel level, highest level of severity. Logs and then calls panic with the
+ // message passed to Debug, Info, ...
+ PanicLevel Level = iota
+ // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
+ // logging level is set to Panic.
+ FatalLevel
+ // ErrorLevel level. Logs. Used for errors that should definitely be noted.
+ // Commonly used for hooks to send errors to an error tracking service.
+ ErrorLevel
+ // WarnLevel level. Non-critical entries that deserve eyes.
+ WarnLevel
+ // InfoLevel level. General operational entries about what's going on inside the
+ // application.
+ InfoLevel
+ // DebugLevel level. Usually only enabled when debugging. Very verbose logging.
+ DebugLevel
+)
+
+// Won't compile if StdLogger can't be realized by a log.Logger
+var (
+ _ StdLogger = &log.Logger{}
+ _ StdLogger = &Entry{}
+ _ StdLogger = &Logger{}
+)
+
+// StdLogger is what your logrus-enabled library should take, that way
+// it'll accept a stdlib logger and a logrus logger. There's no standard
+// interface, this is the closest we get, unfortunately.
+type StdLogger interface {
+ Print(...interface{})
+ Printf(string, ...interface{})
+ Println(...interface{})
+
+ Fatal(...interface{})
+ Fatalf(string, ...interface{})
+ Fatalln(...interface{})
+
+ Panic(...interface{})
+ Panicf(string, ...interface{})
+ Panicln(...interface{})
+}
+
+// The FieldLogger interface generalizes the Entry and Logger types
+type FieldLogger interface {
+ WithField(key string, value interface{}) *Entry
+ WithFields(fields Fields) *Entry
+ WithError(err error) *Entry
+
+ Debugf(format string, args ...interface{})
+ Infof(format string, args ...interface{})
+ Printf(format string, args ...interface{})
+ Warnf(format string, args ...interface{})
+ Warningf(format string, args ...interface{})
+ Errorf(format string, args ...interface{})
+ Fatalf(format string, args ...interface{})
+ Panicf(format string, args ...interface{})
+
+ Debug(args ...interface{})
+ Info(args ...interface{})
+ Print(args ...interface{})
+ Warn(args ...interface{})
+ Warning(args ...interface{})
+ Error(args ...interface{})
+ Fatal(args ...interface{})
+ Panic(args ...interface{})
+
+ Debugln(args ...interface{})
+ Infoln(args ...interface{})
+ Println(args ...interface{})
+ Warnln(args ...interface{})
+ Warningln(args ...interface{})
+ Errorln(args ...interface{})
+ Fatalln(args ...interface{})
+ Panicln(args ...interface{})
+}
diff --git a/vendor/github.com/Sirupsen/logrus/logrus_test.go b/vendor/github.com/Sirupsen/logrus/logrus_test.go
new file mode 100644
index 0000000..bfc4780
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/logrus_test.go
@@ -0,0 +1,361 @@
+package logrus
+
+import (
+ "bytes"
+ "encoding/json"
+ "strconv"
+ "strings"
+ "sync"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
+ var buffer bytes.Buffer
+ var fields Fields
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = new(JSONFormatter)
+
+ log(logger)
+
+ err := json.Unmarshal(buffer.Bytes(), &fields)
+ assert.Nil(t, err)
+
+ assertions(fields)
+}
+
+func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
+ var buffer bytes.Buffer
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = &TextFormatter{
+ DisableColors: true,
+ }
+
+ log(logger)
+
+ fields := make(map[string]string)
+ for _, kv := range strings.Split(buffer.String(), " ") {
+ if !strings.Contains(kv, "=") {
+ continue
+ }
+ kvArr := strings.Split(kv, "=")
+ key := strings.TrimSpace(kvArr[0])
+ val := kvArr[1]
+ if kvArr[1][0] == '"' {
+ var err error
+ val, err = strconv.Unquote(val)
+ assert.NoError(t, err)
+ }
+ fields[key] = val
+ }
+ assertions(fields)
+}
+
+func TestPrint(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["level"], "info")
+ })
+}
+
+func TestInfo(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["level"], "info")
+ })
+}
+
+func TestWarn(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Warn("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["level"], "warning")
+ })
+}
+
+func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln("test", "test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test test")
+ })
+}
+
+func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln("test", 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test 10")
+ })
+}
+
+func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln(10, 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "10 10")
+ })
+}
+
+func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln(10, 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "10 10")
+ })
+}
+
+func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Info("test", 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test10")
+ })
+}
+
+func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Info("test", "test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "testtest")
+ })
+}
+
+func TestWithFieldsShouldAllowAssignments(t *testing.T) {
+ var buffer bytes.Buffer
+ var fields Fields
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = new(JSONFormatter)
+
+ localLog := logger.WithFields(Fields{
+ "key1": "value1",
+ })
+
+ localLog.WithField("key2", "value2").Info("test")
+ err := json.Unmarshal(buffer.Bytes(), &fields)
+ assert.Nil(t, err)
+
+ assert.Equal(t, "value2", fields["key2"])
+ assert.Equal(t, "value1", fields["key1"])
+
+ buffer = bytes.Buffer{}
+ fields = Fields{}
+ localLog.Info("test")
+ err = json.Unmarshal(buffer.Bytes(), &fields)
+ assert.Nil(t, err)
+
+ _, ok := fields["key2"]
+ assert.Equal(t, false, ok)
+ assert.Equal(t, "value1", fields["key1"])
+}
+
+func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("msg", "hello").Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ })
+}
+
+func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("msg", "hello").Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["fields.msg"], "hello")
+ })
+}
+
+func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("time", "hello").Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["fields.time"], "hello")
+ })
+}
+
+func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("level", 1).Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["level"], "info")
+ assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only
+ })
+}
+
+func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
+ LogAndAssertText(t, func(log *Logger) {
+ ll := log.WithField("herp", "derp")
+ ll.Info("hello")
+ ll.Info("bye")
+ }, func(fields map[string]string) {
+ for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
+ if _, ok := fields[fieldName]; ok {
+ t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
+ }
+ }
+ })
+}
+
+func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
+
+ var buffer bytes.Buffer
+ var fields Fields
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = new(JSONFormatter)
+
+ llog := logger.WithField("context", "eating raw fish")
+
+ llog.Info("looks delicious")
+
+ err := json.Unmarshal(buffer.Bytes(), &fields)
+ assert.NoError(t, err, "should have decoded first message")
+ assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
+ assert.Equal(t, fields["msg"], "looks delicious")
+ assert.Equal(t, fields["context"], "eating raw fish")
+
+ buffer.Reset()
+
+ llog.Warn("omg it is!")
+
+ err = json.Unmarshal(buffer.Bytes(), &fields)
+ assert.NoError(t, err, "should have decoded second message")
+ assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
+ assert.Equal(t, fields["msg"], "omg it is!")
+ assert.Equal(t, fields["context"], "eating raw fish")
+ assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
+
+}
+
+func TestConvertLevelToString(t *testing.T) {
+ assert.Equal(t, "debug", DebugLevel.String())
+ assert.Equal(t, "info", InfoLevel.String())
+ assert.Equal(t, "warning", WarnLevel.String())
+ assert.Equal(t, "error", ErrorLevel.String())
+ assert.Equal(t, "fatal", FatalLevel.String())
+ assert.Equal(t, "panic", PanicLevel.String())
+}
+
+func TestParseLevel(t *testing.T) {
+ l, err := ParseLevel("panic")
+ assert.Nil(t, err)
+ assert.Equal(t, PanicLevel, l)
+
+ l, err = ParseLevel("PANIC")
+ assert.Nil(t, err)
+ assert.Equal(t, PanicLevel, l)
+
+ l, err = ParseLevel("fatal")
+ assert.Nil(t, err)
+ assert.Equal(t, FatalLevel, l)
+
+ l, err = ParseLevel("FATAL")
+ assert.Nil(t, err)
+ assert.Equal(t, FatalLevel, l)
+
+ l, err = ParseLevel("error")
+ assert.Nil(t, err)
+ assert.Equal(t, ErrorLevel, l)
+
+ l, err = ParseLevel("ERROR")
+ assert.Nil(t, err)
+ assert.Equal(t, ErrorLevel, l)
+
+ l, err = ParseLevel("warn")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("WARN")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("warning")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("WARNING")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("info")
+ assert.Nil(t, err)
+ assert.Equal(t, InfoLevel, l)
+
+ l, err = ParseLevel("INFO")
+ assert.Nil(t, err)
+ assert.Equal(t, InfoLevel, l)
+
+ l, err = ParseLevel("debug")
+ assert.Nil(t, err)
+ assert.Equal(t, DebugLevel, l)
+
+ l, err = ParseLevel("DEBUG")
+ assert.Nil(t, err)
+ assert.Equal(t, DebugLevel, l)
+
+ l, err = ParseLevel("invalid")
+ assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
+}
+
+func TestGetSetLevelRace(t *testing.T) {
+ wg := sync.WaitGroup{}
+ for i := 0; i < 100; i++ {
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+ if i%2 == 0 {
+ SetLevel(InfoLevel)
+ } else {
+ GetLevel()
+ }
+ }(i)
+
+ }
+ wg.Wait()
+}
+
+func TestLoggingRace(t *testing.T) {
+ logger := New()
+
+ var wg sync.WaitGroup
+ wg.Add(100)
+
+ for i := 0; i < 100; i++ {
+ go func() {
+ logger.Info("info")
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
+
+// Compile test
+func TestLogrusInterface(t *testing.T) {
+ var buffer bytes.Buffer
+ fn := func(l FieldLogger) {
+ b := l.WithField("key", "value")
+ b.Debug("Test")
+ }
+ // test logger
+ logger := New()
+ logger.Out = &buffer
+ fn(logger)
+
+ // test Entry
+ e := logger.WithField("another", "value")
+ fn(e)
+}
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_bsd.go b/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
new file mode 100644
index 0000000..71f8d67
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
@@ -0,0 +1,9 @@
+// +build darwin freebsd openbsd netbsd dragonfly
+
+package logrus
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+type Termios syscall.Termios
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_linux.go b/vendor/github.com/Sirupsen/logrus/terminal_linux.go
new file mode 100644
index 0000000..a2c0b40
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_linux.go
@@ -0,0 +1,12 @@
+// Based on ssh/terminal:
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package logrus
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TCGETS
+
+type Termios syscall.Termios
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go b/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
new file mode 100644
index 0000000..b343b3a
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
@@ -0,0 +1,21 @@
+// Based on ssh/terminal:
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux darwin freebsd openbsd netbsd dragonfly
+
+package logrus
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+// IsTerminal returns true if stderr's file descriptor is a terminal.
+func IsTerminal() bool {
+ fd := syscall.Stderr
+ var termios Termios
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
+}
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_solaris.go b/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
new file mode 100644
index 0000000..3e70bf7
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
@@ -0,0 +1,15 @@
+// +build solaris
+
+package logrus
+
+import (
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal() bool {
+ _, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
+ return err == nil
+}
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_windows.go b/vendor/github.com/Sirupsen/logrus/terminal_windows.go
new file mode 100644
index 0000000..0146845
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_windows.go
@@ -0,0 +1,27 @@
+// Based on ssh/terminal:
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package logrus
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+var (
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+)
+
+// IsTerminal returns true if stderr's file descriptor is a terminal.
+func IsTerminal() bool {
+ fd := syscall.Stderr
+ var st uint32
+ r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+ return r != 0 && e == 0
+}
diff --git a/vendor/github.com/Sirupsen/logrus/text_formatter.go b/vendor/github.com/Sirupsen/logrus/text_formatter.go
new file mode 100644
index 0000000..6afd0e0
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/text_formatter.go
@@ -0,0 +1,161 @@
+package logrus
+
+import (
+ "bytes"
+ "fmt"
+ "runtime"
+ "sort"
+ "strings"
+ "time"
+)
+
+const (
+ nocolor = 0
+ red = 31
+ green = 32
+ yellow = 33
+ blue = 34
+ gray = 37
+)
+
+var (
+ baseTimestamp time.Time
+ isTerminal bool
+)
+
+func init() {
+ baseTimestamp = time.Now()
+ isTerminal = IsTerminal()
+}
+
+func miniTS() int {
+ return int(time.Since(baseTimestamp) / time.Second)
+}
+
+type TextFormatter struct {
+ // Set to true to bypass checking for a TTY before outputting colors.
+ ForceColors bool
+
+ // Force disabling colors.
+ DisableColors bool
+
+ // Disable timestamp logging. useful when output is redirected to logging
+ // system that already adds timestamps.
+ DisableTimestamp bool
+
+ // Enable logging the full timestamp when a TTY is attached instead of just
+ // the time passed since beginning of execution.
+ FullTimestamp bool
+
+ // TimestampFormat to use for display when a full timestamp is printed
+ TimestampFormat string
+
+ // The fields are sorted by default for a consistent output. For applications
+ // that log extremely frequently and don't use the JSON formatter this may not
+ // be desired.
+ DisableSorting bool
+}
+
+func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
+ var keys []string = make([]string, 0, len(entry.Data))
+ for k := range entry.Data {
+ keys = append(keys, k)
+ }
+
+ if !f.DisableSorting {
+ sort.Strings(keys)
+ }
+
+ b := &bytes.Buffer{}
+
+ prefixFieldClashes(entry.Data)
+
+ isColorTerminal := isTerminal && (runtime.GOOS != "windows")
+ isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
+
+ timestampFormat := f.TimestampFormat
+ if timestampFormat == "" {
+ timestampFormat = DefaultTimestampFormat
+ }
+ if isColored {
+ f.printColored(b, entry, keys, timestampFormat)
+ } else {
+ if !f.DisableTimestamp {
+ f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
+ }
+ f.appendKeyValue(b, "level", entry.Level.String())
+ if entry.Message != "" {
+ f.appendKeyValue(b, "msg", entry.Message)
+ }
+ for _, key := range keys {
+ f.appendKeyValue(b, key, entry.Data[key])
+ }
+ }
+
+ b.WriteByte('\n')
+ return b.Bytes(), nil
+}
+
+func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
+ var levelColor int
+ switch entry.Level {
+ case DebugLevel:
+ levelColor = gray
+ case WarnLevel:
+ levelColor = yellow
+ case ErrorLevel, FatalLevel, PanicLevel:
+ levelColor = red
+ default:
+ levelColor = blue
+ }
+
+ levelText := strings.ToUpper(entry.Level.String())[0:4]
+
+ if !f.FullTimestamp {
+ fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
+ } else {
+ fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
+ }
+ for _, k := range keys {
+ v := entry.Data[k]
+ fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
+ }
+}
+
+func needsQuoting(text string) bool {
+ for _, ch := range text {
+ if !((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') ||
+ ch == '-' || ch == '.') {
+ return true
+ }
+ }
+ return false
+}
+
+func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
+
+ b.WriteString(key)
+ b.WriteByte('=')
+
+ switch value := value.(type) {
+ case string:
+ if !needsQuoting(value) {
+ b.WriteString(value)
+ } else {
+ fmt.Fprintf(b, "%q", value)
+ }
+ case error:
+ errmsg := value.Error()
+ if !needsQuoting(errmsg) {
+ b.WriteString(errmsg)
+ } else {
+ fmt.Fprintf(b, "%q", value)
+ }
+ default:
+ fmt.Fprint(b, value)
+ }
+
+ b.WriteByte(' ')
+}
diff --git a/vendor/github.com/Sirupsen/logrus/text_formatter_test.go b/vendor/github.com/Sirupsen/logrus/text_formatter_test.go
new file mode 100644
index 0000000..e25a44f
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/text_formatter_test.go
@@ -0,0 +1,61 @@
+package logrus
+
+import (
+ "bytes"
+ "errors"
+ "testing"
+ "time"
+)
+
+func TestQuoting(t *testing.T) {
+ tf := &TextFormatter{DisableColors: true}
+
+ checkQuoting := func(q bool, value interface{}) {
+ b, _ := tf.Format(WithField("test", value))
+ idx := bytes.Index(b, ([]byte)("test="))
+ cont := bytes.Contains(b[idx+5:], []byte{'"'})
+ if cont != q {
+ if q {
+ t.Errorf("quoting expected for: %#v", value)
+ } else {
+ t.Errorf("quoting not expected for: %#v", value)
+ }
+ }
+ }
+
+ checkQuoting(false, "abcd")
+ checkQuoting(false, "v1.0")
+ checkQuoting(false, "1234567890")
+ checkQuoting(true, "/foobar")
+ checkQuoting(true, "x y")
+ checkQuoting(true, "x,y")
+ checkQuoting(false, errors.New("invalid"))
+ checkQuoting(true, errors.New("invalid argument"))
+}
+
+func TestTimestampFormat(t *testing.T) {
+ checkTimeStr := func(format string) {
+ customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format}
+ customStr, _ := customFormatter.Format(WithField("test", "test"))
+ timeStart := bytes.Index(customStr, ([]byte)("time="))
+ timeEnd := bytes.Index(customStr, ([]byte)("level="))
+ timeStr := customStr[timeStart+5 : timeEnd-1]
+ if timeStr[0] == '"' && timeStr[len(timeStr)-1] == '"' {
+ timeStr = timeStr[1 : len(timeStr)-1]
+ }
+ if format == "" {
+ format = time.RFC3339
+ }
+ _, e := time.Parse(format, (string)(timeStr))
+ if e != nil {
+ t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e)
+ }
+ }
+
+ checkTimeStr("2006-01-02T15:04:05.000000000Z07:00")
+ checkTimeStr("Mon Jan _2 15:04:05 2006")
+ checkTimeStr("")
+}
+
+// TODO add tests for sorting etc., this requires a parser for the text
+// formatter output.
diff --git a/vendor/github.com/Sirupsen/logrus/writer.go b/vendor/github.com/Sirupsen/logrus/writer.go
new file mode 100644
index 0000000..f74d2aa
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/writer.go
@@ -0,0 +1,53 @@
+package logrus
+
+import (
+ "bufio"
+ "io"
+ "runtime"
+)
+
+func (logger *Logger) Writer() *io.PipeWriter {
+ return logger.WriterLevel(InfoLevel)
+}
+
+func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
+ reader, writer := io.Pipe()
+
+ var printFunc func(args ...interface{})
+ switch level {
+ case DebugLevel:
+ printFunc = logger.Debug
+ case InfoLevel:
+ printFunc = logger.Info
+ case WarnLevel:
+ printFunc = logger.Warn
+ case ErrorLevel:
+ printFunc = logger.Error
+ case FatalLevel:
+ printFunc = logger.Fatal
+ case PanicLevel:
+ printFunc = logger.Panic
+ default:
+ printFunc = logger.Print
+ }
+
+ go logger.writerScanner(reader, printFunc)
+ runtime.SetFinalizer(writer, writerFinalizer)
+
+ return writer
+}
+
+func (logger *Logger) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
+ scanner := bufio.NewScanner(reader)
+ for scanner.Scan() {
+ printFunc(scanner.Text())
+ }
+ if err := scanner.Err(); err != nil {
+ logger.Errorf("Error while reading from Writer: %s", err)
+ }
+ reader.Close()
+}
+
+func writerFinalizer(writer *io.PipeWriter) {
+ writer.Close()
+}
diff --git a/vendor/github.com/codegangsta/cli/.gitignore b/vendor/github.com/codegangsta/cli/.gitignore
new file mode 100644
index 0000000..faf70c4
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/.gitignore
@@ -0,0 +1,2 @@
+*.coverprofile
+node_modules/
diff --git a/vendor/github.com/codegangsta/cli/.travis.yml b/vendor/github.com/codegangsta/cli/.travis.yml
new file mode 100644
index 0000000..273d017
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/.travis.yml
@@ -0,0 +1,40 @@
+language: go
+
+sudo: false
+
+cache:
+ directories:
+ - node_modules
+
+go:
+- 1.2.2
+- 1.3.3
+- 1.4
+- 1.5.4
+- 1.6.2
+- master
+
+matrix:
+ allow_failures:
+ - go: master
+ include:
+ - go: 1.6.2
+ os: osx
+ - go: 1.1.2
+ install: go get -v .
+ before_script: echo skipping gfmxr on $TRAVIS_GO_VERSION
+ script:
+ - ./runtests vet
+ - ./runtests test
+
+before_script:
+- go get github.com/urfave/gfmxr/...
+- if [ ! -f node_modules/.bin/markdown-toc ] ; then
+ npm install markdown-toc ;
+ fi
+
+script:
+- ./runtests vet
+- ./runtests test
+- ./runtests gfmxr
+- ./runtests toc
diff --git a/vendor/github.com/codegangsta/cli/CHANGELOG.md b/vendor/github.com/codegangsta/cli/CHANGELOG.md
new file mode 100644
index 0000000..d1904fe
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/CHANGELOG.md
@@ -0,0 +1,329 @@
+# Change Log
+
+**ATTN**: This project uses [semantic versioning](http://semver.org/).
+
+## [Unreleased]
+
+## [1.18.0] - 2016-06-27
+### Added
+- `./runtests` test runner with coverage tracking by default
+- testing on OS X
+- testing on Windows
+- `UintFlag`, `Uint64Flag`, and `Int64Flag` types and supporting code
+
+### Changed
+- Use spaces for alignment in help/usage output instead of tabs, making the
+ output alignment consistent regardless of tab width
+
+### Fixed
+- Printing of command aliases in help text
+- Printing of visible flags for both struct and struct pointer flags
+- Display the `help` subcommand when using `CommandCategories`
+- No longer swallows `panic`s that occur within the `Action`s themselves when
+ detecting the signature of the `Action` field
+
+## [1.17.0] - 2016-05-09
+### Added
+- Pluggable flag-level help text rendering via `cli.DefaultFlagStringFunc`
+- `context.GlobalBoolT` was added as an analogue to `context.GlobalBool`
+- Support for hiding commands by setting `Hidden: true` -- this will hide the
+ commands in help output
+
+### Changed
+- `Float64Flag`, `IntFlag`, and `DurationFlag` default values are no longer
+ quoted in help text output.
+- All flag types now include `(default: {value})` strings following usage when a
+ default value can be (reasonably) detected.
+- `IntSliceFlag` and `StringSliceFlag` usage strings are now more consistent
+ with non-slice flag types
+- Apps now exit with a code of 3 if an unknown subcommand is specified
+ (previously they printed "No help topic for...", but still exited 0. This
+ makes it easier to script around apps built using `cli` since they can trust
+ that a 0 exit code indicated a successful execution.
+- cleanups based on [Go Report Card
+ feedback](https://goreportcard.com/report/github.com/urfave/cli)
+
+## [1.16.0] - 2016-05-02
+### Added
+- `Hidden` field on all flag struct types to omit from generated help text
+
+### Changed
+- `BashCompletionFlag` (`--enable-bash-completion`) is now omitted from
+generated help text via the `Hidden` field
+
+### Fixed
+- handling of error values in `HandleAction` and `HandleExitCoder`
+
+## [1.15.0] - 2016-04-30
+### Added
+- This file!
+- Support for placeholders in flag usage strings
+- `App.Metadata` map for arbitrary data/state management
+- `Set` and `GlobalSet` methods on `*cli.Context` for altering values after
+parsing.
+- Support for nested lookup of dot-delimited keys in structures loaded from
+YAML.
+
+### Changed
+- The `App.Action` and `Command.Action` now prefer a return signature of
+`func(*cli.Context) error`, as defined by `cli.ActionFunc`. If a non-nil
+`error` is returned, there may be two outcomes:
+ - If the error fulfills `cli.ExitCoder`, then `os.Exit` will be called
+ automatically
+ - Else the error is bubbled up and returned from `App.Run`
+- Specifying an `Action` with the legacy return signature of
+`func(*cli.Context)` will produce a deprecation message to stderr
+- Specifying an `Action` that is not a `func` type will produce a non-zero exit
+from `App.Run`
+- Specifying an `Action` func that has an invalid (input) signature will
+produce a non-zero exit from `App.Run`
+
+### Deprecated
+-
+`cli.App.RunAndExitOnError`, which should now be done by returning an error
+that fulfills `cli.ExitCoder` to `cli.App.Run`.
+- the legacy signature for
+`cli.App.Action` of `func(*cli.Context)`, which should now have a return
+signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`.
+
+### Fixed
+- Added missing `*cli.Context.GlobalFloat64` method
+
+## [1.14.0] - 2016-04-03 (backfilled 2016-04-25)
+### Added
+- Codebeat badge
+- Support for categorization via `CategorizedHelp` and `Categories` on app.
+
+### Changed
+- Use `filepath.Base` instead of `path.Base` in `Name` and `HelpName`.
+
+### Fixed
+- Ensure version is not shown in help text when `HideVersion` set.
+
+## [1.13.0] - 2016-03-06 (backfilled 2016-04-25)
+### Added
+- YAML file input support.
+- `NArg` method on context.
+
+## [1.12.0] - 2016-02-17 (backfilled 2016-04-25)
+### Added
+- Custom usage error handling.
+- Custom text support in `USAGE` section of help output.
+- Improved help messages for empty strings.
+- AppVeyor CI configuration.
+
+### Changed
+- Removed `panic` from default help printer func.
+- De-duping and optimizations.
+
+### Fixed
+- Correctly handle `Before`/`After` at command level when no subcommands.
+- Case of literal `-` argument causing flag reordering.
+- Environment variable hints on Windows.
+- Docs updates.
+
+## [1.11.1] - 2015-12-21 (backfilled 2016-04-25)
+### Changed
+- Use `path.Base` in `Name` and `HelpName`
+- Export `GetName` on flag types.
+
+### Fixed
+- Flag parsing when skipping is enabled.
+- Test output cleanup.
+- Move completion check to account for empty input case.
+
+## [1.11.0] - 2015-11-15 (backfilled 2016-04-25)
+### Added
+- Destination scan support for flags.
+- Testing against `tip` in Travis CI config.
+
+### Changed
+- Go version in Travis CI config.
+
+### Fixed
+- Removed redundant tests.
+- Use correct example naming in tests.
+
+## [1.10.2] - 2015-10-29 (backfilled 2016-04-25)
+### Fixed
+- Remove unused var in bash completion.
+
+## [1.10.1] - 2015-10-21 (backfilled 2016-04-25)
+### Added
+- Coverage and reference logos in README.
+
+### Fixed
+- Use specified values in help and version parsing.
+- Only display app version and help message once.
+
+## [1.10.0] - 2015-10-06 (backfilled 2016-04-25)
+### Added
+- More tests for existing functionality.
+- `ArgsUsage` at app and command level for help text flexibility.
+
+### Fixed
+- Honor `HideHelp` and `HideVersion` in `App.Run`.
+- Remove juvenile word from README.
+
+## [1.9.0] - 2015-09-08 (backfilled 2016-04-25)
+### Added
+- `FullName` on command with accompanying help output update.
+- Set default `$PROG` in bash completion.
+
+### Changed
+- Docs formatting.
+
+### Fixed
+- Removed self-referential imports in tests.
+
+## [1.8.0] - 2015-06-30 (backfilled 2016-04-25)
+### Added
+- Support for `Copyright` at app level.
+- `Parent` func at context level to walk up context lineage.
+
+### Fixed
+- Global flag processing at top level.
+
+## [1.7.1] - 2015-06-11 (backfilled 2016-04-25)
+### Added
+- Aggregate errors from `Before`/`After` funcs.
+- Doc comments on flag structs.
+- Include non-global flags when checking version and help.
+- Travis CI config updates.
+
+### Fixed
+- Ensure slice type flags have non-nil values.
+- Collect global flags from the full command hierarchy.
+- Docs prose.
+
+## [1.7.0] - 2015-05-03 (backfilled 2016-04-25)
+### Changed
+- `HelpPrinter` signature includes output writer.
+
+### Fixed
+- Specify go 1.1+ in docs.
+- Set `Writer` when running command as app.
+
+## [1.6.0] - 2015-03-23 (backfilled 2016-04-25)
+### Added
+- Multiple author support.
+- `NumFlags` at context level.
+- `Aliases` at command level.
+
+### Deprecated
+- `ShortName` at command level.
+
+### Fixed
+- Subcommand help output.
+- Backward compatible support for deprecated `Author` and `Email` fields.
+- Docs regarding `Names`/`Aliases`.
+
+## [1.5.0] - 2015-02-20 (backfilled 2016-04-25)
+### Added
+- `After` hook func support at app and command level.
+
+### Fixed
+- Use parsed context when running command as subcommand.
+- Docs prose.
+
+## [1.4.1] - 2015-01-09 (backfilled 2016-04-25)
+### Added
+- Support for hiding `-h / --help` flags, but not `help` subcommand.
+- Stop flag parsing after `--`.
+
+### Fixed
+- Help text for generic flags to specify single value.
+- Use double quotes in output for defaults.
+- Use `ParseInt` instead of `ParseUint` for int environment var values.
+- Use `0` as base when parsing int environment var values.
+
+## [1.4.0] - 2014-12-12 (backfilled 2016-04-25)
+### Added
+- Support for environment variable lookup "cascade".
+- Support for `Stdout` on app for output redirection.
+
+### Fixed
+- Print command help instead of app help in `ShowCommandHelp`.
+
+## [1.3.1] - 2014-11-13 (backfilled 2016-04-25)
+### Added
+- Docs and example code updates.
+
+### Changed
+- Default `-v / --version` flag made optional.
+
+## [1.3.0] - 2014-08-10 (backfilled 2016-04-25)
+### Added
+- `FlagNames` at context level.
+- Exposed `VersionPrinter` var for more control over version output.
+- Zsh completion hook.
+- `AUTHOR` section in default app help template.
+- Contribution guidelines.
+- `DurationFlag` type.
+
+## [1.2.0] - 2014-08-02
+### Added
+- Support for environment variable defaults on flags plus tests.
+
+## [1.1.0] - 2014-07-15
+### Added
+- Bash completion.
+- Optional hiding of built-in help command.
+- Optional skipping of flag parsing at command level.
+- `Author`, `Email`, and `Compiled` metadata on app.
+- `Before` hook func support at app and command level.
+- `CommandNotFound` func support at app level.
+- Command reference available on context.
+- `GenericFlag` type.
+- `Float64Flag` type.
+- `BoolTFlag` type.
+- `IsSet` flag helper on context.
+- More flag lookup funcs at context level.
+- More tests & docs.
+
+### Changed
+- Help template updates to account for presence/absence of flags.
+- Separated subcommand help template.
+- Exposed `HelpPrinter` var for more control over help output.
+
+## [1.0.0] - 2013-11-01
+### Added
+- `help` flag in default app flag set and each command flag set.
+- Custom handling of argument parsing errors.
+- Command lookup by name at app level.
+- `StringSliceFlag` type and supporting `StringSlice` type.
+- `IntSliceFlag` type and supporting `IntSlice` type.
+- Slice type flag lookups by name at context level.
+- Export of app and command help functions.
+- More tests & docs.
+
+## 0.1.0 - 2013-07-22
+### Added
+- Initial implementation.
+
+[Unreleased]: https://github.com/urfave/cli/compare/v1.18.0...HEAD
+[1.18.0]: https://github.com/urfave/cli/compare/v1.17.0...v1.18.0
+[1.17.0]: https://github.com/urfave/cli/compare/v1.16.0...v1.17.0
+[1.16.0]: https://github.com/urfave/cli/compare/v1.15.0...v1.16.0
+[1.15.0]: https://github.com/urfave/cli/compare/v1.14.0...v1.15.0
+[1.14.0]: https://github.com/urfave/cli/compare/v1.13.0...v1.14.0
+[1.13.0]: https://github.com/urfave/cli/compare/v1.12.0...v1.13.0
+[1.12.0]: https://github.com/urfave/cli/compare/v1.11.1...v1.12.0
+[1.11.1]: https://github.com/urfave/cli/compare/v1.11.0...v1.11.1
+[1.11.0]: https://github.com/urfave/cli/compare/v1.10.2...v1.11.0
+[1.10.2]: https://github.com/urfave/cli/compare/v1.10.1...v1.10.2
+[1.10.1]: https://github.com/urfave/cli/compare/v1.10.0...v1.10.1
+[1.10.0]: https://github.com/urfave/cli/compare/v1.9.0...v1.10.0
+[1.9.0]: https://github.com/urfave/cli/compare/v1.8.0...v1.9.0
+[1.8.0]: https://github.com/urfave/cli/compare/v1.7.1...v1.8.0
+[1.7.1]: https://github.com/urfave/cli/compare/v1.7.0...v1.7.1
+[1.7.0]: https://github.com/urfave/cli/compare/v1.6.0...v1.7.0
+[1.6.0]: https://github.com/urfave/cli/compare/v1.5.0...v1.6.0
+[1.5.0]: https://github.com/urfave/cli/compare/v1.4.1...v1.5.0
+[1.4.1]: https://github.com/urfave/cli/compare/v1.4.0...v1.4.1
+[1.4.0]: https://github.com/urfave/cli/compare/v1.3.1...v1.4.0
+[1.3.1]: https://github.com/urfave/cli/compare/v1.3.0...v1.3.1
+[1.3.0]: https://github.com/urfave/cli/compare/v1.2.0...v1.3.0
+[1.2.0]: https://github.com/urfave/cli/compare/v1.1.0...v1.2.0
+[1.1.0]: https://github.com/urfave/cli/compare/v1.0.0...v1.1.0
+[1.0.0]: https://github.com/urfave/cli/compare/v0.1.0...v1.0.0
diff --git a/vendor/github.com/codegangsta/cli/LICENSE b/vendor/github.com/codegangsta/cli/LICENSE
new file mode 100644
index 0000000..42a597e
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Jeremy Saenz & Contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/codegangsta/cli/README.md b/vendor/github.com/codegangsta/cli/README.md
new file mode 100644
index 0000000..ebb1d74
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/README.md
@@ -0,0 +1,1309 @@
+cli
+===
+
+[](https://travis-ci.org/urfave/cli)
+[](https://ci.appveyor.com/project/urfave/cli)
+[](https://godoc.org/github.com/urfave/cli)
+[](https://codebeat.co/projects/github-com-urfave-cli)
+[](https://goreportcard.com/report/urfave/cli)
+[](http://gocover.io/github.com/urfave/cli) /
+[](http://gocover.io/github.com/urfave/cli/altsrc)
+
+**Notice:** This is the library formerly known as
+`github.com/codegangsta/cli` -- Github will automatically redirect requests
+to this repository, but we recommend updating your references for clarity.
+
+cli is a simple, fast, and fun package for building command line apps in Go. The
+goal is to enable developers to write fast and distributable command line
+applications in an expressive way.
+
+
+
+- [Overview](#overview)
+- [Installation](#installation)
+ * [Supported platforms](#supported-platforms)
+ * [Using the `v2` branch](#using-the-v2-branch)
+ * [Pinning to the `v1` branch](#pinning-to-the-v1-branch)
+- [Getting Started](#getting-started)
+- [Examples](#examples)
+ * [Arguments](#arguments)
+ * [Flags](#flags)
+ + [Placeholder Values](#placeholder-values)
+ + [Alternate Names](#alternate-names)
+ + [Values from the Environment](#values-from-the-environment)
+ + [Values from alternate input sources (YAML and others)](#values-from-alternate-input-sources-yaml-and-others)
+ * [Subcommands](#subcommands)
+ * [Subcommands categories](#subcommands-categories)
+ * [Exit code](#exit-code)
+ * [Bash Completion](#bash-completion)
+ + [Enabling](#enabling)
+ + [Distribution](#distribution)
+ + [Customization](#customization)
+ * [Generated Help Text](#generated-help-text)
+ + [Customization](#customization-1)
+ * [Version Flag](#version-flag)
+ + [Customization](#customization-2)
+ + [Full API Example](#full-api-example)
+- [Contribution Guidelines](#contribution-guidelines)
+
+
+
+## Overview
+
+Command line apps are usually so tiny that there is absolutely no reason why
+your code should *not* be self-documenting. Things like generating help text and
+parsing command flags/options should not hinder productivity when writing a
+command line app.
+
+**This is where cli comes into play.** cli makes command line programming fun,
+organized, and expressive!
+
+## Installation
+
+Make sure you have a working Go environment. Go version 1.1+ is required for
+core cli, whereas use of the [`./altsrc`](./altsrc) input extensions requires Go
+version 1.2+. [See the install
+instructions](http://golang.org/doc/install.html).
+
+To install cli, simply run:
+```
+$ go get github.com/urfave/cli
+```
+
+Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands
+can be easily used:
+```
+export PATH=$PATH:$GOPATH/bin
+```
+
+### Supported platforms
+
+cli is tested against multiple versions of Go on Linux, and against the latest
+released version of Go on OS X and Windows. For full details, see
+[`./.travis.yml`](./.travis.yml) and [`./appveyor.yml`](./appveyor.yml).
+
+### Using the `v2` branch
+
+**Warning**: The `v2` branch is currently unreleased and considered unstable.
+
+There is currently a long-lived branch named `v2` that is intended to land as
+the new `master` branch once development there has settled down. The current
+`master` branch (mirrored as `v1`) is being manually merged into `v2` on
+an irregular human-based schedule, but generally if one wants to "upgrade" to
+`v2` *now* and accept the volatility (read: "awesomeness") that comes along with
+that, please use whatever version pinning of your preference, such as via
+`gopkg.in`:
+
+```
+$ go get gopkg.in/urfave/cli.v2
+```
+
+``` go
+...
+import (
+ "gopkg.in/urfave/cli.v2" // imports as package "cli"
+)
+...
+```
+
+### Pinning to the `v1` branch
+
+Similarly to the section above describing use of the `v2` branch, if one wants
+to avoid any unexpected compatibility pains once `v2` becomes `master`, then
+pinning to the `v1` branch is an acceptable option, e.g.:
+
+```
+$ go get gopkg.in/urfave/cli.v1
+```
+
+``` go
+...
+import (
+ "gopkg.in/urfave/cli.v1" // imports as package "cli"
+)
+...
+```
+
+## Getting Started
+
+One of the philosophies behind cli is that an API should be playful and full of
+discovery. So a cli app can be as little as one line of code in `main()`.
+
+
+``` go
+package main
+
+import (
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ cli.NewApp().Run(os.Args)
+}
+```
+
+This app will run and show help text, but is not very useful. Let's give an
+action to execute and some help documentation:
+
+
+``` go
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+ app.Name = "boom"
+ app.Usage = "make an explosive entrance"
+ app.Action = func(c *cli.Context) error {
+ fmt.Println("boom! I say!")
+ return nil
+ }
+
+ app.Run(os.Args)
+}
+```
+
+Running this already gives you a ton of functionality, plus support for things
+like subcommands and flags, which are covered below.
+
+## Examples
+
+Being a programmer can be a lonely job. Thankfully by the power of automation
+that is not the case! Let's create a greeter app to fend off our demons of
+loneliness!
+
+Start by creating a directory named `greet`, and within it, add a file,
+`greet.go` with the following code in it:
+
+
+``` go
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+ app.Name = "greet"
+ app.Usage = "fight the loneliness!"
+ app.Action = func(c *cli.Context) error {
+ fmt.Println("Hello friend!")
+ return nil
+ }
+
+ app.Run(os.Args)
+}
+```
+
+Install our command to the `$GOPATH/bin` directory:
+
+```
+$ go install
+```
+
+Finally run our new command:
+
+```
+$ greet
+Hello friend!
+```
+
+cli also generates neat help text:
+
+```
+$ greet help
+NAME:
+ greet - fight the loneliness!
+
+USAGE:
+ greet [global options] command [command options] [arguments...]
+
+VERSION:
+ 0.0.0
+
+COMMANDS:
+ help, h Shows a list of commands or help for one command
+
+GLOBAL OPTIONS
+ --version Shows version information
+```
+
+### Arguments
+
+You can lookup arguments by calling the `Args` function on `cli.Context`, e.g.:
+
+
+``` go
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+
+ app.Action = func(c *cli.Context) error {
+ fmt.Printf("Hello %q", c.Args().Get(0))
+ return nil
+ }
+
+ app.Run(os.Args)
+}
+```
+
+### Flags
+
+Setting and querying flags is simple.
+
+
+``` go
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+
+ app.Flags = []cli.Flag {
+ cli.StringFlag{
+ Name: "lang",
+ Value: "english",
+ Usage: "language for the greeting",
+ },
+ }
+
+ app.Action = func(c *cli.Context) error {
+ name := "Nefertiti"
+ if c.NArg() > 0 {
+ name = c.Args().Get(0)
+ }
+ if c.String("lang") == "spanish" {
+ fmt.Println("Hola", name)
+ } else {
+ fmt.Println("Hello", name)
+ }
+ return nil
+ }
+
+ app.Run(os.Args)
+}
+```
+
+You can also set a destination variable for a flag, to which the content will be
+scanned.
+
+
+``` go
+package main
+
+import (
+ "os"
+ "fmt"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ var language string
+
+ app := cli.NewApp()
+
+ app.Flags = []cli.Flag {
+ cli.StringFlag{
+ Name: "lang",
+ Value: "english",
+ Usage: "language for the greeting",
+ Destination: &language,
+ },
+ }
+
+ app.Action = func(c *cli.Context) error {
+ name := "someone"
+ if c.NArg() > 0 {
+ name = c.Args()[0]
+ }
+ if language == "spanish" {
+ fmt.Println("Hola", name)
+ } else {
+ fmt.Println("Hello", name)
+ }
+ return nil
+ }
+
+ app.Run(os.Args)
+}
+```
+
+See full list of flags at http://godoc.org/github.com/urfave/cli
+
+#### Placeholder Values
+
+Sometimes it's useful to specify a flag's value within the usage string itself.
+Such placeholders are indicated with back quotes.
+
+For example this:
+
+
+```go
+package main
+
+import (
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+
+ app.Flags = []cli.Flag{
+ cli.StringFlag{
+ Name: "config, c",
+ Usage: "Load configuration from `FILE`",
+ },
+ }
+
+ app.Run(os.Args)
+}
+```
+
+Will result in help output like:
+
+```
+--config FILE, -c FILE Load configuration from FILE
+```
+
+Note that only the first placeholder is used. Subsequent back-quoted words will
+be left as-is.
+
+#### Alternate Names
+
+You can set alternate (or short) names for flags by providing a comma-delimited
+list for the `Name`. e.g.
+
+
+``` go
+package main
+
+import (
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+
+ app.Flags = []cli.Flag {
+ cli.StringFlag{
+ Name: "lang, l",
+ Value: "english",
+ Usage: "language for the greeting",
+ },
+ }
+
+ app.Run(os.Args)
+}
+```
+
+That flag can then be set with `--lang spanish` or `-l spanish`. Note that
+giving two different forms of the same flag in the same command invocation is an
+error.
+
+#### Values from the Environment
+
+You can also have the default value set from the environment via `EnvVar`. e.g.
+
+
+``` go
+package main
+
+import (
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+
+ app.Flags = []cli.Flag {
+ cli.StringFlag{
+ Name: "lang, l",
+ Value: "english",
+ Usage: "language for the greeting",
+ EnvVar: "APP_LANG",
+ },
+ }
+
+ app.Run(os.Args)
+}
+```
+
+The `EnvVar` may also be given as a comma-delimited "cascade", where the first
+environment variable that resolves is used as the default.
+
+
+``` go
+package main
+
+import (
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+
+ app.Flags = []cli.Flag {
+ cli.StringFlag{
+ Name: "lang, l",
+ Value: "english",
+ Usage: "language for the greeting",
+ EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
+ },
+ }
+
+ app.Run(os.Args)
+}
+```
+
+#### Values from alternate input sources (YAML and others)
+
+There is a separate package altsrc that adds support for getting flag values
+from other input sources like YAML.
+
+In order to get values for a flag from an alternate input source the following
+code would be added to wrap an existing cli.Flag like below:
+
+``` go
+ altsrc.NewIntFlag(cli.IntFlag{Name: "test"})
+```
+
+Initialization must also occur for these flags. Below is an example initializing
+getting data from a yaml file below.
+
+``` go
+ command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
+```
+
+The code above will use the "load" string as a flag name to get the file name of
+a yaml file from the cli.Context. It will then use that file name to initialize
+the yaml input source for any flags that are defined on that command. As a note
+the "load" flag used would also have to be defined on the command flags in order
+for this code snipped to work.
+
+Currently only YAML files are supported but developers can add support for other
+input sources by implementing the altsrc.InputSourceContext for their given
+sources.
+
+Here is a more complete sample of a command using YAML support:
+
+
+``` go
+package notmain
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/urfave/cli"
+ "github.com/urfave/cli/altsrc"
+)
+
+func main() {
+ app := cli.NewApp()
+
+ flags := []cli.Flag{
+ altsrc.NewIntFlag(cli.IntFlag{Name: "test"}),
+ cli.StringFlag{Name: "load"},
+ }
+
+ app.Action = func(c *cli.Context) error {
+ fmt.Println("yaml ist rad")
+ return nil
+ }
+
+ app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load"))
+ app.Flags = flags
+
+ app.Run(os.Args)
+}
+```
+
+### Subcommands
+
+Subcommands can be defined for a more git-like command line app.
+
+
+```go
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+
+ app.Commands = []cli.Command{
+ {
+ Name: "add",
+ Aliases: []string{"a"},
+ Usage: "add a task to the list",
+ Action: func(c *cli.Context) error {
+ fmt.Println("added task: ", c.Args().First())
+ return nil
+ },
+ },
+ {
+ Name: "complete",
+ Aliases: []string{"c"},
+ Usage: "complete a task on the list",
+ Action: func(c *cli.Context) error {
+ fmt.Println("completed task: ", c.Args().First())
+ return nil
+ },
+ },
+ {
+ Name: "template",
+ Aliases: []string{"t"},
+ Usage: "options for task templates",
+ Subcommands: []cli.Command{
+ {
+ Name: "add",
+ Usage: "add a new template",
+ Action: func(c *cli.Context) error {
+ fmt.Println("new task template: ", c.Args().First())
+ return nil
+ },
+ },
+ {
+ Name: "remove",
+ Usage: "remove an existing template",
+ Action: func(c *cli.Context) error {
+ fmt.Println("removed task template: ", c.Args().First())
+ return nil
+ },
+ },
+ },
+ },
+ }
+
+ app.Run(os.Args)
+}
+```
+
+### Subcommands categories
+
+For additional organization in apps that have many subcommands, you can
+associate a category for each command to group them together in the help
+output.
+
+E.g.
+
+```go
+package main
+
+import (
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+
+ app.Commands = []cli.Command{
+ {
+ Name: "noop",
+ },
+ {
+ Name: "add",
+ Category: "template",
+ },
+ {
+ Name: "remove",
+ Category: "template",
+ },
+ }
+
+ app.Run(os.Args)
+}
+```
+
+Will include:
+
+```
+COMMANDS:
+ noop
+
+ Template actions:
+ add
+ remove
+```
+
+### Exit code
+
+Calling `App.Run` will not automatically call `os.Exit`, which means that by
+default the exit code will "fall through" to being `0`. An explicit exit code
+may be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a
+`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.:
+
+``` go
+package main
+
+import (
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ app := cli.NewApp()
+ app.Flags = []cli.Flag{
+ cli.BoolTFlag{
+ Name: "ginger-crouton",
+ Usage: "is it in the soup?",
+ },
+ }
+ app.Action = func(ctx *cli.Context) error {
+ if !ctx.Bool("ginger-crouton") {
+ return cli.NewExitError("it is not in the soup", 86)
+ }
+ return nil
+ }
+
+ app.Run(os.Args)
+}
+```
+
+### Bash Completion
+
+You can enable completion commands by setting the `EnableBashCompletion`
+flag on the `App` object. By default, this setting will only auto-complete to
+show an app's subcommands, but you can write your own completion methods for
+the App or its subcommands.
+
+
+``` go
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
+
+ app := cli.NewApp()
+ app.EnableBashCompletion = true
+ app.Commands = []cli.Command{
+ {
+ Name: "complete",
+ Aliases: []string{"c"},
+ Usage: "complete a task on the list",
+ Action: func(c *cli.Context) error {
+ fmt.Println("completed task: ", c.Args().First())
+ return nil
+ },
+ BashComplete: func(c *cli.Context) {
+ // This will complete if no args are passed
+ if c.NArg() > 0 {
+ return
+ }
+ for _, t := range tasks {
+ fmt.Println(t)
+ }
+ },
+ },
+ }
+
+ app.Run(os.Args)
+}
+```
+
+#### Enabling
+
+Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while
+setting the `PROG` variable to the name of your program:
+
+`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
+
+#### Distribution
+
+Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename
+it to the name of the program you wish to add autocomplete support for (or
+automatically install it there if you are distributing a package). Don't forget
+to source the file to make it active in the current shell.
+
+```
+sudo cp src/bash_autocomplete /etc/bash_completion.d/
+source /etc/bash_completion.d/
+```
+
+Alternatively, you can just document that users should source the generic
+`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set
+to the name of their program (as above).
+
+#### Customization
+
+The default bash completion flag (`--generate-bash-completion`) is defined as
+`cli.BashCompletionFlag`, and may be redefined if desired, e.g.:
+
+
+``` go
+package main
+
+import (
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ cli.BashCompletionFlag = cli.BoolFlag{
+ Name: "compgen",
+ Hidden: true,
+ }
+
+ app := cli.NewApp()
+ app.EnableBashCompletion = true
+ app.Commands = []cli.Command{
+ {
+ Name: "wat",
+ },
+ }
+ app.Run(os.Args)
+}
+```
+
+### Generated Help Text
+
+The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked
+by the cli internals in order to print generated help text for the app, command,
+or subcommand, and break execution.
+
+#### Customization
+
+All of the help text generation may be customized, and at multiple levels. The
+templates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and
+`SubcommandHelpTemplate` which may be reassigned or augmented, and full override
+is possible by assigning a compatible func to the `cli.HelpPrinter` variable,
+e.g.:
+
+
+``` go
+package main
+
+import (
+ "fmt"
+ "io"
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ // EXAMPLE: Append to an existing template
+ cli.AppHelpTemplate = fmt.Sprintf(`%s
+
+WEBSITE: http://awesometown.example.com
+
+SUPPORT: support@awesometown.example.com
+
+`, cli.AppHelpTemplate)
+
+ // EXAMPLE: Override a template
+ cli.AppHelpTemplate = `NAME:
+ {{.Name}} - {{.Usage}}
+USAGE:
+ {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command
+[command options]{{end}} {{if
+.ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
+ {{if len .Authors}}
+AUTHOR(S):
+ {{range .Authors}}{{ . }}{{end}}
+ {{end}}{{if .Commands}}
+COMMANDS:
+{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"
+}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
+GLOBAL OPTIONS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}{{end}}{{if .Copyright }}
+COPYRIGHT:
+ {{.Copyright}}
+ {{end}}{{if .Version}}
+VERSION:
+ {{.Version}}
+ {{end}}
+`
+
+ // EXAMPLE: Replace the `HelpPrinter` func
+ cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
+ fmt.Println("Ha HA. I pwnd the help!!1")
+ }
+
+ cli.NewApp().Run(os.Args)
+}
+```
+
+The default flag may be customized to something other than `-h/--help` by
+setting `cli.HelpFlag`, e.g.:
+
+
+``` go
+package main
+
+import (
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ cli.HelpFlag = cli.BoolFlag{
+ Name: "halp, haaaaalp",
+ Usage: "HALP",
+ EnvVar: "SHOW_HALP,HALPPLZ",
+ }
+
+ cli.NewApp().Run(os.Args)
+}
+```
+
+### Version Flag
+
+The default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which
+is checked by the cli internals in order to print the `App.Version` via
+`cli.VersionPrinter` and break execution.
+
+#### Customization
+
+The default flag may be cusomized to something other than `-v/--version` by
+setting `cli.VersionFlag`, e.g.:
+
+
+``` go
+package main
+
+import (
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+func main() {
+ cli.VersionFlag = cli.BoolFlag{
+ Name: "print-version, V",
+ Usage: "print only the version",
+ }
+
+ app := cli.NewApp()
+ app.Name = "partay"
+ app.Version = "v19.99.0"
+ app.Run(os.Args)
+}
+```
+
+Alternatively, the version printer at `cli.VersionPrinter` may be overridden, e.g.:
+
+
+``` go
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/urfave/cli"
+)
+
+var (
+ Revision = "fafafaf"
+)
+
+func main() {
+ cli.VersionPrinter = func(c *cli.Context) {
+ fmt.Printf("version=%s revision=%s\n", c.App.Version, Revision)
+ }
+
+ app := cli.NewApp()
+ app.Name = "partay"
+ app.Version = "v19.99.0"
+ app.Run(os.Args)
+}
+```
+
+#### Full API Example
+
+**Notice**: This is a contrived (functioning) example meant strictly for API
+demonstration purposes. Use of one's imagination is encouraged.
+
+
+``` go
+package main
+
+import (
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "time"
+
+ "github.com/urfave/cli"
+)
+
+func init() {
+ cli.AppHelpTemplate += "\nCUSTOMIZED: you bet ur muffins\n"
+ cli.CommandHelpTemplate += "\nYMMV\n"
+ cli.SubcommandHelpTemplate += "\nor something\n"
+
+ cli.HelpFlag = cli.BoolFlag{Name: "halp"}
+ cli.BashCompletionFlag = cli.BoolFlag{Name: "compgen", Hidden: true}
+ cli.VersionFlag = cli.BoolFlag{Name: "print-version, V"}
+
+ cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
+ fmt.Fprintf(w, "best of luck to you\n")
+ }
+ cli.VersionPrinter = func(c *cli.Context) {
+ fmt.Fprintf(c.App.Writer, "version=%s\n", c.App.Version)
+ }
+ cli.OsExiter = func(c int) {
+ fmt.Fprintf(cli.ErrWriter, "refusing to exit %d\n", c)
+ }
+ cli.ErrWriter = ioutil.Discard
+ cli.FlagStringer = func(fl cli.Flag) string {
+ return fmt.Sprintf("\t\t%s", fl.GetName())
+ }
+}
+
+type hexWriter struct{}
+
+func (w *hexWriter) Write(p []byte) (int, error) {
+ for _, b := range p {
+ fmt.Printf("%x", b)
+ }
+ fmt.Printf("\n")
+
+ return len(p), nil
+}
+
+type genericType struct{
+ s string
+}
+
+func (g *genericType) Set(value string) error {
+ g.s = value
+ return nil
+}
+
+func (g *genericType) String() string {
+ return g.s
+}
+
+func main() {
+ app := cli.NewApp()
+ app.Name = "kənˈtrīv"
+ app.Version = "v19.99.0"
+ app.Compiled = time.Now()
+ app.Authors = []cli.Author{
+ cli.Author{
+ Name: "Example Human",
+ Email: "human@example.com",
+ },
+ }
+ app.Copyright = "(c) 1999 Serious Enterprise"
+ app.HelpName = "contrive"
+ app.Usage = "demonstrate available API"
+ app.UsageText = "contrive - demonstrating the available API"
+ app.ArgsUsage = "[args and such]"
+ app.Commands = []cli.Command{
+ cli.Command{
+ Name: "doo",
+ Aliases: []string{"do"},
+ Category: "motion",
+ Usage: "do the doo",
+ UsageText: "doo - does the dooing",
+ Description: "no really, there is a lot of dooing to be done",
+ ArgsUsage: "[arrgh]",
+ Flags: []cli.Flag{
+ cli.BoolFlag{Name: "forever, forevvarr"},
+ },
+ Subcommands: cli.Commands{
+ cli.Command{
+ Name: "wop",
+ Action: wopAction,
+ },
+ },
+ SkipFlagParsing: false,
+ HideHelp: false,
+ Hidden: false,
+ HelpName: "doo!",
+ BashComplete: func(c *cli.Context) {
+ fmt.Fprintf(c.App.Writer, "--better\n")
+ },
+ Before: func(c *cli.Context) error {
+ fmt.Fprintf(c.App.Writer, "brace for impact\n")
+ return nil
+ },
+ After: func(c *cli.Context) error {
+ fmt.Fprintf(c.App.Writer, "did we lose anyone?\n")
+ return nil
+ },
+ Action: func(c *cli.Context) error {
+ c.Command.FullName()
+ c.Command.HasName("wop")
+ c.Command.Names()
+ c.Command.VisibleFlags()
+ fmt.Fprintf(c.App.Writer, "dodododododoodododddooooododododooo\n")
+ if c.Bool("forever") {
+ c.Command.Run(c)
+ }
+ return nil
+ },
+ OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error {
+ fmt.Fprintf(c.App.Writer, "for shame\n")
+ return err
+ },
+ },
+ }
+ app.Flags = []cli.Flag{
+ cli.BoolFlag{Name: "fancy"},
+ cli.BoolTFlag{Name: "fancier"},
+ cli.DurationFlag{Name: "howlong, H", Value: time.Second * 3},
+ cli.Float64Flag{Name: "howmuch"},
+ cli.GenericFlag{Name: "wat", Value: &genericType{}},
+ cli.Int64Flag{Name: "longdistance"},
+ cli.Int64SliceFlag{Name: "intervals"},
+ cli.IntFlag{Name: "distance"},
+ cli.IntSliceFlag{Name: "times"},
+ cli.StringFlag{Name: "dance-move, d"},
+ cli.StringSliceFlag{Name: "names, N"},
+ cli.UintFlag{Name: "age"},
+ cli.Uint64Flag{Name: "bigage"},
+ }
+ app.EnableBashCompletion = true
+ app.HideHelp = false
+ app.HideVersion = false
+ app.BashComplete = func(c *cli.Context) {
+ fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n")
+ }
+ app.Before = func(c *cli.Context) error {
+ fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n")
+ return nil
+ }
+ app.After = func(c *cli.Context) error {
+ fmt.Fprintf(c.App.Writer, "Phew!\n")
+ return nil
+ }
+ app.CommandNotFound = func(c *cli.Context, command string) {
+ fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command)
+ }
+ app.OnUsageError = func(c *cli.Context, err error, isSubcommand bool) error {
+ if isSubcommand {
+ return err
+ }
+
+ fmt.Fprintf(c.App.Writer, "WRONG: %#v\n", err)
+ return nil
+ }
+ app.Action = func(c *cli.Context) error {
+ cli.DefaultAppComplete(c)
+ cli.HandleExitCoder(errors.New("not an exit coder, though"))
+ cli.ShowAppHelp(c)
+ cli.ShowCommandCompletions(c, "nope")
+ cli.ShowCommandHelp(c, "also-nope")
+ cli.ShowCompletions(c)
+ cli.ShowSubcommandHelp(c)
+ cli.ShowVersion(c)
+
+ categories := c.App.Categories()
+ categories.AddCommand("sounds", cli.Command{
+ Name: "bloop",
+ })
+
+ for _, category := range c.App.Categories() {
+ fmt.Fprintf(c.App.Writer, "%s\n", category.Name)
+ fmt.Fprintf(c.App.Writer, "%#v\n", category.Commands)
+ fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands())
+ }
+
+ fmt.Printf("%#v\n", c.App.Command("doo"))
+ if c.Bool("infinite") {
+ c.App.Run([]string{"app", "doo", "wop"})
+ }
+
+ if c.Bool("forevar") {
+ c.App.RunAsSubcommand(c)
+ }
+ c.App.Setup()
+ fmt.Printf("%#v\n", c.App.VisibleCategories())
+ fmt.Printf("%#v\n", c.App.VisibleCommands())
+ fmt.Printf("%#v\n", c.App.VisibleFlags())
+
+ fmt.Printf("%#v\n", c.Args().First())
+ if len(c.Args()) > 0 {
+ fmt.Printf("%#v\n", c.Args()[1])
+ }
+ fmt.Printf("%#v\n", c.Args().Present())
+ fmt.Printf("%#v\n", c.Args().Tail())
+
+ set := flag.NewFlagSet("contrive", 0)
+ nc := cli.NewContext(c.App, set, c)
+
+ fmt.Printf("%#v\n", nc.Args())
+ fmt.Printf("%#v\n", nc.Bool("nope"))
+ fmt.Printf("%#v\n", nc.BoolT("nerp"))
+ fmt.Printf("%#v\n", nc.Duration("howlong"))
+ fmt.Printf("%#v\n", nc.Float64("hay"))
+ fmt.Printf("%#v\n", nc.Generic("bloop"))
+ fmt.Printf("%#v\n", nc.Int64("bonk"))
+ fmt.Printf("%#v\n", nc.Int64Slice("burnks"))
+ fmt.Printf("%#v\n", nc.Int("bips"))
+ fmt.Printf("%#v\n", nc.IntSlice("blups"))
+ fmt.Printf("%#v\n", nc.String("snurt"))
+ fmt.Printf("%#v\n", nc.StringSlice("snurkles"))
+ fmt.Printf("%#v\n", nc.Uint("flub"))
+ fmt.Printf("%#v\n", nc.Uint64("florb"))
+ fmt.Printf("%#v\n", nc.GlobalBool("global-nope"))
+ fmt.Printf("%#v\n", nc.GlobalBoolT("global-nerp"))
+ fmt.Printf("%#v\n", nc.GlobalDuration("global-howlong"))
+ fmt.Printf("%#v\n", nc.GlobalFloat64("global-hay"))
+ fmt.Printf("%#v\n", nc.GlobalGeneric("global-bloop"))
+ fmt.Printf("%#v\n", nc.GlobalInt("global-bips"))
+ fmt.Printf("%#v\n", nc.GlobalIntSlice("global-blups"))
+ fmt.Printf("%#v\n", nc.GlobalString("global-snurt"))
+ fmt.Printf("%#v\n", nc.GlobalStringSlice("global-snurkles"))
+
+ fmt.Printf("%#v\n", nc.FlagNames())
+ fmt.Printf("%#v\n", nc.GlobalFlagNames())
+ fmt.Printf("%#v\n", nc.GlobalIsSet("wat"))
+ fmt.Printf("%#v\n", nc.GlobalSet("wat", "nope"))
+ fmt.Printf("%#v\n", nc.NArg())
+ fmt.Printf("%#v\n", nc.NumFlags())
+ fmt.Printf("%#v\n", nc.Parent())
+
+ nc.Set("wat", "also-nope")
+
+ ec := cli.NewExitError("ohwell", 86)
+ fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode())
+ fmt.Printf("made it!\n")
+ return ec
+ }
+
+ if os.Getenv("HEXY") != "" {
+ app.Writer = &hexWriter{}
+ app.ErrWriter = &hexWriter{}
+ }
+
+ app.Metadata = map[string]interface{}{
+ "layers": "many",
+ "explicable": false,
+ "whatever-values": 19.99,
+ }
+
+ app.Run(os.Args)
+}
+
+func wopAction(c *cli.Context) error {
+ fmt.Fprintf(c.App.Writer, ":wave: over here, eh\n")
+ return nil
+}
+```
+
+## Contribution Guidelines
+
+Feel free to put up a pull request to fix a bug or maybe add a feature. I will
+give it a code review and make sure that it does not break backwards
+compatibility. If I or any other collaborators agree that it is in line with
+the vision of the project, we will work with you to get the code into
+a mergeable state and merge it into the master branch.
+
+If you have contributed something significant to the project, we will most
+likely add you as a collaborator. As a collaborator you are given the ability
+to merge others pull requests. It is very important that new code does not
+break existing code, so be careful about what code you do choose to merge.
+
+If you feel like you have contributed to the project but have not yet been
+added as a collaborator, we probably forgot to add you, please open an issue.
diff --git a/vendor/github.com/codegangsta/cli/altsrc/flag.go b/vendor/github.com/codegangsta/cli/altsrc/flag.go
new file mode 100644
index 0000000..3e44d02
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/altsrc/flag.go
@@ -0,0 +1,439 @@
+package altsrc
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/urfave/cli"
+)
+
+// FlagInputSourceExtension is an extension interface of cli.Flag that
+// allows a value to be set on the existing parsed flags.
+type FlagInputSourceExtension interface {
+ cli.Flag
+ ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error
+}
+
+// ApplyInputSourceValues iterates over all provided flags and
+// executes ApplyInputSourceValue on flags implementing the
+// FlagInputSourceExtension interface to initialize these flags
+// to an alternate input source.
+func ApplyInputSourceValues(context *cli.Context, inputSourceContext InputSourceContext, flags []cli.Flag) error {
+ for _, f := range flags {
+ inputSourceExtendedFlag, isType := f.(FlagInputSourceExtension)
+ if isType {
+ err := inputSourceExtendedFlag.ApplyInputSourceValue(context, inputSourceContext)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
+// InitInputSource is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new
+// input source based on the func provided. If there is no error it will then apply the new input source to any flags
+// that are supported by the input source
+func InitInputSource(flags []cli.Flag, createInputSource func() (InputSourceContext, error)) cli.BeforeFunc {
+ return func(context *cli.Context) error {
+ inputSource, err := createInputSource()
+ if err != nil {
+ return fmt.Errorf("Unable to create input source: inner error: \n'%v'", err.Error())
+ }
+
+ return ApplyInputSourceValues(context, inputSource, flags)
+ }
+}
+
+// InitInputSourceWithContext is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new
+// input source based on the func provided with potentially using existing cli.Context values to initialize itself. If there is
+// no error it will then apply the new input source to any flags that are supported by the input source
+func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(context *cli.Context) (InputSourceContext, error)) cli.BeforeFunc {
+ return func(context *cli.Context) error {
+ inputSource, err := createInputSource(context)
+ if err != nil {
+ return fmt.Errorf("Unable to create input source with context: inner error: \n'%v'", err.Error())
+ }
+
+ return ApplyInputSourceValues(context, inputSource, flags)
+ }
+}
+
+// GenericFlag is the flag type that wraps cli.GenericFlag to allow
+// for other values to be specified
+type GenericFlag struct {
+ cli.GenericFlag
+ set *flag.FlagSet
+}
+
+// NewGenericFlag creates a new GenericFlag
+func NewGenericFlag(flag cli.GenericFlag) *GenericFlag {
+ return &GenericFlag{GenericFlag: flag, set: nil}
+}
+
+// ApplyInputSourceValue applies a generic value to the flagSet if required
+func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
+ if f.set != nil {
+ if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
+ value, err := isc.Generic(f.GenericFlag.Name)
+ if err != nil {
+ return err
+ }
+ if value != nil {
+ eachName(f.Name, func(name string) {
+ f.set.Set(f.Name, value.String())
+ })
+ }
+ }
+ }
+
+ return nil
+}
+
+// Apply saves the flagSet for later usage then calls
+// the wrapped GenericFlag.Apply
+func (f *GenericFlag) Apply(set *flag.FlagSet) {
+ f.set = set
+ f.GenericFlag.Apply(set)
+}
+
+// StringSliceFlag is the flag type that wraps cli.StringSliceFlag to allow
+// for other values to be specified
+type StringSliceFlag struct {
+ cli.StringSliceFlag
+ set *flag.FlagSet
+}
+
+// NewStringSliceFlag creates a new StringSliceFlag
+func NewStringSliceFlag(flag cli.StringSliceFlag) *StringSliceFlag {
+ return &StringSliceFlag{StringSliceFlag: flag, set: nil}
+}
+
+// ApplyInputSourceValue applies a StringSlice value to the flagSet if required
+func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
+ if f.set != nil {
+ if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
+ value, err := isc.StringSlice(f.StringSliceFlag.Name)
+ if err != nil {
+ return err
+ }
+ if value != nil {
+ var sliceValue cli.StringSlice = value
+ eachName(f.Name, func(name string) {
+ underlyingFlag := f.set.Lookup(f.Name)
+ if underlyingFlag != nil {
+ underlyingFlag.Value = &sliceValue
+ }
+ })
+ }
+ }
+ }
+ return nil
+}
+
+// Apply saves the flagSet for later usage then calls
+// the wrapped StringSliceFlag.Apply
+func (f *StringSliceFlag) Apply(set *flag.FlagSet) {
+ f.set = set
+ f.StringSliceFlag.Apply(set)
+}
+
+// IntSliceFlag is the flag type that wraps cli.IntSliceFlag to allow
+// for other values to be specified
+type IntSliceFlag struct {
+ cli.IntSliceFlag
+ set *flag.FlagSet
+}
+
+// NewIntSliceFlag creates a new IntSliceFlag
+func NewIntSliceFlag(flag cli.IntSliceFlag) *IntSliceFlag {
+ return &IntSliceFlag{IntSliceFlag: flag, set: nil}
+}
+
+// ApplyInputSourceValue applies a IntSlice value if required
+func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
+ if f.set != nil {
+ if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
+ value, err := isc.IntSlice(f.IntSliceFlag.Name)
+ if err != nil {
+ return err
+ }
+ if value != nil {
+ var sliceValue cli.IntSlice = value
+ eachName(f.Name, func(name string) {
+ underlyingFlag := f.set.Lookup(f.Name)
+ if underlyingFlag != nil {
+ underlyingFlag.Value = &sliceValue
+ }
+ })
+ }
+ }
+ }
+ return nil
+}
+
+// Apply saves the flagSet for later usage then calls
+// the wrapped IntSliceFlag.Apply
+func (f *IntSliceFlag) Apply(set *flag.FlagSet) {
+ f.set = set
+ f.IntSliceFlag.Apply(set)
+}
+
+// BoolFlag is the flag type that wraps cli.BoolFlag to allow
+// for other values to be specified
+type BoolFlag struct {
+ cli.BoolFlag
+ set *flag.FlagSet
+}
+
+// NewBoolFlag creates a new BoolFlag
+func NewBoolFlag(flag cli.BoolFlag) *BoolFlag {
+ return &BoolFlag{BoolFlag: flag, set: nil}
+}
+
+// ApplyInputSourceValue applies a Bool value to the flagSet if required
+func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
+ if f.set != nil {
+ if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
+ value, err := isc.Bool(f.BoolFlag.Name)
+ if err != nil {
+ return err
+ }
+ if value {
+ eachName(f.Name, func(name string) {
+ f.set.Set(f.Name, strconv.FormatBool(value))
+ })
+ }
+ }
+ }
+ return nil
+}
+
+// Apply saves the flagSet for later usage then calls
+// the wrapped BoolFlag.Apply
+func (f *BoolFlag) Apply(set *flag.FlagSet) {
+ f.set = set
+ f.BoolFlag.Apply(set)
+}
+
+// BoolTFlag is the flag type that wraps cli.BoolTFlag to allow
+// for other values to be specified
+type BoolTFlag struct {
+ cli.BoolTFlag
+ set *flag.FlagSet
+}
+
+// NewBoolTFlag creates a new BoolTFlag
+func NewBoolTFlag(flag cli.BoolTFlag) *BoolTFlag {
+ return &BoolTFlag{BoolTFlag: flag, set: nil}
+}
+
+// ApplyInputSourceValue applies a BoolT value to the flagSet if required
+func (f *BoolTFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
+ if f.set != nil {
+ if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
+ value, err := isc.BoolT(f.BoolTFlag.Name)
+ if err != nil {
+ return err
+ }
+ if !value {
+ eachName(f.Name, func(name string) {
+ f.set.Set(f.Name, strconv.FormatBool(value))
+ })
+ }
+ }
+ }
+ return nil
+}
+
+// Apply saves the flagSet for later usage then calls
+// the wrapped BoolTFlag.Apply
+func (f *BoolTFlag) Apply(set *flag.FlagSet) {
+ f.set = set
+
+ f.BoolTFlag.Apply(set)
+}
+
+// StringFlag is the flag type that wraps cli.StringFlag to allow
+// for other values to be specified
+type StringFlag struct {
+ cli.StringFlag
+ set *flag.FlagSet
+}
+
+// NewStringFlag creates a new StringFlag
+func NewStringFlag(flag cli.StringFlag) *StringFlag {
+ return &StringFlag{StringFlag: flag, set: nil}
+}
+
+// ApplyInputSourceValue applies a String value to the flagSet if required
+func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
+ if f.set != nil {
+ if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
+ value, err := isc.String(f.StringFlag.Name)
+ if err != nil {
+ return err
+ }
+ if value != "" {
+ eachName(f.Name, func(name string) {
+ f.set.Set(f.Name, value)
+ })
+ }
+ }
+ }
+ return nil
+}
+
+// Apply saves the flagSet for later usage then calls
+// the wrapped StringFlag.Apply
+func (f *StringFlag) Apply(set *flag.FlagSet) {
+ f.set = set
+
+ f.StringFlag.Apply(set)
+}
+
+// IntFlag is the flag type that wraps cli.IntFlag to allow
+// for other values to be specified
+type IntFlag struct {
+ cli.IntFlag
+ set *flag.FlagSet
+}
+
+// NewIntFlag creates a new IntFlag
+func NewIntFlag(flag cli.IntFlag) *IntFlag {
+ return &IntFlag{IntFlag: flag, set: nil}
+}
+
+// ApplyInputSourceValue applies a int value to the flagSet if required
+func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
+ if f.set != nil {
+ if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
+ value, err := isc.Int(f.IntFlag.Name)
+ if err != nil {
+ return err
+ }
+ if value > 0 {
+ eachName(f.Name, func(name string) {
+ f.set.Set(f.Name, strconv.FormatInt(int64(value), 10))
+ })
+ }
+ }
+ }
+ return nil
+}
+
+// Apply saves the flagSet for later usage then calls
+// the wrapped IntFlag.Apply
+func (f *IntFlag) Apply(set *flag.FlagSet) {
+ f.set = set
+ f.IntFlag.Apply(set)
+}
+
+// DurationFlag is the flag type that wraps cli.DurationFlag to allow
+// for other values to be specified
+type DurationFlag struct {
+ cli.DurationFlag
+ set *flag.FlagSet
+}
+
+// NewDurationFlag creates a new DurationFlag
+func NewDurationFlag(flag cli.DurationFlag) *DurationFlag {
+ return &DurationFlag{DurationFlag: flag, set: nil}
+}
+
+// ApplyInputSourceValue applies a Duration value to the flagSet if required
+func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
+ if f.set != nil {
+ if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
+ value, err := isc.Duration(f.DurationFlag.Name)
+ if err != nil {
+ return err
+ }
+ if value > 0 {
+ eachName(f.Name, func(name string) {
+ f.set.Set(f.Name, value.String())
+ })
+ }
+ }
+ }
+ return nil
+}
+
+// Apply saves the flagSet for later usage then calls
+// the wrapped DurationFlag.Apply
+func (f *DurationFlag) Apply(set *flag.FlagSet) {
+ f.set = set
+
+ f.DurationFlag.Apply(set)
+}
+
+// Float64Flag is the flag type that wraps cli.Float64Flag to allow
+// for other values to be specified
+type Float64Flag struct {
+ cli.Float64Flag
+ set *flag.FlagSet
+}
+
+// NewFloat64Flag creates a new Float64Flag
+func NewFloat64Flag(flag cli.Float64Flag) *Float64Flag {
+ return &Float64Flag{Float64Flag: flag, set: nil}
+}
+
+// ApplyInputSourceValue applies a Float64 value to the flagSet if required
+func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
+ if f.set != nil {
+ if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
+ value, err := isc.Float64(f.Float64Flag.Name)
+ if err != nil {
+ return err
+ }
+ if value > 0 {
+ floatStr := float64ToString(value)
+ eachName(f.Name, func(name string) {
+ f.set.Set(f.Name, floatStr)
+ })
+ }
+ }
+ }
+ return nil
+}
+
+// Apply saves the flagSet for later usage then calls
+// the wrapped Float64Flag.Apply
+func (f *Float64Flag) Apply(set *flag.FlagSet) {
+ f.set = set
+
+ f.Float64Flag.Apply(set)
+}
+
+func isEnvVarSet(envVars string) bool {
+ for _, envVar := range strings.Split(envVars, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ // TODO: Can't use this for bools as
+ // set means that it was true or false based on
+ // Bool flag type, should work for other types
+ if len(envVal) > 0 {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+func float64ToString(f float64) string {
+ return fmt.Sprintf("%v", f)
+}
+
+func eachName(longName string, fn func(string)) {
+ parts := strings.Split(longName, ",")
+ for _, name := range parts {
+ name = strings.Trim(name, " ")
+ fn(name)
+ }
+}
diff --git a/vendor/github.com/codegangsta/cli/altsrc/flag_test.go b/vendor/github.com/codegangsta/cli/altsrc/flag_test.go
new file mode 100644
index 0000000..218e9b8
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/altsrc/flag_test.go
@@ -0,0 +1,336 @@
+package altsrc
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/urfave/cli"
+)
+
+type testApplyInputSource struct {
+ Flag FlagInputSourceExtension
+ FlagName string
+ FlagSetName string
+ Expected string
+ ContextValueString string
+ ContextValue flag.Value
+ EnvVarValue string
+ EnvVarName string
+ MapValue interface{}
+}
+
+func TestGenericApplyInputSourceValue(t *testing.T) {
+ v := &Parser{"abc", "def"}
+ c := runTest(t, testApplyInputSource{
+ Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}}),
+ FlagName: "test",
+ MapValue: v,
+ })
+ expect(t, v, c.Generic("test"))
+}
+
+func TestGenericApplyInputSourceMethodContextSet(t *testing.T) {
+ p := &Parser{"abc", "def"}
+ c := runTest(t, testApplyInputSource{
+ Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}}),
+ FlagName: "test",
+ MapValue: &Parser{"efg", "hig"},
+ ContextValueString: p.String(),
+ })
+ expect(t, p, c.Generic("test"))
+}
+
+func TestGenericApplyInputSourceMethodEnvVarSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}, EnvVar: "TEST"}),
+ FlagName: "test",
+ MapValue: &Parser{"efg", "hij"},
+ EnvVarName: "TEST",
+ EnvVarValue: "abc,def",
+ })
+ expect(t, &Parser{"abc", "def"}, c.Generic("test"))
+}
+
+func TestStringSliceApplyInputSourceValue(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: []string{"hello", "world"},
+ })
+ expect(t, c.StringSlice("test"), []string{"hello", "world"})
+}
+
+func TestStringSliceApplyInputSourceMethodContextSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: []string{"hello", "world"},
+ ContextValueString: "ohno",
+ })
+ expect(t, c.StringSlice("test"), []string{"ohno"})
+}
+
+func TestStringSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test", EnvVar: "TEST"}),
+ FlagName: "test",
+ MapValue: []string{"hello", "world"},
+ EnvVarName: "TEST",
+ EnvVarValue: "oh,no",
+ })
+ expect(t, c.StringSlice("test"), []string{"oh", "no"})
+}
+
+func TestIntSliceApplyInputSourceValue(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: []int{1, 2},
+ })
+ expect(t, c.IntSlice("test"), []int{1, 2})
+}
+
+func TestIntSliceApplyInputSourceMethodContextSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: []int{1, 2},
+ ContextValueString: "3",
+ })
+ expect(t, c.IntSlice("test"), []int{3})
+}
+
+func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test", EnvVar: "TEST"}),
+ FlagName: "test",
+ MapValue: []int{1, 2},
+ EnvVarName: "TEST",
+ EnvVarValue: "3,4",
+ })
+ expect(t, c.IntSlice("test"), []int{3, 4})
+}
+
+func TestBoolApplyInputSourceMethodSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewBoolFlag(cli.BoolFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: true,
+ })
+ expect(t, true, c.Bool("test"))
+}
+
+func TestBoolApplyInputSourceMethodContextSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewBoolFlag(cli.BoolFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: false,
+ ContextValueString: "true",
+ })
+ expect(t, true, c.Bool("test"))
+}
+
+func TestBoolApplyInputSourceMethodEnvVarSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewBoolFlag(cli.BoolFlag{Name: "test", EnvVar: "TEST"}),
+ FlagName: "test",
+ MapValue: false,
+ EnvVarName: "TEST",
+ EnvVarValue: "true",
+ })
+ expect(t, true, c.Bool("test"))
+}
+
+func TestBoolTApplyInputSourceMethodSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewBoolTFlag(cli.BoolTFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: false,
+ })
+ expect(t, false, c.BoolT("test"))
+}
+
+func TestBoolTApplyInputSourceMethodContextSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewBoolTFlag(cli.BoolTFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: true,
+ ContextValueString: "false",
+ })
+ expect(t, false, c.BoolT("test"))
+}
+
+func TestBoolTApplyInputSourceMethodEnvVarSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewBoolTFlag(cli.BoolTFlag{Name: "test", EnvVar: "TEST"}),
+ FlagName: "test",
+ MapValue: true,
+ EnvVarName: "TEST",
+ EnvVarValue: "false",
+ })
+ expect(t, false, c.BoolT("test"))
+}
+
+func TestStringApplyInputSourceMethodSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewStringFlag(cli.StringFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: "hello",
+ })
+ expect(t, "hello", c.String("test"))
+}
+
+func TestStringApplyInputSourceMethodContextSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewStringFlag(cli.StringFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: "hello",
+ ContextValueString: "goodbye",
+ })
+ expect(t, "goodbye", c.String("test"))
+}
+
+func TestStringApplyInputSourceMethodEnvVarSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewStringFlag(cli.StringFlag{Name: "test", EnvVar: "TEST"}),
+ FlagName: "test",
+ MapValue: "hello",
+ EnvVarName: "TEST",
+ EnvVarValue: "goodbye",
+ })
+ expect(t, "goodbye", c.String("test"))
+}
+
+func TestIntApplyInputSourceMethodSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewIntFlag(cli.IntFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: 15,
+ })
+ expect(t, 15, c.Int("test"))
+}
+
+func TestIntApplyInputSourceMethodContextSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewIntFlag(cli.IntFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: 15,
+ ContextValueString: "7",
+ })
+ expect(t, 7, c.Int("test"))
+}
+
+func TestIntApplyInputSourceMethodEnvVarSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "TEST"}),
+ FlagName: "test",
+ MapValue: 15,
+ EnvVarName: "TEST",
+ EnvVarValue: "12",
+ })
+ expect(t, 12, c.Int("test"))
+}
+
+func TestDurationApplyInputSourceMethodSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewDurationFlag(cli.DurationFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: time.Duration(30 * time.Second),
+ })
+ expect(t, time.Duration(30*time.Second), c.Duration("test"))
+}
+
+func TestDurationApplyInputSourceMethodContextSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewDurationFlag(cli.DurationFlag{Name: "test"}),
+ FlagName: "test",
+ MapValue: time.Duration(30 * time.Second),
+ ContextValueString: time.Duration(15 * time.Second).String(),
+ })
+ expect(t, time.Duration(15*time.Second), c.Duration("test"))
+}
+
+func TestDurationApplyInputSourceMethodEnvVarSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewDurationFlag(cli.DurationFlag{Name: "test", EnvVar: "TEST"}),
+ FlagName: "test",
+ MapValue: time.Duration(30 * time.Second),
+ EnvVarName: "TEST",
+ EnvVarValue: time.Duration(15 * time.Second).String(),
+ })
+ expect(t, time.Duration(15*time.Second), c.Duration("test"))
+}
+
+func TestFloat64ApplyInputSourceMethodSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewFloat64Flag(cli.Float64Flag{Name: "test"}),
+ FlagName: "test",
+ MapValue: 1.3,
+ })
+ expect(t, 1.3, c.Float64("test"))
+}
+
+func TestFloat64ApplyInputSourceMethodContextSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewFloat64Flag(cli.Float64Flag{Name: "test"}),
+ FlagName: "test",
+ MapValue: 1.3,
+ ContextValueString: fmt.Sprintf("%v", 1.4),
+ })
+ expect(t, 1.4, c.Float64("test"))
+}
+
+func TestFloat64ApplyInputSourceMethodEnvVarSet(t *testing.T) {
+ c := runTest(t, testApplyInputSource{
+ Flag: NewFloat64Flag(cli.Float64Flag{Name: "test", EnvVar: "TEST"}),
+ FlagName: "test",
+ MapValue: 1.3,
+ EnvVarName: "TEST",
+ EnvVarValue: fmt.Sprintf("%v", 1.4),
+ })
+ expect(t, 1.4, c.Float64("test"))
+}
+
+func runTest(t *testing.T, test testApplyInputSource) *cli.Context {
+ inputSource := &MapInputSource{valueMap: map[interface{}]interface{}{test.FlagName: test.MapValue}}
+ set := flag.NewFlagSet(test.FlagSetName, flag.ContinueOnError)
+ c := cli.NewContext(nil, set, nil)
+ if test.EnvVarName != "" && test.EnvVarValue != "" {
+ os.Setenv(test.EnvVarName, test.EnvVarValue)
+ defer os.Setenv(test.EnvVarName, "")
+ }
+
+ test.Flag.Apply(set)
+ if test.ContextValue != nil {
+ flag := set.Lookup(test.FlagName)
+ flag.Value = test.ContextValue
+ }
+ if test.ContextValueString != "" {
+ set.Set(test.FlagName, test.ContextValueString)
+ }
+ test.Flag.ApplyInputSourceValue(c, inputSource)
+
+ return c
+}
+
+type Parser [2]string
+
+func (p *Parser) Set(value string) error {
+ parts := strings.Split(value, ",")
+ if len(parts) != 2 {
+ return fmt.Errorf("invalid format")
+ }
+
+ (*p)[0] = parts[0]
+ (*p)[1] = parts[1]
+
+ return nil
+}
+
+func (p *Parser) String() string {
+ return fmt.Sprintf("%s,%s", p[0], p[1])
+}
diff --git a/vendor/github.com/codegangsta/cli/altsrc/helpers_test.go b/vendor/github.com/codegangsta/cli/altsrc/helpers_test.go
new file mode 100644
index 0000000..3b7f7e9
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/altsrc/helpers_test.go
@@ -0,0 +1,18 @@
+package altsrc
+
+import (
+ "reflect"
+ "testing"
+)
+
+func expect(t *testing.T, a interface{}, b interface{}) {
+ if !reflect.DeepEqual(b, a) {
+ t.Errorf("Expected %#v (type %v) - Got %#v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
+ }
+}
+
+func refute(t *testing.T, a interface{}, b interface{}) {
+ if a == b {
+ t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
+ }
+}
diff --git a/vendor/github.com/codegangsta/cli/altsrc/input_source_context.go b/vendor/github.com/codegangsta/cli/altsrc/input_source_context.go
new file mode 100644
index 0000000..8ea7e92
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/altsrc/input_source_context.go
@@ -0,0 +1,21 @@
+package altsrc
+
+import (
+ "time"
+
+ "github.com/urfave/cli"
+)
+
+// InputSourceContext is an interface used to allow
+// other input sources to be implemented as needed.
+type InputSourceContext interface {
+ Int(name string) (int, error)
+ Duration(name string) (time.Duration, error)
+ Float64(name string) (float64, error)
+ String(name string) (string, error)
+ StringSlice(name string) ([]string, error)
+ IntSlice(name string) ([]int, error)
+ Generic(name string) (cli.Generic, error)
+ Bool(name string) (bool, error)
+ BoolT(name string) (bool, error)
+}
diff --git a/vendor/github.com/codegangsta/cli/altsrc/map_input_source.go b/vendor/github.com/codegangsta/cli/altsrc/map_input_source.go
new file mode 100644
index 0000000..b1c8e4f
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/altsrc/map_input_source.go
@@ -0,0 +1,248 @@
+package altsrc
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+ "time"
+
+ "github.com/urfave/cli"
+)
+
+// MapInputSource implements InputSourceContext to return
+// data from the map that is loaded.
+type MapInputSource struct {
+ valueMap map[interface{}]interface{}
+}
+
+// nestedVal checks if the name has '.' delimiters.
+// If so, it tries to traverse the tree by the '.' delimited sections to find
+// a nested value for the key.
+func nestedVal(name string, tree map[interface{}]interface{}) (interface{}, bool) {
+ if sections := strings.Split(name, "."); len(sections) > 1 {
+ node := tree
+ for _, section := range sections[:len(sections)-1] {
+ if child, ok := node[section]; !ok {
+ return nil, false
+ } else {
+ if ctype, ok := child.(map[interface{}]interface{}); !ok {
+ return nil, false
+ } else {
+ node = ctype
+ }
+ }
+ }
+ if val, ok := node[sections[len(sections)-1]]; ok {
+ return val, true
+ }
+ }
+ return nil, false
+}
+
+// Int returns an int from the map if it exists otherwise returns 0
+func (fsm *MapInputSource) Int(name string) (int, error) {
+ otherGenericValue, exists := fsm.valueMap[name]
+ if exists {
+ otherValue, isType := otherGenericValue.(int)
+ if !isType {
+ return 0, incorrectTypeForFlagError(name, "int", otherGenericValue)
+ }
+ return otherValue, nil
+ }
+ nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
+ if exists {
+ otherValue, isType := nestedGenericValue.(int)
+ if !isType {
+ return 0, incorrectTypeForFlagError(name, "int", nestedGenericValue)
+ }
+ return otherValue, nil
+ }
+
+ return 0, nil
+}
+
+// Duration returns a duration from the map if it exists otherwise returns 0
+func (fsm *MapInputSource) Duration(name string) (time.Duration, error) {
+ otherGenericValue, exists := fsm.valueMap[name]
+ if exists {
+ otherValue, isType := otherGenericValue.(time.Duration)
+ if !isType {
+ return 0, incorrectTypeForFlagError(name, "duration", otherGenericValue)
+ }
+ return otherValue, nil
+ }
+ nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
+ if exists {
+ otherValue, isType := nestedGenericValue.(time.Duration)
+ if !isType {
+ return 0, incorrectTypeForFlagError(name, "duration", nestedGenericValue)
+ }
+ return otherValue, nil
+ }
+
+ return 0, nil
+}
+
+// Float64 returns an float64 from the map if it exists otherwise returns 0
+func (fsm *MapInputSource) Float64(name string) (float64, error) {
+ otherGenericValue, exists := fsm.valueMap[name]
+ if exists {
+ otherValue, isType := otherGenericValue.(float64)
+ if !isType {
+ return 0, incorrectTypeForFlagError(name, "float64", otherGenericValue)
+ }
+ return otherValue, nil
+ }
+ nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
+ if exists {
+ otherValue, isType := nestedGenericValue.(float64)
+ if !isType {
+ return 0, incorrectTypeForFlagError(name, "float64", nestedGenericValue)
+ }
+ return otherValue, nil
+ }
+
+ return 0, nil
+}
+
+// String returns a string from the map if it exists otherwise returns an empty string
+func (fsm *MapInputSource) String(name string) (string, error) {
+ otherGenericValue, exists := fsm.valueMap[name]
+ if exists {
+ otherValue, isType := otherGenericValue.(string)
+ if !isType {
+ return "", incorrectTypeForFlagError(name, "string", otherGenericValue)
+ }
+ return otherValue, nil
+ }
+ nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
+ if exists {
+ otherValue, isType := nestedGenericValue.(string)
+ if !isType {
+ return "", incorrectTypeForFlagError(name, "string", nestedGenericValue)
+ }
+ return otherValue, nil
+ }
+
+ return "", nil
+}
+
+// StringSlice returns an []string from the map if it exists otherwise returns nil
+func (fsm *MapInputSource) StringSlice(name string) ([]string, error) {
+ otherGenericValue, exists := fsm.valueMap[name]
+ if exists {
+ otherValue, isType := otherGenericValue.([]string)
+ if !isType {
+ return nil, incorrectTypeForFlagError(name, "[]string", otherGenericValue)
+ }
+ return otherValue, nil
+ }
+ nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
+ if exists {
+ otherValue, isType := nestedGenericValue.([]string)
+ if !isType {
+ return nil, incorrectTypeForFlagError(name, "[]string", nestedGenericValue)
+ }
+ return otherValue, nil
+ }
+
+ return nil, nil
+}
+
+// IntSlice returns an []int from the map if it exists otherwise returns nil
+func (fsm *MapInputSource) IntSlice(name string) ([]int, error) {
+ otherGenericValue, exists := fsm.valueMap[name]
+ if exists {
+ otherValue, isType := otherGenericValue.([]int)
+ if !isType {
+ return nil, incorrectTypeForFlagError(name, "[]int", otherGenericValue)
+ }
+ return otherValue, nil
+ }
+ nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
+ if exists {
+ otherValue, isType := nestedGenericValue.([]int)
+ if !isType {
+ return nil, incorrectTypeForFlagError(name, "[]int", nestedGenericValue)
+ }
+ return otherValue, nil
+ }
+
+ return nil, nil
+}
+
+// Generic returns an cli.Generic from the map if it exists otherwise returns nil
+func (fsm *MapInputSource) Generic(name string) (cli.Generic, error) {
+ otherGenericValue, exists := fsm.valueMap[name]
+ if exists {
+ otherValue, isType := otherGenericValue.(cli.Generic)
+ if !isType {
+ return nil, incorrectTypeForFlagError(name, "cli.Generic", otherGenericValue)
+ }
+ return otherValue, nil
+ }
+ nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
+ if exists {
+ otherValue, isType := nestedGenericValue.(cli.Generic)
+ if !isType {
+ return nil, incorrectTypeForFlagError(name, "cli.Generic", nestedGenericValue)
+ }
+ return otherValue, nil
+ }
+
+ return nil, nil
+}
+
+// Bool returns an bool from the map otherwise returns false
+func (fsm *MapInputSource) Bool(name string) (bool, error) {
+ otherGenericValue, exists := fsm.valueMap[name]
+ if exists {
+ otherValue, isType := otherGenericValue.(bool)
+ if !isType {
+ return false, incorrectTypeForFlagError(name, "bool", otherGenericValue)
+ }
+ return otherValue, nil
+ }
+ nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
+ if exists {
+ otherValue, isType := nestedGenericValue.(bool)
+ if !isType {
+ return false, incorrectTypeForFlagError(name, "bool", nestedGenericValue)
+ }
+ return otherValue, nil
+ }
+
+ return false, nil
+}
+
+// BoolT returns an bool from the map otherwise returns true
+func (fsm *MapInputSource) BoolT(name string) (bool, error) {
+ otherGenericValue, exists := fsm.valueMap[name]
+ if exists {
+ otherValue, isType := otherGenericValue.(bool)
+ if !isType {
+ return true, incorrectTypeForFlagError(name, "bool", otherGenericValue)
+ }
+ return otherValue, nil
+ }
+ nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
+ if exists {
+ otherValue, isType := nestedGenericValue.(bool)
+ if !isType {
+ return true, incorrectTypeForFlagError(name, "bool", nestedGenericValue)
+ }
+ return otherValue, nil
+ }
+
+ return true, nil
+}
+
+func incorrectTypeForFlagError(name, expectedTypeName string, value interface{}) error {
+ valueType := reflect.TypeOf(value)
+ valueTypeName := ""
+ if valueType != nil {
+ valueTypeName = valueType.Name()
+ }
+
+ return fmt.Errorf("Mismatched type for flag '%s'. Expected '%s' but actual is '%s'", name, expectedTypeName, valueTypeName)
+}
diff --git a/vendor/github.com/codegangsta/cli/altsrc/yaml_command_test.go b/vendor/github.com/codegangsta/cli/altsrc/yaml_command_test.go
new file mode 100644
index 0000000..31f78ce
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/altsrc/yaml_command_test.go
@@ -0,0 +1,313 @@
+// Disabling building of yaml support in cases where golang is 1.0 or 1.1
+// as the encoding library is not implemented or supported.
+
+// +build go1.2
+
+package altsrc
+
+import (
+ "flag"
+ "io/ioutil"
+ "os"
+ "testing"
+
+ "github.com/urfave/cli"
+)
+
+func TestCommandYamlFileTest(t *testing.T) {
+ app := cli.NewApp()
+ set := flag.NewFlagSet("test", 0)
+ ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
+ defer os.Remove("current.yaml")
+ test := []string{"test-cmd", "--load", "current.yaml"}
+ set.Parse(test)
+
+ c := cli.NewContext(app, set, nil)
+
+ command := &cli.Command{
+ Name: "test-cmd",
+ Aliases: []string{"tc"},
+ Usage: "this is for testing",
+ Description: "testing",
+ Action: func(c *cli.Context) error {
+ val := c.Int("test")
+ expect(t, val, 15)
+ return nil
+ },
+ Flags: []cli.Flag{
+ NewIntFlag(cli.IntFlag{Name: "test"}),
+ cli.StringFlag{Name: "load"}},
+ }
+ command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
+ err := command.Run(c)
+
+ expect(t, err, nil)
+}
+
+func TestCommandYamlFileTestGlobalEnvVarWins(t *testing.T) {
+ app := cli.NewApp()
+ set := flag.NewFlagSet("test", 0)
+ ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
+ defer os.Remove("current.yaml")
+
+ os.Setenv("THE_TEST", "10")
+ defer os.Setenv("THE_TEST", "")
+ test := []string{"test-cmd", "--load", "current.yaml"}
+ set.Parse(test)
+
+ c := cli.NewContext(app, set, nil)
+
+ command := &cli.Command{
+ Name: "test-cmd",
+ Aliases: []string{"tc"},
+ Usage: "this is for testing",
+ Description: "testing",
+ Action: func(c *cli.Context) error {
+ val := c.Int("test")
+ expect(t, val, 10)
+ return nil
+ },
+ Flags: []cli.Flag{
+ NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "THE_TEST"}),
+ cli.StringFlag{Name: "load"}},
+ }
+ command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
+
+ err := command.Run(c)
+
+ expect(t, err, nil)
+}
+
+func TestCommandYamlFileTestGlobalEnvVarWinsNested(t *testing.T) {
+ app := cli.NewApp()
+ set := flag.NewFlagSet("test", 0)
+ ioutil.WriteFile("current.yaml", []byte(`top:
+ test: 15`), 0666)
+ defer os.Remove("current.yaml")
+
+ os.Setenv("THE_TEST", "10")
+ defer os.Setenv("THE_TEST", "")
+ test := []string{"test-cmd", "--load", "current.yaml"}
+ set.Parse(test)
+
+ c := cli.NewContext(app, set, nil)
+
+ command := &cli.Command{
+ Name: "test-cmd",
+ Aliases: []string{"tc"},
+ Usage: "this is for testing",
+ Description: "testing",
+ Action: func(c *cli.Context) error {
+ val := c.Int("top.test")
+ expect(t, val, 10)
+ return nil
+ },
+ Flags: []cli.Flag{
+ NewIntFlag(cli.IntFlag{Name: "top.test", EnvVar: "THE_TEST"}),
+ cli.StringFlag{Name: "load"}},
+ }
+ command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
+
+ err := command.Run(c)
+
+ expect(t, err, nil)
+}
+
+func TestCommandYamlFileTestSpecifiedFlagWins(t *testing.T) {
+ app := cli.NewApp()
+ set := flag.NewFlagSet("test", 0)
+ ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
+ defer os.Remove("current.yaml")
+
+ test := []string{"test-cmd", "--load", "current.yaml", "--test", "7"}
+ set.Parse(test)
+
+ c := cli.NewContext(app, set, nil)
+
+ command := &cli.Command{
+ Name: "test-cmd",
+ Aliases: []string{"tc"},
+ Usage: "this is for testing",
+ Description: "testing",
+ Action: func(c *cli.Context) error {
+ val := c.Int("test")
+ expect(t, val, 7)
+ return nil
+ },
+ Flags: []cli.Flag{
+ NewIntFlag(cli.IntFlag{Name: "test"}),
+ cli.StringFlag{Name: "load"}},
+ }
+ command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
+
+ err := command.Run(c)
+
+ expect(t, err, nil)
+}
+
+func TestCommandYamlFileTestSpecifiedFlagWinsNested(t *testing.T) {
+ app := cli.NewApp()
+ set := flag.NewFlagSet("test", 0)
+ ioutil.WriteFile("current.yaml", []byte(`top:
+ test: 15`), 0666)
+ defer os.Remove("current.yaml")
+
+ test := []string{"test-cmd", "--load", "current.yaml", "--top.test", "7"}
+ set.Parse(test)
+
+ c := cli.NewContext(app, set, nil)
+
+ command := &cli.Command{
+ Name: "test-cmd",
+ Aliases: []string{"tc"},
+ Usage: "this is for testing",
+ Description: "testing",
+ Action: func(c *cli.Context) error {
+ val := c.Int("top.test")
+ expect(t, val, 7)
+ return nil
+ },
+ Flags: []cli.Flag{
+ NewIntFlag(cli.IntFlag{Name: "top.test"}),
+ cli.StringFlag{Name: "load"}},
+ }
+ command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
+
+ err := command.Run(c)
+
+ expect(t, err, nil)
+}
+
+func TestCommandYamlFileTestDefaultValueFileWins(t *testing.T) {
+ app := cli.NewApp()
+ set := flag.NewFlagSet("test", 0)
+ ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
+ defer os.Remove("current.yaml")
+
+ test := []string{"test-cmd", "--load", "current.yaml"}
+ set.Parse(test)
+
+ c := cli.NewContext(app, set, nil)
+
+ command := &cli.Command{
+ Name: "test-cmd",
+ Aliases: []string{"tc"},
+ Usage: "this is for testing",
+ Description: "testing",
+ Action: func(c *cli.Context) error {
+ val := c.Int("test")
+ expect(t, val, 15)
+ return nil
+ },
+ Flags: []cli.Flag{
+ NewIntFlag(cli.IntFlag{Name: "test", Value: 7}),
+ cli.StringFlag{Name: "load"}},
+ }
+ command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
+
+ err := command.Run(c)
+
+ expect(t, err, nil)
+}
+
+func TestCommandYamlFileTestDefaultValueFileWinsNested(t *testing.T) {
+ app := cli.NewApp()
+ set := flag.NewFlagSet("test", 0)
+ ioutil.WriteFile("current.yaml", []byte(`top:
+ test: 15`), 0666)
+ defer os.Remove("current.yaml")
+
+ test := []string{"test-cmd", "--load", "current.yaml"}
+ set.Parse(test)
+
+ c := cli.NewContext(app, set, nil)
+
+ command := &cli.Command{
+ Name: "test-cmd",
+ Aliases: []string{"tc"},
+ Usage: "this is for testing",
+ Description: "testing",
+ Action: func(c *cli.Context) error {
+ val := c.Int("top.test")
+ expect(t, val, 15)
+ return nil
+ },
+ Flags: []cli.Flag{
+ NewIntFlag(cli.IntFlag{Name: "top.test", Value: 7}),
+ cli.StringFlag{Name: "load"}},
+ }
+ command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
+
+ err := command.Run(c)
+
+ expect(t, err, nil)
+}
+
+func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWins(t *testing.T) {
+ app := cli.NewApp()
+ set := flag.NewFlagSet("test", 0)
+ ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
+ defer os.Remove("current.yaml")
+
+ os.Setenv("THE_TEST", "11")
+ defer os.Setenv("THE_TEST", "")
+
+ test := []string{"test-cmd", "--load", "current.yaml"}
+ set.Parse(test)
+
+ c := cli.NewContext(app, set, nil)
+
+ command := &cli.Command{
+ Name: "test-cmd",
+ Aliases: []string{"tc"},
+ Usage: "this is for testing",
+ Description: "testing",
+ Action: func(c *cli.Context) error {
+ val := c.Int("test")
+ expect(t, val, 11)
+ return nil
+ },
+ Flags: []cli.Flag{
+ NewIntFlag(cli.IntFlag{Name: "test", Value: 7, EnvVar: "THE_TEST"}),
+ cli.StringFlag{Name: "load"}},
+ }
+ command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
+ err := command.Run(c)
+
+ expect(t, err, nil)
+}
+
+func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWinsNested(t *testing.T) {
+ app := cli.NewApp()
+ set := flag.NewFlagSet("test", 0)
+ ioutil.WriteFile("current.yaml", []byte(`top:
+ test: 15`), 0666)
+ defer os.Remove("current.yaml")
+
+ os.Setenv("THE_TEST", "11")
+ defer os.Setenv("THE_TEST", "")
+
+ test := []string{"test-cmd", "--load", "current.yaml"}
+ set.Parse(test)
+
+ c := cli.NewContext(app, set, nil)
+
+ command := &cli.Command{
+ Name: "test-cmd",
+ Aliases: []string{"tc"},
+ Usage: "this is for testing",
+ Description: "testing",
+ Action: func(c *cli.Context) error {
+ val := c.Int("top.test")
+ expect(t, val, 11)
+ return nil
+ },
+ Flags: []cli.Flag{
+ NewIntFlag(cli.IntFlag{Name: "top.test", Value: 7, EnvVar: "THE_TEST"}),
+ cli.StringFlag{Name: "load"}},
+ }
+ command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
+ err := command.Run(c)
+
+ expect(t, err, nil)
+}
diff --git a/vendor/github.com/codegangsta/cli/altsrc/yaml_file_loader.go b/vendor/github.com/codegangsta/cli/altsrc/yaml_file_loader.go
new file mode 100644
index 0000000..b4e3365
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/altsrc/yaml_file_loader.go
@@ -0,0 +1,84 @@
+// Disabling building of yaml support in cases where golang is 1.0 or 1.1
+// as the encoding library is not implemented or supported.
+
+// +build go1.2
+
+package altsrc
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "os"
+
+ "github.com/urfave/cli"
+
+ "gopkg.in/yaml.v2"
+)
+
+type yamlSourceContext struct {
+ FilePath string
+}
+
+// NewYamlSourceFromFile creates a new Yaml InputSourceContext from a filepath.
+func NewYamlSourceFromFile(file string) (InputSourceContext, error) {
+ ysc := &yamlSourceContext{FilePath: file}
+ var results map[interface{}]interface{}
+ err := readCommandYaml(ysc.FilePath, &results)
+ if err != nil {
+ return nil, fmt.Errorf("Unable to load Yaml file '%s': inner error: \n'%v'", ysc.FilePath, err.Error())
+ }
+
+ return &MapInputSource{valueMap: results}, nil
+}
+
+// NewYamlSourceFromFlagFunc creates a new Yaml InputSourceContext from a provided flag name and source context.
+func NewYamlSourceFromFlagFunc(flagFileName string) func(context *cli.Context) (InputSourceContext, error) {
+ return func(context *cli.Context) (InputSourceContext, error) {
+ filePath := context.String(flagFileName)
+ return NewYamlSourceFromFile(filePath)
+ }
+}
+
+func readCommandYaml(filePath string, container interface{}) (err error) {
+ b, err := loadDataFrom(filePath)
+ if err != nil {
+ return err
+ }
+
+ err = yaml.Unmarshal(b, container)
+ if err != nil {
+ return err
+ }
+
+ err = nil
+ return
+}
+
+func loadDataFrom(filePath string) ([]byte, error) {
+ u, err := url.Parse(filePath)
+ if err != nil {
+ return nil, err
+ }
+
+ if u.Host != "" { // i have a host, now do i support the scheme?
+ switch u.Scheme {
+ case "http", "https":
+ res, err := http.Get(filePath)
+ if err != nil {
+ return nil, err
+ }
+ return ioutil.ReadAll(res.Body)
+ default:
+ return nil, fmt.Errorf("scheme of %s is unsupported", filePath)
+ }
+ } else if u.Path != "" { // i dont have a host, but I have a path. I am a local file.
+ if _, notFoundFileErr := os.Stat(filePath); notFoundFileErr != nil {
+ return nil, fmt.Errorf("Cannot read from file: '%s' because it does not exist.", filePath)
+ }
+ return ioutil.ReadFile(filePath)
+ } else {
+ return nil, fmt.Errorf("unable to determine how to load from path %s", filePath)
+ }
+}
diff --git a/vendor/github.com/codegangsta/cli/app.go b/vendor/github.com/codegangsta/cli/app.go
new file mode 100644
index 0000000..a046c01
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/app.go
@@ -0,0 +1,499 @@
+package cli
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "reflect"
+ "sort"
+ "strings"
+ "time"
+)
+
+var (
+ changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md"
+ appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL)
+ runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL)
+
+ contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you."
+
+ errNonFuncAction = NewExitError("ERROR invalid Action type. "+
+ fmt.Sprintf("Must be a func of type `cli.ActionFunc`. %s", contactSysadmin)+
+ fmt.Sprintf("See %s", appActionDeprecationURL), 2)
+ errInvalidActionSignature = NewExitError("ERROR invalid Action signature. "+
+ fmt.Sprintf("Must be `cli.ActionFunc`. %s", contactSysadmin)+
+ fmt.Sprintf("See %s", appActionDeprecationURL), 2)
+)
+
+// App is the main structure of a cli application. It is recommended that
+// an app be created with the cli.NewApp() function
+type App struct {
+ // The name of the program. Defaults to path.Base(os.Args[0])
+ Name string
+ // Full name of command for help, defaults to Name
+ HelpName string
+ // Description of the program.
+ Usage string
+ // Text to override the USAGE section of help
+ UsageText string
+ // Description of the program argument format.
+ ArgsUsage string
+ // Version of the program
+ Version string
+ // List of commands to execute
+ Commands []Command
+ // List of flags to parse
+ Flags []Flag
+ // Boolean to enable bash completion commands
+ EnableBashCompletion bool
+ // Boolean to hide built-in help command
+ HideHelp bool
+ // Boolean to hide built-in version flag and the VERSION section of help
+ HideVersion bool
+ // Populate on app startup, only gettable through method Categories()
+ categories CommandCategories
+ // An action to execute when the bash-completion flag is set
+ BashComplete BashCompleteFunc
+ // An action to execute before any subcommands are run, but after the context is ready
+ // If a non-nil error is returned, no subcommands are run
+ Before BeforeFunc
+ // An action to execute after any subcommands are run, but after the subcommand has finished
+ // It is run even if Action() panics
+ After AfterFunc
+ // The action to execute when no subcommands are specified
+ Action interface{}
+ // TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind
+ // of deprecation period has passed, maybe?
+
+ // Execute this function if the proper command cannot be found
+ CommandNotFound CommandNotFoundFunc
+ // Execute this function if an usage error occurs
+ OnUsageError OnUsageErrorFunc
+ // Compilation date
+ Compiled time.Time
+ // List of all authors who contributed
+ Authors []Author
+ // Copyright of the binary if any
+ Copyright string
+ // Name of Author (Note: Use App.Authors, this is deprecated)
+ Author string
+ // Email of Author (Note: Use App.Authors, this is deprecated)
+ Email string
+ // Writer writer to write output to
+ Writer io.Writer
+ // ErrWriter writes error output
+ ErrWriter io.Writer
+ // Other custom info
+ Metadata map[string]interface{}
+
+ didSetup bool
+}
+
+// Tries to find out when this binary was compiled.
+// Returns the current time if it fails to find it.
+func compileTime() time.Time {
+ info, err := os.Stat(os.Args[0])
+ if err != nil {
+ return time.Now()
+ }
+ return info.ModTime()
+}
+
+// NewApp creates a new cli Application with some reasonable defaults for Name,
+// Usage, Version and Action.
+func NewApp() *App {
+ return &App{
+ Name: filepath.Base(os.Args[0]),
+ HelpName: filepath.Base(os.Args[0]),
+ Usage: "A new cli application",
+ UsageText: "",
+ Version: "0.0.0",
+ BashComplete: DefaultAppComplete,
+ Action: helpCommand.Action,
+ Compiled: compileTime(),
+ Writer: os.Stdout,
+ }
+}
+
+// Setup runs initialization code to ensure all data structures are ready for
+// `Run` or inspection prior to `Run`. It is internally called by `Run`, but
+// will return early if setup has already happened.
+func (a *App) Setup() {
+ if a.didSetup {
+ return
+ }
+
+ a.didSetup = true
+
+ if a.Author != "" || a.Email != "" {
+ a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
+ }
+
+ newCmds := []Command{}
+ for _, c := range a.Commands {
+ if c.HelpName == "" {
+ c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
+ }
+ newCmds = append(newCmds, c)
+ }
+ a.Commands = newCmds
+
+ if a.Command(helpCommand.Name) == nil && !a.HideHelp {
+ a.Commands = append(a.Commands, helpCommand)
+ if (HelpFlag != BoolFlag{}) {
+ a.appendFlag(HelpFlag)
+ }
+ }
+
+ if a.EnableBashCompletion {
+ a.appendFlag(BashCompletionFlag)
+ }
+
+ if !a.HideVersion {
+ a.appendFlag(VersionFlag)
+ }
+
+ a.categories = CommandCategories{}
+ for _, command := range a.Commands {
+ a.categories = a.categories.AddCommand(command.Category, command)
+ }
+ sort.Sort(a.categories)
+}
+
+// Run is the entry point to the cli app. Parses the arguments slice and routes
+// to the proper flag/args combination
+func (a *App) Run(arguments []string) (err error) {
+ a.Setup()
+
+ // parse flags
+ set := flagSet(a.Name, a.Flags)
+ set.SetOutput(ioutil.Discard)
+ err = set.Parse(arguments[1:])
+ nerr := normalizeFlags(a.Flags, set)
+ context := NewContext(a, set, nil)
+ if nerr != nil {
+ fmt.Fprintln(a.Writer, nerr)
+ ShowAppHelp(context)
+ return nerr
+ }
+
+ if checkCompletions(context) {
+ return nil
+ }
+
+ if err != nil {
+ if a.OnUsageError != nil {
+ err := a.OnUsageError(context, err, false)
+ HandleExitCoder(err)
+ return err
+ }
+ fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
+ ShowAppHelp(context)
+ return err
+ }
+
+ if !a.HideHelp && checkHelp(context) {
+ ShowAppHelp(context)
+ return nil
+ }
+
+ if !a.HideVersion && checkVersion(context) {
+ ShowVersion(context)
+ return nil
+ }
+
+ if a.After != nil {
+ defer func() {
+ if afterErr := a.After(context); afterErr != nil {
+ if err != nil {
+ err = NewMultiError(err, afterErr)
+ } else {
+ err = afterErr
+ }
+ }
+ }()
+ }
+
+ if a.Before != nil {
+ beforeErr := a.Before(context)
+ if beforeErr != nil {
+ fmt.Fprintf(a.Writer, "%v\n\n", beforeErr)
+ ShowAppHelp(context)
+ HandleExitCoder(beforeErr)
+ err = beforeErr
+ return err
+ }
+ }
+
+ args := context.Args()
+ if args.Present() {
+ name := args.First()
+ c := a.Command(name)
+ if c != nil {
+ return c.Run(context)
+ }
+ }
+
+ // Run default Action
+ err = HandleAction(a.Action, context)
+
+ HandleExitCoder(err)
+ return err
+}
+
+// DEPRECATED: Another entry point to the cli app, takes care of passing arguments and error handling
+func (a *App) RunAndExitOnError() {
+ fmt.Fprintf(a.errWriter(),
+ "DEPRECATED cli.App.RunAndExitOnError. %s See %s\n",
+ contactSysadmin, runAndExitOnErrorDeprecationURL)
+ if err := a.Run(os.Args); err != nil {
+ fmt.Fprintln(a.errWriter(), err)
+ OsExiter(1)
+ }
+}
+
+// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
+// generate command-specific flags
+func (a *App) RunAsSubcommand(ctx *Context) (err error) {
+ // append help to commands
+ if len(a.Commands) > 0 {
+ if a.Command(helpCommand.Name) == nil && !a.HideHelp {
+ a.Commands = append(a.Commands, helpCommand)
+ if (HelpFlag != BoolFlag{}) {
+ a.appendFlag(HelpFlag)
+ }
+ }
+ }
+
+ newCmds := []Command{}
+ for _, c := range a.Commands {
+ if c.HelpName == "" {
+ c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
+ }
+ newCmds = append(newCmds, c)
+ }
+ a.Commands = newCmds
+
+ // append flags
+ if a.EnableBashCompletion {
+ a.appendFlag(BashCompletionFlag)
+ }
+
+ // parse flags
+ set := flagSet(a.Name, a.Flags)
+ set.SetOutput(ioutil.Discard)
+ err = set.Parse(ctx.Args().Tail())
+ nerr := normalizeFlags(a.Flags, set)
+ context := NewContext(a, set, ctx)
+
+ if nerr != nil {
+ fmt.Fprintln(a.Writer, nerr)
+ fmt.Fprintln(a.Writer)
+ if len(a.Commands) > 0 {
+ ShowSubcommandHelp(context)
+ } else {
+ ShowCommandHelp(ctx, context.Args().First())
+ }
+ return nerr
+ }
+
+ if checkCompletions(context) {
+ return nil
+ }
+
+ if err != nil {
+ if a.OnUsageError != nil {
+ err = a.OnUsageError(context, err, true)
+ HandleExitCoder(err)
+ return err
+ }
+ fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
+ ShowSubcommandHelp(context)
+ return err
+ }
+
+ if len(a.Commands) > 0 {
+ if checkSubcommandHelp(context) {
+ return nil
+ }
+ } else {
+ if checkCommandHelp(ctx, context.Args().First()) {
+ return nil
+ }
+ }
+
+ if a.After != nil {
+ defer func() {
+ afterErr := a.After(context)
+ if afterErr != nil {
+ HandleExitCoder(err)
+ if err != nil {
+ err = NewMultiError(err, afterErr)
+ } else {
+ err = afterErr
+ }
+ }
+ }()
+ }
+
+ if a.Before != nil {
+ beforeErr := a.Before(context)
+ if beforeErr != nil {
+ HandleExitCoder(beforeErr)
+ err = beforeErr
+ return err
+ }
+ }
+
+ args := context.Args()
+ if args.Present() {
+ name := args.First()
+ c := a.Command(name)
+ if c != nil {
+ return c.Run(context)
+ }
+ }
+
+ // Run default Action
+ err = HandleAction(a.Action, context)
+
+ HandleExitCoder(err)
+ return err
+}
+
+// Command returns the named command on App. Returns nil if the command does not exist
+func (a *App) Command(name string) *Command {
+ for _, c := range a.Commands {
+ if c.HasName(name) {
+ return &c
+ }
+ }
+
+ return nil
+}
+
+// Categories returns a slice containing all the categories with the commands they contain
+func (a *App) Categories() CommandCategories {
+ return a.categories
+}
+
+// VisibleCategories returns a slice of categories and commands that are
+// Hidden=false
+func (a *App) VisibleCategories() []*CommandCategory {
+ ret := []*CommandCategory{}
+ for _, category := range a.categories {
+ if visible := func() *CommandCategory {
+ for _, command := range category.Commands {
+ if !command.Hidden {
+ return category
+ }
+ }
+ return nil
+ }(); visible != nil {
+ ret = append(ret, visible)
+ }
+ }
+ return ret
+}
+
+// VisibleCommands returns a slice of the Commands with Hidden=false
+func (a *App) VisibleCommands() []Command {
+ ret := []Command{}
+ for _, command := range a.Commands {
+ if !command.Hidden {
+ ret = append(ret, command)
+ }
+ }
+ return ret
+}
+
+// VisibleFlags returns a slice of the Flags with Hidden=false
+func (a *App) VisibleFlags() []Flag {
+ return visibleFlags(a.Flags)
+}
+
+func (a *App) hasFlag(flag Flag) bool {
+ for _, f := range a.Flags {
+ if flag == f {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (a *App) errWriter() io.Writer {
+
+ // When the app ErrWriter is nil use the package level one.
+ if a.ErrWriter == nil {
+ return ErrWriter
+ }
+
+ return a.ErrWriter
+}
+
+func (a *App) appendFlag(flag Flag) {
+ if !a.hasFlag(flag) {
+ a.Flags = append(a.Flags, flag)
+ }
+}
+
+// Author represents someone who has contributed to a cli project.
+type Author struct {
+ Name string // The Authors name
+ Email string // The Authors email
+}
+
+// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
+func (a Author) String() string {
+ e := ""
+ if a.Email != "" {
+ e = "<" + a.Email + "> "
+ }
+
+ return fmt.Sprintf("%v %v", a.Name, e)
+}
+
+// HandleAction uses ✧✧✧reflection✧✧✧ to figure out if the given Action is an
+// ActionFunc, a func with the legacy signature for Action, or some other
+// invalid thing. If it's an ActionFunc or a func with the legacy signature for
+// Action, the func is run!
+func HandleAction(action interface{}, context *Context) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ // Try to detect a known reflection error from *this scope*, rather than
+ // swallowing all panics that may happen when calling an Action func.
+ s := fmt.Sprintf("%v", r)
+ if strings.HasPrefix(s, "reflect: ") && strings.Contains(s, "too many input arguments") {
+ err = NewExitError(fmt.Sprintf("ERROR unknown Action error: %v. See %s", r, appActionDeprecationURL), 2)
+ } else {
+ panic(r)
+ }
+ }
+ }()
+
+ if reflect.TypeOf(action).Kind() != reflect.Func {
+ return errNonFuncAction
+ }
+
+ vals := reflect.ValueOf(action).Call([]reflect.Value{reflect.ValueOf(context)})
+
+ if len(vals) == 0 {
+ fmt.Fprintf(ErrWriter,
+ "DEPRECATED Action signature. Must be `cli.ActionFunc`. %s See %s\n",
+ contactSysadmin, appActionDeprecationURL)
+ return nil
+ }
+
+ if len(vals) > 1 {
+ return errInvalidActionSignature
+ }
+
+ if retErr, ok := vals[0].Interface().(error); vals[0].IsValid() && ok {
+ return retErr
+ }
+
+ return err
+}
diff --git a/vendor/github.com/codegangsta/cli/app_test.go b/vendor/github.com/codegangsta/cli/app_test.go
new file mode 100644
index 0000000..9c6b960
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/app_test.go
@@ -0,0 +1,1471 @@
+package cli
+
+import (
+ "bytes"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type opCounts struct {
+ Total, BashComplete, OnUsageError, Before, CommandNotFound, Action, After, SubCommand int
+}
+
+func ExampleApp_Run() {
+ // set args for examples sake
+ os.Args = []string{"greet", "--name", "Jeremy"}
+
+ app := NewApp()
+ app.Name = "greet"
+ app.Flags = []Flag{
+ StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
+ }
+ app.Action = func(c *Context) error {
+ fmt.Printf("Hello %v\n", c.String("name"))
+ return nil
+ }
+ app.UsageText = "app [first_arg] [second_arg]"
+ app.Author = "Harrison"
+ app.Email = "harrison@lolwut.com"
+ app.Authors = []Author{{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
+ app.Run(os.Args)
+ // Output:
+ // Hello Jeremy
+}
+
+func ExampleApp_Run_subcommand() {
+ // set args for examples sake
+ os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
+ app := NewApp()
+ app.Name = "say"
+ app.Commands = []Command{
+ {
+ Name: "hello",
+ Aliases: []string{"hi"},
+ Usage: "use it to see a description",
+ Description: "This is how we describe hello the function",
+ Subcommands: []Command{
+ {
+ Name: "english",
+ Aliases: []string{"en"},
+ Usage: "sends a greeting in english",
+ Description: "greets someone in english",
+ Flags: []Flag{
+ StringFlag{
+ Name: "name",
+ Value: "Bob",
+ Usage: "Name of the person to greet",
+ },
+ },
+ Action: func(c *Context) error {
+ fmt.Println("Hello,", c.String("name"))
+ return nil
+ },
+ },
+ },
+ },
+ }
+
+ app.Run(os.Args)
+ // Output:
+ // Hello, Jeremy
+}
+
+func ExampleApp_Run_help() {
+ // set args for examples sake
+ os.Args = []string{"greet", "h", "describeit"}
+
+ app := NewApp()
+ app.Name = "greet"
+ app.Flags = []Flag{
+ StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
+ }
+ app.Commands = []Command{
+ {
+ Name: "describeit",
+ Aliases: []string{"d"},
+ Usage: "use it to see a description",
+ Description: "This is how we describe describeit the function",
+ Action: func(c *Context) error {
+ fmt.Printf("i like to describe things")
+ return nil
+ },
+ },
+ }
+ app.Run(os.Args)
+ // Output:
+ // NAME:
+ // greet describeit - use it to see a description
+ //
+ // USAGE:
+ // greet describeit [arguments...]
+ //
+ // DESCRIPTION:
+ // This is how we describe describeit the function
+}
+
+func ExampleApp_Run_bashComplete() {
+ // set args for examples sake
+ os.Args = []string{"greet", "--generate-bash-completion"}
+
+ app := NewApp()
+ app.Name = "greet"
+ app.EnableBashCompletion = true
+ app.Commands = []Command{
+ {
+ Name: "describeit",
+ Aliases: []string{"d"},
+ Usage: "use it to see a description",
+ Description: "This is how we describe describeit the function",
+ Action: func(c *Context) error {
+ fmt.Printf("i like to describe things")
+ return nil
+ },
+ }, {
+ Name: "next",
+ Usage: "next example",
+ Description: "more stuff to see when generating bash completion",
+ Action: func(c *Context) error {
+ fmt.Printf("the next example")
+ return nil
+ },
+ },
+ }
+
+ app.Run(os.Args)
+ // Output:
+ // describeit
+ // d
+ // next
+ // help
+ // h
+}
+
+func TestApp_Run(t *testing.T) {
+ s := ""
+
+ app := NewApp()
+ app.Action = func(c *Context) error {
+ s = s + c.Args().First()
+ return nil
+ }
+
+ err := app.Run([]string{"command", "foo"})
+ expect(t, err, nil)
+ err = app.Run([]string{"command", "bar"})
+ expect(t, err, nil)
+ expect(t, s, "foobar")
+}
+
+var commandAppTests = []struct {
+ name string
+ expected bool
+}{
+ {"foobar", true},
+ {"batbaz", true},
+ {"b", true},
+ {"f", true},
+ {"bat", false},
+ {"nothing", false},
+}
+
+func TestApp_Command(t *testing.T) {
+ app := NewApp()
+ fooCommand := Command{Name: "foobar", Aliases: []string{"f"}}
+ batCommand := Command{Name: "batbaz", Aliases: []string{"b"}}
+ app.Commands = []Command{
+ fooCommand,
+ batCommand,
+ }
+
+ for _, test := range commandAppTests {
+ expect(t, app.Command(test.name) != nil, test.expected)
+ }
+}
+
+func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
+ var parsedOption, firstArg string
+
+ app := NewApp()
+ command := Command{
+ Name: "cmd",
+ Flags: []Flag{
+ StringFlag{Name: "option", Value: "", Usage: "some option"},
+ },
+ Action: func(c *Context) error {
+ parsedOption = c.String("option")
+ firstArg = c.Args().First()
+ return nil
+ },
+ }
+ app.Commands = []Command{command}
+
+ app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
+
+ expect(t, parsedOption, "my-option")
+ expect(t, firstArg, "my-arg")
+}
+
+func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
+ var context *Context
+
+ a := NewApp()
+ a.Commands = []Command{
+ {
+ Name: "foo",
+ Action: func(c *Context) error {
+ context = c
+ return nil
+ },
+ Flags: []Flag{
+ StringFlag{
+ Name: "lang",
+ Value: "english",
+ Usage: "language for the greeting",
+ },
+ },
+ Before: func(_ *Context) error { return nil },
+ },
+ }
+ a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
+
+ expect(t, context.Args().Get(0), "abcd")
+ expect(t, context.String("lang"), "spanish")
+}
+
+func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
+ var parsedOption string
+ var args []string
+
+ app := NewApp()
+ command := Command{
+ Name: "cmd",
+ Flags: []Flag{
+ StringFlag{Name: "option", Value: "", Usage: "some option"},
+ },
+ Action: func(c *Context) error {
+ parsedOption = c.String("option")
+ args = c.Args()
+ return nil
+ },
+ }
+ app.Commands = []Command{command}
+
+ app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
+
+ expect(t, parsedOption, "my-option")
+ expect(t, args[0], "my-arg")
+ expect(t, args[1], "--")
+ expect(t, args[2], "--notARealFlag")
+}
+
+func TestApp_CommandWithDash(t *testing.T) {
+ var args []string
+
+ app := NewApp()
+ command := Command{
+ Name: "cmd",
+ Action: func(c *Context) error {
+ args = c.Args()
+ return nil
+ },
+ }
+ app.Commands = []Command{command}
+
+ app.Run([]string{"", "cmd", "my-arg", "-"})
+
+ expect(t, args[0], "my-arg")
+ expect(t, args[1], "-")
+}
+
+func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
+ var args []string
+
+ app := NewApp()
+ command := Command{
+ Name: "cmd",
+ Action: func(c *Context) error {
+ args = c.Args()
+ return nil
+ },
+ }
+ app.Commands = []Command{command}
+
+ app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
+
+ expect(t, args[0], "my-arg")
+ expect(t, args[1], "--")
+ expect(t, args[2], "notAFlagAtAll")
+}
+
+func TestApp_VisibleCommands(t *testing.T) {
+ app := NewApp()
+ app.Commands = []Command{
+ {
+ Name: "frob",
+ HelpName: "foo frob",
+ Action: func(_ *Context) error { return nil },
+ },
+ {
+ Name: "frib",
+ HelpName: "foo frib",
+ Hidden: true,
+ Action: func(_ *Context) error { return nil },
+ },
+ }
+
+ app.Setup()
+ expected := []Command{
+ app.Commands[0],
+ app.Commands[2], // help
+ }
+ actual := app.VisibleCommands()
+ expect(t, len(expected), len(actual))
+ for i, actualCommand := range actual {
+ expectedCommand := expected[i]
+
+ if expectedCommand.Action != nil {
+ // comparing func addresses is OK!
+ expect(t, fmt.Sprintf("%p", expectedCommand.Action), fmt.Sprintf("%p", actualCommand.Action))
+ }
+
+ // nil out funcs, as they cannot be compared
+ // (https://github.com/golang/go/issues/8554)
+ expectedCommand.Action = nil
+ actualCommand.Action = nil
+
+ if !reflect.DeepEqual(expectedCommand, actualCommand) {
+ t.Errorf("expected\n%#v\n!=\n%#v", expectedCommand, actualCommand)
+ }
+ }
+}
+
+func TestApp_Float64Flag(t *testing.T) {
+ var meters float64
+
+ app := NewApp()
+ app.Flags = []Flag{
+ Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
+ }
+ app.Action = func(c *Context) error {
+ meters = c.Float64("height")
+ return nil
+ }
+
+ app.Run([]string{"", "--height", "1.93"})
+ expect(t, meters, 1.93)
+}
+
+func TestApp_ParseSliceFlags(t *testing.T) {
+ var parsedOption, firstArg string
+ var parsedIntSlice []int
+ var parsedStringSlice []string
+
+ app := NewApp()
+ command := Command{
+ Name: "cmd",
+ Flags: []Flag{
+ IntSliceFlag{Name: "p", Value: &IntSlice{}, Usage: "set one or more ip addr"},
+ StringSliceFlag{Name: "ip", Value: &StringSlice{}, Usage: "set one or more ports to open"},
+ },
+ Action: func(c *Context) error {
+ parsedIntSlice = c.IntSlice("p")
+ parsedStringSlice = c.StringSlice("ip")
+ parsedOption = c.String("option")
+ firstArg = c.Args().First()
+ return nil
+ },
+ }
+ app.Commands = []Command{command}
+
+ app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
+
+ IntsEquals := func(a, b []int) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, v := range a {
+ if v != b[i] {
+ return false
+ }
+ }
+ return true
+ }
+
+ StrsEquals := func(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, v := range a {
+ if v != b[i] {
+ return false
+ }
+ }
+ return true
+ }
+ var expectedIntSlice = []int{22, 80}
+ var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
+
+ if !IntsEquals(parsedIntSlice, expectedIntSlice) {
+ t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
+ }
+
+ if !StrsEquals(parsedStringSlice, expectedStringSlice) {
+ t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
+ }
+}
+
+func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
+ var parsedIntSlice []int
+ var parsedStringSlice []string
+
+ app := NewApp()
+ command := Command{
+ Name: "cmd",
+ Flags: []Flag{
+ IntSliceFlag{Name: "a", Usage: "set numbers"},
+ StringSliceFlag{Name: "str", Usage: "set strings"},
+ },
+ Action: func(c *Context) error {
+ parsedIntSlice = c.IntSlice("a")
+ parsedStringSlice = c.StringSlice("str")
+ return nil
+ },
+ }
+ app.Commands = []Command{command}
+
+ app.Run([]string{"", "cmd", "my-arg", "-a", "2", "-str", "A"})
+
+ var expectedIntSlice = []int{2}
+ var expectedStringSlice = []string{"A"}
+
+ if parsedIntSlice[0] != expectedIntSlice[0] {
+ t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
+ }
+
+ if parsedStringSlice[0] != expectedStringSlice[0] {
+ t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
+ }
+}
+
+func TestApp_DefaultStdout(t *testing.T) {
+ app := NewApp()
+
+ if app.Writer != os.Stdout {
+ t.Error("Default output writer not set.")
+ }
+}
+
+type mockWriter struct {
+ written []byte
+}
+
+func (fw *mockWriter) Write(p []byte) (n int, err error) {
+ if fw.written == nil {
+ fw.written = p
+ } else {
+ fw.written = append(fw.written, p...)
+ }
+
+ return len(p), nil
+}
+
+func (fw *mockWriter) GetWritten() (b []byte) {
+ return fw.written
+}
+
+func TestApp_SetStdout(t *testing.T) {
+ w := &mockWriter{}
+
+ app := NewApp()
+ app.Name = "test"
+ app.Writer = w
+
+ err := app.Run([]string{"help"})
+
+ if err != nil {
+ t.Fatalf("Run error: %s", err)
+ }
+
+ if len(w.written) == 0 {
+ t.Error("App did not write output to desired writer.")
+ }
+}
+
+func TestApp_BeforeFunc(t *testing.T) {
+ counts := &opCounts{}
+ beforeError := fmt.Errorf("fail")
+ var err error
+
+ app := NewApp()
+
+ app.Before = func(c *Context) error {
+ counts.Total++
+ counts.Before = counts.Total
+ s := c.String("opt")
+ if s == "fail" {
+ return beforeError
+ }
+
+ return nil
+ }
+
+ app.Commands = []Command{
+ {
+ Name: "sub",
+ Action: func(c *Context) error {
+ counts.Total++
+ counts.SubCommand = counts.Total
+ return nil
+ },
+ },
+ }
+
+ app.Flags = []Flag{
+ StringFlag{Name: "opt"},
+ }
+
+ // run with the Before() func succeeding
+ err = app.Run([]string{"command", "--opt", "succeed", "sub"})
+
+ if err != nil {
+ t.Fatalf("Run error: %s", err)
+ }
+
+ if counts.Before != 1 {
+ t.Errorf("Before() not executed when expected")
+ }
+
+ if counts.SubCommand != 2 {
+ t.Errorf("Subcommand not executed when expected")
+ }
+
+ // reset
+ counts = &opCounts{}
+
+ // run with the Before() func failing
+ err = app.Run([]string{"command", "--opt", "fail", "sub"})
+
+ // should be the same error produced by the Before func
+ if err != beforeError {
+ t.Errorf("Run error expected, but not received")
+ }
+
+ if counts.Before != 1 {
+ t.Errorf("Before() not executed when expected")
+ }
+
+ if counts.SubCommand != 0 {
+ t.Errorf("Subcommand executed when NOT expected")
+ }
+
+ // reset
+ counts = &opCounts{}
+
+ afterError := errors.New("fail again")
+ app.After = func(_ *Context) error {
+ return afterError
+ }
+
+ // run with the Before() func failing, wrapped by After()
+ err = app.Run([]string{"command", "--opt", "fail", "sub"})
+
+ // should be the same error produced by the Before func
+ if _, ok := err.(MultiError); !ok {
+ t.Errorf("MultiError expected, but not received")
+ }
+
+ if counts.Before != 1 {
+ t.Errorf("Before() not executed when expected")
+ }
+
+ if counts.SubCommand != 0 {
+ t.Errorf("Subcommand executed when NOT expected")
+ }
+}
+
+func TestApp_AfterFunc(t *testing.T) {
+ counts := &opCounts{}
+ afterError := fmt.Errorf("fail")
+ var err error
+
+ app := NewApp()
+
+ app.After = func(c *Context) error {
+ counts.Total++
+ counts.After = counts.Total
+ s := c.String("opt")
+ if s == "fail" {
+ return afterError
+ }
+
+ return nil
+ }
+
+ app.Commands = []Command{
+ {
+ Name: "sub",
+ Action: func(c *Context) error {
+ counts.Total++
+ counts.SubCommand = counts.Total
+ return nil
+ },
+ },
+ }
+
+ app.Flags = []Flag{
+ StringFlag{Name: "opt"},
+ }
+
+ // run with the After() func succeeding
+ err = app.Run([]string{"command", "--opt", "succeed", "sub"})
+
+ if err != nil {
+ t.Fatalf("Run error: %s", err)
+ }
+
+ if counts.After != 2 {
+ t.Errorf("After() not executed when expected")
+ }
+
+ if counts.SubCommand != 1 {
+ t.Errorf("Subcommand not executed when expected")
+ }
+
+ // reset
+ counts = &opCounts{}
+
+ // run with the Before() func failing
+ err = app.Run([]string{"command", "--opt", "fail", "sub"})
+
+ // should be the same error produced by the Before func
+ if err != afterError {
+ t.Errorf("Run error expected, but not received")
+ }
+
+ if counts.After != 2 {
+ t.Errorf("After() not executed when expected")
+ }
+
+ if counts.SubCommand != 1 {
+ t.Errorf("Subcommand not executed when expected")
+ }
+}
+
+func TestAppNoHelpFlag(t *testing.T) {
+ oldFlag := HelpFlag
+ defer func() {
+ HelpFlag = oldFlag
+ }()
+
+ HelpFlag = BoolFlag{}
+
+ app := NewApp()
+ app.Writer = ioutil.Discard
+ err := app.Run([]string{"test", "-h"})
+
+ if err != flag.ErrHelp {
+ t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
+ }
+}
+
+func TestAppHelpPrinter(t *testing.T) {
+ oldPrinter := HelpPrinter
+ defer func() {
+ HelpPrinter = oldPrinter
+ }()
+
+ var wasCalled = false
+ HelpPrinter = func(w io.Writer, template string, data interface{}) {
+ wasCalled = true
+ }
+
+ app := NewApp()
+ app.Run([]string{"-h"})
+
+ if wasCalled == false {
+ t.Errorf("Help printer expected to be called, but was not")
+ }
+}
+
+func TestApp_VersionPrinter(t *testing.T) {
+ oldPrinter := VersionPrinter
+ defer func() {
+ VersionPrinter = oldPrinter
+ }()
+
+ var wasCalled = false
+ VersionPrinter = func(c *Context) {
+ wasCalled = true
+ }
+
+ app := NewApp()
+ ctx := NewContext(app, nil, nil)
+ ShowVersion(ctx)
+
+ if wasCalled == false {
+ t.Errorf("Version printer expected to be called, but was not")
+ }
+}
+
+func TestApp_CommandNotFound(t *testing.T) {
+ counts := &opCounts{}
+ app := NewApp()
+
+ app.CommandNotFound = func(c *Context, command string) {
+ counts.Total++
+ counts.CommandNotFound = counts.Total
+ }
+
+ app.Commands = []Command{
+ {
+ Name: "bar",
+ Action: func(c *Context) error {
+ counts.Total++
+ counts.SubCommand = counts.Total
+ return nil
+ },
+ },
+ }
+
+ app.Run([]string{"command", "foo"})
+
+ expect(t, counts.CommandNotFound, 1)
+ expect(t, counts.SubCommand, 0)
+ expect(t, counts.Total, 1)
+}
+
+func TestApp_OrderOfOperations(t *testing.T) {
+ counts := &opCounts{}
+
+ resetCounts := func() { counts = &opCounts{} }
+
+ app := NewApp()
+ app.EnableBashCompletion = true
+ app.BashComplete = func(c *Context) {
+ counts.Total++
+ counts.BashComplete = counts.Total
+ }
+
+ app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
+ counts.Total++
+ counts.OnUsageError = counts.Total
+ return errors.New("hay OnUsageError")
+ }
+
+ beforeNoError := func(c *Context) error {
+ counts.Total++
+ counts.Before = counts.Total
+ return nil
+ }
+
+ beforeError := func(c *Context) error {
+ counts.Total++
+ counts.Before = counts.Total
+ return errors.New("hay Before")
+ }
+
+ app.Before = beforeNoError
+ app.CommandNotFound = func(c *Context, command string) {
+ counts.Total++
+ counts.CommandNotFound = counts.Total
+ }
+
+ afterNoError := func(c *Context) error {
+ counts.Total++
+ counts.After = counts.Total
+ return nil
+ }
+
+ afterError := func(c *Context) error {
+ counts.Total++
+ counts.After = counts.Total
+ return errors.New("hay After")
+ }
+
+ app.After = afterNoError
+ app.Commands = []Command{
+ {
+ Name: "bar",
+ Action: func(c *Context) error {
+ counts.Total++
+ counts.SubCommand = counts.Total
+ return nil
+ },
+ },
+ }
+
+ app.Action = func(c *Context) error {
+ counts.Total++
+ counts.Action = counts.Total
+ return nil
+ }
+
+ _ = app.Run([]string{"command", "--nope"})
+ expect(t, counts.OnUsageError, 1)
+ expect(t, counts.Total, 1)
+
+ resetCounts()
+
+ _ = app.Run([]string{"command", "--generate-bash-completion"})
+ expect(t, counts.BashComplete, 1)
+ expect(t, counts.Total, 1)
+
+ resetCounts()
+
+ oldOnUsageError := app.OnUsageError
+ app.OnUsageError = nil
+ _ = app.Run([]string{"command", "--nope"})
+ expect(t, counts.Total, 0)
+ app.OnUsageError = oldOnUsageError
+
+ resetCounts()
+
+ _ = app.Run([]string{"command", "foo"})
+ expect(t, counts.OnUsageError, 0)
+ expect(t, counts.Before, 1)
+ expect(t, counts.CommandNotFound, 0)
+ expect(t, counts.Action, 2)
+ expect(t, counts.After, 3)
+ expect(t, counts.Total, 3)
+
+ resetCounts()
+
+ app.Before = beforeError
+ _ = app.Run([]string{"command", "bar"})
+ expect(t, counts.OnUsageError, 0)
+ expect(t, counts.Before, 1)
+ expect(t, counts.After, 2)
+ expect(t, counts.Total, 2)
+ app.Before = beforeNoError
+
+ resetCounts()
+
+ app.After = nil
+ _ = app.Run([]string{"command", "bar"})
+ expect(t, counts.OnUsageError, 0)
+ expect(t, counts.Before, 1)
+ expect(t, counts.SubCommand, 2)
+ expect(t, counts.Total, 2)
+ app.After = afterNoError
+
+ resetCounts()
+
+ app.After = afterError
+ err := app.Run([]string{"command", "bar"})
+ if err == nil {
+ t.Fatalf("expected a non-nil error")
+ }
+ expect(t, counts.OnUsageError, 0)
+ expect(t, counts.Before, 1)
+ expect(t, counts.SubCommand, 2)
+ expect(t, counts.After, 3)
+ expect(t, counts.Total, 3)
+ app.After = afterNoError
+
+ resetCounts()
+
+ oldCommands := app.Commands
+ app.Commands = nil
+ _ = app.Run([]string{"command"})
+ expect(t, counts.OnUsageError, 0)
+ expect(t, counts.Before, 1)
+ expect(t, counts.Action, 2)
+ expect(t, counts.After, 3)
+ expect(t, counts.Total, 3)
+ app.Commands = oldCommands
+}
+
+func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
+ var subcommandHelpTopics = [][]string{
+ {"command", "foo", "--help"},
+ {"command", "foo", "-h"},
+ {"command", "foo", "help"},
+ }
+
+ for _, flagSet := range subcommandHelpTopics {
+ t.Logf("==> checking with flags %v", flagSet)
+
+ app := NewApp()
+ buf := new(bytes.Buffer)
+ app.Writer = buf
+
+ subCmdBar := Command{
+ Name: "bar",
+ Usage: "does bar things",
+ }
+ subCmdBaz := Command{
+ Name: "baz",
+ Usage: "does baz things",
+ }
+ cmd := Command{
+ Name: "foo",
+ Description: "descriptive wall of text about how it does foo things",
+ Subcommands: []Command{subCmdBar, subCmdBaz},
+ }
+
+ app.Commands = []Command{cmd}
+ err := app.Run(flagSet)
+
+ if err != nil {
+ t.Error(err)
+ }
+
+ output := buf.String()
+ t.Logf("output: %q\n", buf.Bytes())
+
+ if strings.Contains(output, "No help topic for") {
+ t.Errorf("expect a help topic, got none: \n%q", output)
+ }
+
+ for _, shouldContain := range []string{
+ cmd.Name, cmd.Description,
+ subCmdBar.Name, subCmdBar.Usage,
+ subCmdBaz.Name, subCmdBaz.Usage,
+ } {
+ if !strings.Contains(output, shouldContain) {
+ t.Errorf("want help to contain %q, did not: \n%q", shouldContain, output)
+ }
+ }
+ }
+}
+
+func TestApp_Run_SubcommandFullPath(t *testing.T) {
+ app := NewApp()
+ buf := new(bytes.Buffer)
+ app.Writer = buf
+ app.Name = "command"
+ subCmd := Command{
+ Name: "bar",
+ Usage: "does bar things",
+ }
+ cmd := Command{
+ Name: "foo",
+ Description: "foo commands",
+ Subcommands: []Command{subCmd},
+ }
+ app.Commands = []Command{cmd}
+
+ err := app.Run([]string{"command", "foo", "bar", "--help"})
+ if err != nil {
+ t.Error(err)
+ }
+
+ output := buf.String()
+ if !strings.Contains(output, "command foo bar - does bar things") {
+ t.Errorf("expected full path to subcommand: %s", output)
+ }
+ if !strings.Contains(output, "command foo bar [arguments...]") {
+ t.Errorf("expected full path to subcommand: %s", output)
+ }
+}
+
+func TestApp_Run_SubcommandHelpName(t *testing.T) {
+ app := NewApp()
+ buf := new(bytes.Buffer)
+ app.Writer = buf
+ app.Name = "command"
+ subCmd := Command{
+ Name: "bar",
+ HelpName: "custom",
+ Usage: "does bar things",
+ }
+ cmd := Command{
+ Name: "foo",
+ Description: "foo commands",
+ Subcommands: []Command{subCmd},
+ }
+ app.Commands = []Command{cmd}
+
+ err := app.Run([]string{"command", "foo", "bar", "--help"})
+ if err != nil {
+ t.Error(err)
+ }
+
+ output := buf.String()
+ if !strings.Contains(output, "custom - does bar things") {
+ t.Errorf("expected HelpName for subcommand: %s", output)
+ }
+ if !strings.Contains(output, "custom [arguments...]") {
+ t.Errorf("expected HelpName to subcommand: %s", output)
+ }
+}
+
+func TestApp_Run_CommandHelpName(t *testing.T) {
+ app := NewApp()
+ buf := new(bytes.Buffer)
+ app.Writer = buf
+ app.Name = "command"
+ subCmd := Command{
+ Name: "bar",
+ Usage: "does bar things",
+ }
+ cmd := Command{
+ Name: "foo",
+ HelpName: "custom",
+ Description: "foo commands",
+ Subcommands: []Command{subCmd},
+ }
+ app.Commands = []Command{cmd}
+
+ err := app.Run([]string{"command", "foo", "bar", "--help"})
+ if err != nil {
+ t.Error(err)
+ }
+
+ output := buf.String()
+ if !strings.Contains(output, "command foo bar - does bar things") {
+ t.Errorf("expected full path to subcommand: %s", output)
+ }
+ if !strings.Contains(output, "command foo bar [arguments...]") {
+ t.Errorf("expected full path to subcommand: %s", output)
+ }
+}
+
+func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
+ app := NewApp()
+ buf := new(bytes.Buffer)
+ app.Writer = buf
+ app.Name = "base"
+ subCmd := Command{
+ Name: "bar",
+ HelpName: "custom",
+ Usage: "does bar things",
+ }
+ cmd := Command{
+ Name: "foo",
+ Description: "foo commands",
+ Subcommands: []Command{subCmd},
+ }
+ app.Commands = []Command{cmd}
+
+ err := app.Run([]string{"command", "foo", "--help"})
+ if err != nil {
+ t.Error(err)
+ }
+
+ output := buf.String()
+ if !strings.Contains(output, "base foo - foo commands") {
+ t.Errorf("expected full path to subcommand: %s", output)
+ }
+ if !strings.Contains(output, "base foo command [command options] [arguments...]") {
+ t.Errorf("expected full path to subcommand: %s", output)
+ }
+}
+
+func TestApp_Run_Help(t *testing.T) {
+ var helpArguments = [][]string{{"boom", "--help"}, {"boom", "-h"}, {"boom", "help"}}
+
+ for _, args := range helpArguments {
+ buf := new(bytes.Buffer)
+
+ t.Logf("==> checking with arguments %v", args)
+
+ app := NewApp()
+ app.Name = "boom"
+ app.Usage = "make an explosive entrance"
+ app.Writer = buf
+ app.Action = func(c *Context) error {
+ buf.WriteString("boom I say!")
+ return nil
+ }
+
+ err := app.Run(args)
+ if err != nil {
+ t.Error(err)
+ }
+
+ output := buf.String()
+ t.Logf("output: %q\n", buf.Bytes())
+
+ if !strings.Contains(output, "boom - make an explosive entrance") {
+ t.Errorf("want help to contain %q, did not: \n%q", "boom - make an explosive entrance", output)
+ }
+ }
+}
+
+func TestApp_Run_Version(t *testing.T) {
+ var versionArguments = [][]string{{"boom", "--version"}, {"boom", "-v"}}
+
+ for _, args := range versionArguments {
+ buf := new(bytes.Buffer)
+
+ t.Logf("==> checking with arguments %v", args)
+
+ app := NewApp()
+ app.Name = "boom"
+ app.Usage = "make an explosive entrance"
+ app.Version = "0.1.0"
+ app.Writer = buf
+ app.Action = func(c *Context) error {
+ buf.WriteString("boom I say!")
+ return nil
+ }
+
+ err := app.Run(args)
+ if err != nil {
+ t.Error(err)
+ }
+
+ output := buf.String()
+ t.Logf("output: %q\n", buf.Bytes())
+
+ if !strings.Contains(output, "0.1.0") {
+ t.Errorf("want version to contain %q, did not: \n%q", "0.1.0", output)
+ }
+ }
+}
+
+func TestApp_Run_Categories(t *testing.T) {
+ app := NewApp()
+ app.Name = "categories"
+ app.HideHelp = true
+ app.Commands = []Command{
+ {
+ Name: "command1",
+ Category: "1",
+ },
+ {
+ Name: "command2",
+ Category: "1",
+ },
+ {
+ Name: "command3",
+ Category: "2",
+ },
+ }
+ buf := new(bytes.Buffer)
+ app.Writer = buf
+
+ app.Run([]string{"categories"})
+
+ expect := CommandCategories{
+ &CommandCategory{
+ Name: "1",
+ Commands: []Command{
+ app.Commands[0],
+ app.Commands[1],
+ },
+ },
+ &CommandCategory{
+ Name: "2",
+ Commands: []Command{
+ app.Commands[2],
+ },
+ },
+ }
+ if !reflect.DeepEqual(app.Categories(), expect) {
+ t.Fatalf("expected categories %#v, to equal %#v", app.Categories(), expect)
+ }
+
+ output := buf.String()
+ t.Logf("output: %q\n", buf.Bytes())
+
+ if !strings.Contains(output, "1:\n command1") {
+ t.Errorf("want buffer to include category %q, did not: \n%q", "1:\n command1", output)
+ }
+}
+
+func TestApp_VisibleCategories(t *testing.T) {
+ app := NewApp()
+ app.Name = "visible-categories"
+ app.HideHelp = true
+ app.Commands = []Command{
+ {
+ Name: "command1",
+ Category: "1",
+ HelpName: "foo command1",
+ Hidden: true,
+ },
+ {
+ Name: "command2",
+ Category: "2",
+ HelpName: "foo command2",
+ },
+ {
+ Name: "command3",
+ Category: "3",
+ HelpName: "foo command3",
+ },
+ }
+
+ expected := []*CommandCategory{
+ {
+ Name: "2",
+ Commands: []Command{
+ app.Commands[1],
+ },
+ },
+ {
+ Name: "3",
+ Commands: []Command{
+ app.Commands[2],
+ },
+ },
+ }
+
+ app.Setup()
+ expect(t, expected, app.VisibleCategories())
+
+ app = NewApp()
+ app.Name = "visible-categories"
+ app.HideHelp = true
+ app.Commands = []Command{
+ {
+ Name: "command1",
+ Category: "1",
+ HelpName: "foo command1",
+ Hidden: true,
+ },
+ {
+ Name: "command2",
+ Category: "2",
+ HelpName: "foo command2",
+ Hidden: true,
+ },
+ {
+ Name: "command3",
+ Category: "3",
+ HelpName: "foo command3",
+ },
+ }
+
+ expected = []*CommandCategory{
+ {
+ Name: "3",
+ Commands: []Command{
+ app.Commands[2],
+ },
+ },
+ }
+
+ app.Setup()
+ expect(t, expected, app.VisibleCategories())
+
+ app = NewApp()
+ app.Name = "visible-categories"
+ app.HideHelp = true
+ app.Commands = []Command{
+ {
+ Name: "command1",
+ Category: "1",
+ HelpName: "foo command1",
+ Hidden: true,
+ },
+ {
+ Name: "command2",
+ Category: "2",
+ HelpName: "foo command2",
+ Hidden: true,
+ },
+ {
+ Name: "command3",
+ Category: "3",
+ HelpName: "foo command3",
+ Hidden: true,
+ },
+ }
+
+ expected = []*CommandCategory{}
+
+ app.Setup()
+ expect(t, expected, app.VisibleCategories())
+}
+
+func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
+ app := NewApp()
+ app.Action = func(c *Context) error { return nil }
+ app.Before = func(c *Context) error { return fmt.Errorf("before error") }
+ app.After = func(c *Context) error { return fmt.Errorf("after error") }
+
+ err := app.Run([]string{"foo"})
+ if err == nil {
+ t.Fatalf("expected to receive error from Run, got none")
+ }
+
+ if !strings.Contains(err.Error(), "before error") {
+ t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
+ }
+ if !strings.Contains(err.Error(), "after error") {
+ t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
+ }
+}
+
+func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
+ app := NewApp()
+ app.Commands = []Command{
+ {
+ Subcommands: []Command{
+ {
+ Name: "sub",
+ },
+ },
+ Name: "bar",
+ Before: func(c *Context) error { return fmt.Errorf("before error") },
+ After: func(c *Context) error { return fmt.Errorf("after error") },
+ },
+ }
+
+ err := app.Run([]string{"foo", "bar"})
+ if err == nil {
+ t.Fatalf("expected to receive error from Run, got none")
+ }
+
+ if !strings.Contains(err.Error(), "before error") {
+ t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
+ }
+ if !strings.Contains(err.Error(), "after error") {
+ t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
+ }
+}
+
+func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
+ app := NewApp()
+ app.Flags = []Flag{
+ IntFlag{Name: "flag"},
+ }
+ app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
+ if isSubcommand {
+ t.Errorf("Expect no subcommand")
+ }
+ if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
+ t.Errorf("Expect an invalid value error, but got \"%v\"", err)
+ }
+ return errors.New("intercepted: " + err.Error())
+ }
+ app.Commands = []Command{
+ {
+ Name: "bar",
+ },
+ }
+
+ err := app.Run([]string{"foo", "--flag=wrong"})
+ if err == nil {
+ t.Fatalf("expected to receive error from Run, got none")
+ }
+
+ if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
+ t.Errorf("Expect an intercepted error, but got \"%v\"", err)
+ }
+}
+
+func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
+ app := NewApp()
+ app.Flags = []Flag{
+ IntFlag{Name: "flag"},
+ }
+ app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
+ if isSubcommand {
+ t.Errorf("Expect subcommand")
+ }
+ if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
+ t.Errorf("Expect an invalid value error, but got \"%v\"", err)
+ }
+ return errors.New("intercepted: " + err.Error())
+ }
+ app.Commands = []Command{
+ {
+ Name: "bar",
+ },
+ }
+
+ err := app.Run([]string{"foo", "--flag=wrong", "bar"})
+ if err == nil {
+ t.Fatalf("expected to receive error from Run, got none")
+ }
+
+ if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
+ t.Errorf("Expect an intercepted error, but got \"%v\"", err)
+ }
+}
+
+func TestHandleAction_WithNonFuncAction(t *testing.T) {
+ app := NewApp()
+ app.Action = 42
+ err := HandleAction(app.Action, NewContext(app, flagSet(app.Name, app.Flags), nil))
+
+ if err == nil {
+ t.Fatalf("expected to receive error from Run, got none")
+ }
+
+ exitErr, ok := err.(*ExitError)
+
+ if !ok {
+ t.Fatalf("expected to receive a *ExitError")
+ }
+
+ if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action type") {
+ t.Fatalf("expected an unknown Action error, but got: %v", exitErr.Error())
+ }
+
+ if exitErr.ExitCode() != 2 {
+ t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode())
+ }
+}
+
+func TestHandleAction_WithInvalidFuncSignature(t *testing.T) {
+ app := NewApp()
+ app.Action = func() string { return "" }
+ err := HandleAction(app.Action, NewContext(app, flagSet(app.Name, app.Flags), nil))
+
+ if err == nil {
+ t.Fatalf("expected to receive error from Run, got none")
+ }
+
+ exitErr, ok := err.(*ExitError)
+
+ if !ok {
+ t.Fatalf("expected to receive a *ExitError")
+ }
+
+ if !strings.HasPrefix(exitErr.Error(), "ERROR unknown Action error") {
+ t.Fatalf("expected an unknown Action error, but got: %v", exitErr.Error())
+ }
+
+ if exitErr.ExitCode() != 2 {
+ t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode())
+ }
+}
+
+func TestHandleAction_WithInvalidFuncReturnSignature(t *testing.T) {
+ app := NewApp()
+ app.Action = func(_ *Context) (int, error) { return 0, nil }
+ err := HandleAction(app.Action, NewContext(app, flagSet(app.Name, app.Flags), nil))
+
+ if err == nil {
+ t.Fatalf("expected to receive error from Run, got none")
+ }
+
+ exitErr, ok := err.(*ExitError)
+
+ if !ok {
+ t.Fatalf("expected to receive a *ExitError")
+ }
+
+ if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action signature") {
+ t.Fatalf("expected an invalid Action signature error, but got: %v", exitErr.Error())
+ }
+
+ if exitErr.ExitCode() != 2 {
+ t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode())
+ }
+}
+
+func TestHandleAction_WithUnknownPanic(t *testing.T) {
+ defer func() { refute(t, recover(), nil) }()
+
+ var fn ActionFunc
+
+ app := NewApp()
+ app.Action = func(ctx *Context) error {
+ fn(ctx)
+ return nil
+ }
+ HandleAction(app.Action, NewContext(app, flagSet(app.Name, app.Flags), nil))
+}
diff --git a/vendor/github.com/codegangsta/cli/appveyor.yml b/vendor/github.com/codegangsta/cli/appveyor.yml
new file mode 100644
index 0000000..173086e
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/appveyor.yml
@@ -0,0 +1,25 @@
+version: "{build}"
+
+os: Windows Server 2012 R2
+
+clone_folder: c:\gopath\src\github.com\urfave\cli
+
+environment:
+ GOPATH: C:\gopath
+ GOVERSION: 1.6
+ PYTHON: C:\Python27-x64
+ PYTHON_VERSION: 2.7.x
+ PYTHON_ARCH: 64
+ GFMXR_DEBUG: 1
+
+install:
+- set PATH=%GOPATH%\bin;C:\go\bin;%PATH%
+- go version
+- go env
+- go get github.com/urfave/gfmxr/...
+- go get -v -t ./...
+
+build_script:
+- python runtests vet
+- python runtests test
+- python runtests gfmxr
diff --git a/vendor/github.com/codegangsta/cli/autocomplete/bash_autocomplete b/vendor/github.com/codegangsta/cli/autocomplete/bash_autocomplete
new file mode 100644
index 0000000..21a232f
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/autocomplete/bash_autocomplete
@@ -0,0 +1,14 @@
+#! /bin/bash
+
+: ${PROG:=$(basename ${BASH_SOURCE})}
+
+_cli_bash_autocomplete() {
+ local cur opts base
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
+ COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
+ return 0
+ }
+
+ complete -F _cli_bash_autocomplete $PROG
diff --git a/vendor/github.com/codegangsta/cli/autocomplete/zsh_autocomplete b/vendor/github.com/codegangsta/cli/autocomplete/zsh_autocomplete
new file mode 100644
index 0000000..5430a18
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/autocomplete/zsh_autocomplete
@@ -0,0 +1,5 @@
+autoload -U compinit && compinit
+autoload -U bashcompinit && bashcompinit
+
+script_dir=$(dirname $0)
+source ${script_dir}/bash_autocomplete
diff --git a/vendor/github.com/codegangsta/cli/category.go b/vendor/github.com/codegangsta/cli/category.go
new file mode 100644
index 0000000..1a60550
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/category.go
@@ -0,0 +1,44 @@
+package cli
+
+// CommandCategories is a slice of *CommandCategory.
+type CommandCategories []*CommandCategory
+
+// CommandCategory is a category containing commands.
+type CommandCategory struct {
+ Name string
+ Commands Commands
+}
+
+func (c CommandCategories) Less(i, j int) bool {
+ return c[i].Name < c[j].Name
+}
+
+func (c CommandCategories) Len() int {
+ return len(c)
+}
+
+func (c CommandCategories) Swap(i, j int) {
+ c[i], c[j] = c[j], c[i]
+}
+
+// AddCommand adds a command to a category.
+func (c CommandCategories) AddCommand(category string, command Command) CommandCategories {
+ for _, commandCategory := range c {
+ if commandCategory.Name == category {
+ commandCategory.Commands = append(commandCategory.Commands, command)
+ return c
+ }
+ }
+ return append(c, &CommandCategory{Name: category, Commands: []Command{command}})
+}
+
+// VisibleCommands returns a slice of the Commands with Hidden=false
+func (c *CommandCategory) VisibleCommands() []Command {
+ ret := []Command{}
+ for _, command := range c.Commands {
+ if !command.Hidden {
+ ret = append(ret, command)
+ }
+ }
+ return ret
+}
diff --git a/vendor/github.com/codegangsta/cli/cli.go b/vendor/github.com/codegangsta/cli/cli.go
new file mode 100644
index 0000000..f0440c5
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/cli.go
@@ -0,0 +1,19 @@
+// Package cli provides a minimal framework for creating and organizing command line
+// Go applications. cli is designed to be easy to understand and write, the most simple
+// cli application can be written as follows:
+// func main() {
+// cli.NewApp().Run(os.Args)
+// }
+//
+// Of course this application does not do much, so let's make this an actual application:
+// func main() {
+// app := cli.NewApp()
+// app.Name = "greet"
+// app.Usage = "say a greeting"
+// app.Action = func(c *cli.Context) error {
+// println("Greetings")
+// }
+//
+// app.Run(os.Args)
+// }
+package cli
diff --git a/vendor/github.com/codegangsta/cli/command.go b/vendor/github.com/codegangsta/cli/command.go
new file mode 100644
index 0000000..8950cca
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/command.go
@@ -0,0 +1,279 @@
+package cli
+
+import (
+ "fmt"
+ "io/ioutil"
+ "sort"
+ "strings"
+)
+
+// Command is a subcommand for a cli.App.
+type Command struct {
+ // The name of the command
+ Name string
+ // short name of the command. Typically one character (deprecated, use `Aliases`)
+ ShortName string
+ // A list of aliases for the command
+ Aliases []string
+ // A short description of the usage of this command
+ Usage string
+ // Custom text to show on USAGE section of help
+ UsageText string
+ // A longer explanation of how the command works
+ Description string
+ // A short description of the arguments of this command
+ ArgsUsage string
+ // The category the command is part of
+ Category string
+ // The function to call when checking for bash command completions
+ BashComplete BashCompleteFunc
+ // An action to execute before any sub-subcommands are run, but after the context is ready
+ // If a non-nil error is returned, no sub-subcommands are run
+ Before BeforeFunc
+ // An action to execute after any subcommands are run, but after the subcommand has finished
+ // It is run even if Action() panics
+ After AfterFunc
+ // The function to call when this command is invoked
+ Action interface{}
+ // TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind
+ // of deprecation period has passed, maybe?
+
+ // Execute this function if a usage error occurs.
+ OnUsageError OnUsageErrorFunc
+ // List of child commands
+ Subcommands Commands
+ // List of flags to parse
+ Flags []Flag
+ // Treat all flags as normal arguments if true
+ SkipFlagParsing bool
+ // Boolean to hide built-in help command
+ HideHelp bool
+ // Boolean to hide this command from help or completion
+ Hidden bool
+
+ // Full name of command for help, defaults to full command name, including parent commands.
+ HelpName string
+ commandNamePath []string
+}
+
+// FullName returns the full name of the command.
+// For subcommands this ensures that parent commands are part of the command path
+func (c Command) FullName() string {
+ if c.commandNamePath == nil {
+ return c.Name
+ }
+ return strings.Join(c.commandNamePath, " ")
+}
+
+// Commands is a slice of Command
+type Commands []Command
+
+// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
+func (c Command) Run(ctx *Context) (err error) {
+ if len(c.Subcommands) > 0 {
+ return c.startApp(ctx)
+ }
+
+ if !c.HideHelp && (HelpFlag != BoolFlag{}) {
+ // append help to flags
+ c.Flags = append(
+ c.Flags,
+ HelpFlag,
+ )
+ }
+
+ if ctx.App.EnableBashCompletion {
+ c.Flags = append(c.Flags, BashCompletionFlag)
+ }
+
+ set := flagSet(c.Name, c.Flags)
+ set.SetOutput(ioutil.Discard)
+
+ if !c.SkipFlagParsing {
+ firstFlagIndex := -1
+ terminatorIndex := -1
+ for index, arg := range ctx.Args() {
+ if arg == "--" {
+ terminatorIndex = index
+ break
+ } else if arg == "-" {
+ // Do nothing. A dash alone is not really a flag.
+ continue
+ } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
+ firstFlagIndex = index
+ }
+ }
+
+ if firstFlagIndex > -1 {
+ args := ctx.Args()
+ regularArgs := make([]string, len(args[1:firstFlagIndex]))
+ copy(regularArgs, args[1:firstFlagIndex])
+
+ var flagArgs []string
+ if terminatorIndex > -1 {
+ flagArgs = args[firstFlagIndex:terminatorIndex]
+ regularArgs = append(regularArgs, args[terminatorIndex:]...)
+ } else {
+ flagArgs = args[firstFlagIndex:]
+ }
+
+ err = set.Parse(append(flagArgs, regularArgs...))
+ } else {
+ err = set.Parse(ctx.Args().Tail())
+ }
+ } else {
+ if c.SkipFlagParsing {
+ err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...))
+ }
+ }
+
+ if err != nil {
+ if c.OnUsageError != nil {
+ err := c.OnUsageError(ctx, err, false)
+ HandleExitCoder(err)
+ return err
+ }
+ fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
+ fmt.Fprintln(ctx.App.Writer)
+ ShowCommandHelp(ctx, c.Name)
+ return err
+ }
+
+ nerr := normalizeFlags(c.Flags, set)
+ if nerr != nil {
+ fmt.Fprintln(ctx.App.Writer, nerr)
+ fmt.Fprintln(ctx.App.Writer)
+ ShowCommandHelp(ctx, c.Name)
+ return nerr
+ }
+
+ context := NewContext(ctx.App, set, ctx)
+
+ if checkCommandCompletions(context, c.Name) {
+ return nil
+ }
+
+ if checkCommandHelp(context, c.Name) {
+ return nil
+ }
+
+ if c.After != nil {
+ defer func() {
+ afterErr := c.After(context)
+ if afterErr != nil {
+ HandleExitCoder(err)
+ if err != nil {
+ err = NewMultiError(err, afterErr)
+ } else {
+ err = afterErr
+ }
+ }
+ }()
+ }
+
+ if c.Before != nil {
+ err = c.Before(context)
+ if err != nil {
+ fmt.Fprintln(ctx.App.Writer, err)
+ fmt.Fprintln(ctx.App.Writer)
+ ShowCommandHelp(ctx, c.Name)
+ HandleExitCoder(err)
+ return err
+ }
+ }
+
+ context.Command = c
+ err = HandleAction(c.Action, context)
+
+ if err != nil {
+ HandleExitCoder(err)
+ }
+ return err
+}
+
+// Names returns the names including short names and aliases.
+func (c Command) Names() []string {
+ names := []string{c.Name}
+
+ if c.ShortName != "" {
+ names = append(names, c.ShortName)
+ }
+
+ return append(names, c.Aliases...)
+}
+
+// HasName returns true if Command.Name or Command.ShortName matches given name
+func (c Command) HasName(name string) bool {
+ for _, n := range c.Names() {
+ if n == name {
+ return true
+ }
+ }
+ return false
+}
+
+func (c Command) startApp(ctx *Context) error {
+ app := NewApp()
+ app.Metadata = ctx.App.Metadata
+ // set the name and usage
+ app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
+ if c.HelpName == "" {
+ app.HelpName = c.HelpName
+ } else {
+ app.HelpName = app.Name
+ }
+
+ if c.Description != "" {
+ app.Usage = c.Description
+ } else {
+ app.Usage = c.Usage
+ }
+
+ // set CommandNotFound
+ app.CommandNotFound = ctx.App.CommandNotFound
+
+ // set the flags and commands
+ app.Commands = c.Subcommands
+ app.Flags = c.Flags
+ app.HideHelp = c.HideHelp
+
+ app.Version = ctx.App.Version
+ app.HideVersion = ctx.App.HideVersion
+ app.Compiled = ctx.App.Compiled
+ app.Author = ctx.App.Author
+ app.Email = ctx.App.Email
+ app.Writer = ctx.App.Writer
+
+ app.categories = CommandCategories{}
+ for _, command := range c.Subcommands {
+ app.categories = app.categories.AddCommand(command.Category, command)
+ }
+
+ sort.Sort(app.categories)
+
+ // bash completion
+ app.EnableBashCompletion = ctx.App.EnableBashCompletion
+ if c.BashComplete != nil {
+ app.BashComplete = c.BashComplete
+ }
+
+ // set the actions
+ app.Before = c.Before
+ app.After = c.After
+ if c.Action != nil {
+ app.Action = c.Action
+ } else {
+ app.Action = helpSubcommand.Action
+ }
+
+ for index, cc := range app.Commands {
+ app.Commands[index].commandNamePath = []string{c.Name, cc.Name}
+ }
+
+ return app.RunAsSubcommand(ctx)
+}
+
+// VisibleFlags returns a slice of the Flags with Hidden=false
+func (c Command) VisibleFlags() []Flag {
+ return visibleFlags(c.Flags)
+}
diff --git a/vendor/github.com/codegangsta/cli/command_test.go b/vendor/github.com/codegangsta/cli/command_test.go
new file mode 100644
index 0000000..6608254
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/command_test.go
@@ -0,0 +1,101 @@
+package cli
+
+import (
+ "errors"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "strings"
+ "testing"
+)
+
+func TestCommandFlagParsing(t *testing.T) {
+ cases := []struct {
+ testArgs []string
+ skipFlagParsing bool
+ expectedErr error
+ }{
+ {[]string{"blah", "blah", "-break"}, false, errors.New("flag provided but not defined: -break")}, // Test normal "not ignoring flags" flow
+ {[]string{"blah", "blah"}, true, nil}, // Test SkipFlagParsing without any args that look like flags
+ {[]string{"blah", "-break"}, true, nil}, // Test SkipFlagParsing with random flag arg
+ {[]string{"blah", "-help"}, true, nil}, // Test SkipFlagParsing with "special" help flag arg
+ }
+
+ for _, c := range cases {
+ app := NewApp()
+ app.Writer = ioutil.Discard
+ set := flag.NewFlagSet("test", 0)
+ set.Parse(c.testArgs)
+
+ context := NewContext(app, set, nil)
+
+ command := Command{
+ Name: "test-cmd",
+ Aliases: []string{"tc"},
+ Usage: "this is for testing",
+ Description: "testing",
+ Action: func(_ *Context) error { return nil },
+ }
+
+ command.SkipFlagParsing = c.skipFlagParsing
+
+ err := command.Run(context)
+
+ expect(t, err, c.expectedErr)
+ expect(t, []string(context.Args()), c.testArgs)
+ }
+}
+
+func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
+ app := NewApp()
+ app.Commands = []Command{
+ {
+ Name: "bar",
+ Before: func(c *Context) error {
+ return fmt.Errorf("before error")
+ },
+ After: func(c *Context) error {
+ return fmt.Errorf("after error")
+ },
+ },
+ }
+
+ err := app.Run([]string{"foo", "bar"})
+ if err == nil {
+ t.Fatalf("expected to receive error from Run, got none")
+ }
+
+ if !strings.Contains(err.Error(), "before error") {
+ t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
+ }
+ if !strings.Contains(err.Error(), "after error") {
+ t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
+ }
+}
+
+func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
+ app := NewApp()
+ app.Commands = []Command{
+ {
+ Name: "bar",
+ Flags: []Flag{
+ IntFlag{Name: "flag"},
+ },
+ OnUsageError: func(c *Context, err error, _ bool) error {
+ if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
+ t.Errorf("Expect an invalid value error, but got \"%v\"", err)
+ }
+ return errors.New("intercepted: " + err.Error())
+ },
+ },
+ }
+
+ err := app.Run([]string{"foo", "bar", "--flag=wrong"})
+ if err == nil {
+ t.Fatalf("expected to receive error from Run, got none")
+ }
+
+ if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
+ t.Errorf("Expect an intercepted error, but got \"%v\"", err)
+ }
+}
diff --git a/vendor/github.com/codegangsta/cli/context.go b/vendor/github.com/codegangsta/cli/context.go
new file mode 100644
index 0000000..879bae5
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/context.go
@@ -0,0 +1,549 @@
+package cli
+
+import (
+ "errors"
+ "flag"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Context is a type that is passed through to
+// each Handler action in a cli application. Context
+// can be used to retrieve context-specific Args and
+// parsed command-line options.
+type Context struct {
+ App *App
+ Command Command
+ flagSet *flag.FlagSet
+ setFlags map[string]bool
+ globalSetFlags map[string]bool
+ parentContext *Context
+}
+
+// NewContext creates a new context. For use in when invoking an App or Command action.
+func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
+ return &Context{App: app, flagSet: set, parentContext: parentCtx}
+}
+
+// Int looks up the value of a local int flag, returns 0 if no int flag exists
+func (c *Context) Int(name string) int {
+ return lookupInt(name, c.flagSet)
+}
+
+// Int64 looks up the value of a local int flag, returns 0 if no int flag exists
+func (c *Context) Int64(name string) int64 {
+ return lookupInt64(name, c.flagSet)
+}
+
+// Uint looks up the value of a local int flag, returns 0 if no int flag exists
+func (c *Context) Uint(name string) uint {
+ return lookupUint(name, c.flagSet)
+}
+
+// Uint64 looks up the value of a local int flag, returns 0 if no int flag exists
+func (c *Context) Uint64(name string) uint64 {
+ return lookupUint64(name, c.flagSet)
+}
+
+// Duration looks up the value of a local time.Duration flag, returns 0 if no
+// time.Duration flag exists
+func (c *Context) Duration(name string) time.Duration {
+ return lookupDuration(name, c.flagSet)
+}
+
+// Float64 looks up the value of a local float64 flag, returns 0 if no float64
+// flag exists
+func (c *Context) Float64(name string) float64 {
+ return lookupFloat64(name, c.flagSet)
+}
+
+// Bool looks up the value of a local bool flag, returns false if no bool flag exists
+func (c *Context) Bool(name string) bool {
+ return lookupBool(name, c.flagSet)
+}
+
+// BoolT looks up the value of a local boolT flag, returns false if no bool flag exists
+func (c *Context) BoolT(name string) bool {
+ return lookupBoolT(name, c.flagSet)
+}
+
+// String looks up the value of a local string flag, returns "" if no string flag exists
+func (c *Context) String(name string) string {
+ return lookupString(name, c.flagSet)
+}
+
+// StringSlice looks up the value of a local string slice flag, returns nil if no
+// string slice flag exists
+func (c *Context) StringSlice(name string) []string {
+ return lookupStringSlice(name, c.flagSet)
+}
+
+// IntSlice looks up the value of a local int slice flag, returns nil if no int
+// slice flag exists
+func (c *Context) IntSlice(name string) []int {
+ return lookupIntSlice(name, c.flagSet)
+}
+
+// Int64Slice looks up the value of a local int slice flag, returns nil if no int
+// slice flag exists
+func (c *Context) Int64Slice(name string) []int64 {
+ return lookupInt64Slice(name, c.flagSet)
+}
+
+// Generic looks up the value of a local generic flag, returns nil if no generic
+// flag exists
+func (c *Context) Generic(name string) interface{} {
+ return lookupGeneric(name, c.flagSet)
+}
+
+// GlobalInt looks up the value of a global int flag, returns 0 if no int flag exists
+func (c *Context) GlobalInt(name string) int {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupInt(name, fs)
+ }
+ return 0
+}
+
+// GlobalInt64 looks up the value of a global int flag, returns 0 if no int flag exists
+func (c *Context) GlobalInt64(name string) int64 {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupInt64(name, fs)
+ }
+ return 0
+}
+
+// GlobalUint looks up the value of a global int flag, returns 0 if no int flag exists
+func (c *Context) GlobalUint(name string) uint {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupUint(name, fs)
+ }
+ return 0
+}
+
+// GlobalUint64 looks up the value of a global int flag, returns 0 if no int flag exists
+func (c *Context) GlobalUint64(name string) uint64 {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupUint64(name, fs)
+ }
+ return 0
+}
+
+// GlobalFloat64 looks up the value of a global float64 flag, returns float64(0)
+// if no float64 flag exists
+func (c *Context) GlobalFloat64(name string) float64 {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupFloat64(name, fs)
+ }
+ return float64(0)
+}
+
+// GlobalDuration looks up the value of a global time.Duration flag, returns 0
+// if no time.Duration flag exists
+func (c *Context) GlobalDuration(name string) time.Duration {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupDuration(name, fs)
+ }
+ return 0
+}
+
+// GlobalBool looks up the value of a global bool flag, returns false if no bool
+// flag exists
+func (c *Context) GlobalBool(name string) bool {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupBool(name, fs)
+ }
+ return false
+}
+
+// GlobalBoolT looks up the value of a global bool flag, returns true if no bool
+// flag exists
+func (c *Context) GlobalBoolT(name string) bool {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupBoolT(name, fs)
+ }
+ return false
+}
+
+// GlobalString looks up the value of a global string flag, returns "" if no
+// string flag exists
+func (c *Context) GlobalString(name string) string {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupString(name, fs)
+ }
+ return ""
+}
+
+// GlobalStringSlice looks up the value of a global string slice flag, returns
+// nil if no string slice flag exists
+func (c *Context) GlobalStringSlice(name string) []string {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupStringSlice(name, fs)
+ }
+ return nil
+}
+
+// GlobalIntSlice looks up the value of a global int slice flag, returns nil if
+// no int slice flag exists
+func (c *Context) GlobalIntSlice(name string) []int {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupIntSlice(name, fs)
+ }
+ return nil
+}
+
+// GlobalInt64Slice looks up the value of a global int slice flag, returns nil if
+// no int slice flag exists
+func (c *Context) GlobalInt64Slice(name string) []int64 {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupInt64Slice(name, fs)
+ }
+ return nil
+}
+
+// GlobalGeneric looks up the value of a global generic flag, returns nil if no
+// generic flag exists
+func (c *Context) GlobalGeneric(name string) interface{} {
+ if fs := lookupGlobalFlagSet(name, c); fs != nil {
+ return lookupGeneric(name, fs)
+ }
+ return nil
+}
+
+// NumFlags returns the number of flags set
+func (c *Context) NumFlags() int {
+ return c.flagSet.NFlag()
+}
+
+// Set sets a context flag to a value.
+func (c *Context) Set(name, value string) error {
+ return c.flagSet.Set(name, value)
+}
+
+// GlobalSet sets a context flag to a value on the global flagset
+func (c *Context) GlobalSet(name, value string) error {
+ return globalContext(c).flagSet.Set(name, value)
+}
+
+// IsSet determines if the flag was actually set
+func (c *Context) IsSet(name string) bool {
+ if c.setFlags == nil {
+ c.setFlags = make(map[string]bool)
+ c.flagSet.Visit(func(f *flag.Flag) {
+ c.setFlags[f.Name] = true
+ })
+ }
+ return c.setFlags[name] == true
+}
+
+// GlobalIsSet determines if the global flag was actually set
+func (c *Context) GlobalIsSet(name string) bool {
+ if c.globalSetFlags == nil {
+ c.globalSetFlags = make(map[string]bool)
+ ctx := c
+ if ctx.parentContext != nil {
+ ctx = ctx.parentContext
+ }
+ for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext {
+ ctx.flagSet.Visit(func(f *flag.Flag) {
+ c.globalSetFlags[f.Name] = true
+ })
+ }
+ }
+ return c.globalSetFlags[name]
+}
+
+// FlagNames returns a slice of flag names used in this context.
+func (c *Context) FlagNames() (names []string) {
+ for _, flag := range c.Command.Flags {
+ name := strings.Split(flag.GetName(), ",")[0]
+ if name == "help" {
+ continue
+ }
+ names = append(names, name)
+ }
+ return
+}
+
+// GlobalFlagNames returns a slice of global flag names used by the app.
+func (c *Context) GlobalFlagNames() (names []string) {
+ for _, flag := range c.App.Flags {
+ name := strings.Split(flag.GetName(), ",")[0]
+ if name == "help" || name == "version" {
+ continue
+ }
+ names = append(names, name)
+ }
+ return
+}
+
+// Parent returns the parent context, if any
+func (c *Context) Parent() *Context {
+ return c.parentContext
+}
+
+// Args contains apps console arguments
+type Args []string
+
+// Args returns the command line arguments associated with the context.
+func (c *Context) Args() Args {
+ args := Args(c.flagSet.Args())
+ return args
+}
+
+// NArg returns the number of the command line arguments.
+func (c *Context) NArg() int {
+ return len(c.Args())
+}
+
+// Get returns the nth argument, or else a blank string
+func (a Args) Get(n int) string {
+ if len(a) > n {
+ return a[n]
+ }
+ return ""
+}
+
+// First returns the first argument, or else a blank string
+func (a Args) First() string {
+ return a.Get(0)
+}
+
+// Tail returns the rest of the arguments (not the first one)
+// or else an empty string slice
+func (a Args) Tail() []string {
+ if len(a) >= 2 {
+ return []string(a)[1:]
+ }
+ return []string{}
+}
+
+// Present checks if there are any arguments present
+func (a Args) Present() bool {
+ return len(a) != 0
+}
+
+// Swap swaps arguments at the given indexes
+func (a Args) Swap(from, to int) error {
+ if from >= len(a) || to >= len(a) {
+ return errors.New("index out of range")
+ }
+ a[from], a[to] = a[to], a[from]
+ return nil
+}
+
+func globalContext(ctx *Context) *Context {
+ if ctx == nil {
+ return nil
+ }
+
+ for {
+ if ctx.parentContext == nil {
+ return ctx
+ }
+ ctx = ctx.parentContext
+ }
+}
+
+func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
+ if ctx.parentContext != nil {
+ ctx = ctx.parentContext
+ }
+ for ; ctx != nil; ctx = ctx.parentContext {
+ if f := ctx.flagSet.Lookup(name); f != nil {
+ return ctx.flagSet
+ }
+ }
+ return nil
+}
+
+func lookupInt(name string, set *flag.FlagSet) int {
+ f := set.Lookup(name)
+ if f != nil {
+ val, err := strconv.ParseInt(f.Value.String(), 0, 64)
+ if err != nil {
+ return 0
+ }
+ return int(val)
+ }
+
+ return 0
+}
+
+func lookupInt64(name string, set *flag.FlagSet) int64 {
+ f := set.Lookup(name)
+ if f != nil {
+ val, err := strconv.ParseInt(f.Value.String(), 0, 64)
+ if err != nil {
+ return 0
+ }
+ return val
+ }
+
+ return 0
+}
+
+func lookupUint(name string, set *flag.FlagSet) uint {
+ f := set.Lookup(name)
+ if f != nil {
+ val, err := strconv.ParseUint(f.Value.String(), 0, 64)
+ if err != nil {
+ return 0
+ }
+ return uint(val)
+ }
+
+ return 0
+}
+
+func lookupUint64(name string, set *flag.FlagSet) uint64 {
+ f := set.Lookup(name)
+ if f != nil {
+ val, err := strconv.ParseUint(f.Value.String(), 0, 64)
+ if err != nil {
+ return 0
+ }
+ return val
+ }
+
+ return 0
+}
+
+func lookupDuration(name string, set *flag.FlagSet) time.Duration {
+ f := set.Lookup(name)
+ if f != nil {
+ val, err := time.ParseDuration(f.Value.String())
+ if err == nil {
+ return val
+ }
+ }
+
+ return 0
+}
+
+func lookupFloat64(name string, set *flag.FlagSet) float64 {
+ f := set.Lookup(name)
+ if f != nil {
+ val, err := strconv.ParseFloat(f.Value.String(), 64)
+ if err != nil {
+ return 0
+ }
+ return val
+ }
+
+ return 0
+}
+
+func lookupString(name string, set *flag.FlagSet) string {
+ f := set.Lookup(name)
+ if f != nil {
+ return f.Value.String()
+ }
+
+ return ""
+}
+
+func lookupStringSlice(name string, set *flag.FlagSet) []string {
+ f := set.Lookup(name)
+ if f != nil {
+ return (f.Value.(*StringSlice)).Value()
+
+ }
+
+ return nil
+}
+
+func lookupIntSlice(name string, set *flag.FlagSet) []int {
+ f := set.Lookup(name)
+ if f != nil {
+ return (f.Value.(*IntSlice)).Value()
+
+ }
+
+ return nil
+}
+
+func lookupInt64Slice(name string, set *flag.FlagSet) []int64 {
+ f := set.Lookup(name)
+ if f != nil {
+ return (f.Value.(*Int64Slice)).Value()
+
+ }
+
+ return nil
+}
+
+func lookupGeneric(name string, set *flag.FlagSet) interface{} {
+ f := set.Lookup(name)
+ if f != nil {
+ return f.Value
+ }
+ return nil
+}
+
+func lookupBool(name string, set *flag.FlagSet) bool {
+ f := set.Lookup(name)
+ if f != nil {
+ val, err := strconv.ParseBool(f.Value.String())
+ if err != nil {
+ return false
+ }
+ return val
+ }
+
+ return false
+}
+
+func lookupBoolT(name string, set *flag.FlagSet) bool {
+ f := set.Lookup(name)
+ if f != nil {
+ val, err := strconv.ParseBool(f.Value.String())
+ if err != nil {
+ return true
+ }
+ return val
+ }
+
+ return false
+}
+
+func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
+ switch ff.Value.(type) {
+ case *StringSlice:
+ default:
+ set.Set(name, ff.Value.String())
+ }
+}
+
+func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
+ visited := make(map[string]bool)
+ set.Visit(func(f *flag.Flag) {
+ visited[f.Name] = true
+ })
+ for _, f := range flags {
+ parts := strings.Split(f.GetName(), ",")
+ if len(parts) == 1 {
+ continue
+ }
+ var ff *flag.Flag
+ for _, name := range parts {
+ name = strings.Trim(name, " ")
+ if visited[name] {
+ if ff != nil {
+ return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
+ }
+ ff = set.Lookup(name)
+ }
+ }
+ if ff == nil {
+ continue
+ }
+ for _, name := range parts {
+ name = strings.Trim(name, " ")
+ if !visited[name] {
+ copyFlag(name, ff, set)
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/codegangsta/cli/context_test.go b/vendor/github.com/codegangsta/cli/context_test.go
new file mode 100644
index 0000000..5c68fdd
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/context_test.go
@@ -0,0 +1,297 @@
+package cli
+
+import (
+ "flag"
+ "testing"
+ "time"
+)
+
+func TestNewContext(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Int("myflag", 12, "doc")
+ set.Int64("myflagInt64", int64(12), "doc")
+ set.Uint("myflagUint", uint(93), "doc")
+ set.Uint64("myflagUint64", uint64(93), "doc")
+ set.Float64("myflag64", float64(17), "doc")
+ globalSet := flag.NewFlagSet("test", 0)
+ globalSet.Int("myflag", 42, "doc")
+ globalSet.Int64("myflagInt64", int64(42), "doc")
+ globalSet.Uint("myflagUint", uint(33), "doc")
+ globalSet.Uint64("myflagUint64", uint64(33), "doc")
+ globalSet.Float64("myflag64", float64(47), "doc")
+ globalCtx := NewContext(nil, globalSet, nil)
+ command := Command{Name: "mycommand"}
+ c := NewContext(nil, set, globalCtx)
+ c.Command = command
+ expect(t, c.Int("myflag"), 12)
+ expect(t, c.Int64("myflagInt64"), int64(12))
+ expect(t, c.Uint("myflagUint"), uint(93))
+ expect(t, c.Uint64("myflagUint64"), uint64(93))
+ expect(t, c.Float64("myflag64"), float64(17))
+ expect(t, c.GlobalInt("myflag"), 42)
+ expect(t, c.GlobalInt64("myflagInt64"), int64(42))
+ expect(t, c.GlobalUint("myflagUint"), uint(33))
+ expect(t, c.GlobalUint64("myflagUint64"), uint64(33))
+ expect(t, c.GlobalFloat64("myflag64"), float64(47))
+ expect(t, c.Command.Name, "mycommand")
+}
+
+func TestContext_Int(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Int("myflag", 12, "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.Int("myflag"), 12)
+}
+
+func TestContext_Int64(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Int64("myflagInt64", 12, "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.Int64("myflagInt64"), int64(12))
+}
+
+func TestContext_Uint(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Uint("myflagUint", uint(13), "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.Uint("myflagUint"), uint(13))
+}
+
+func TestContext_Uint64(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Uint64("myflagUint64", uint64(9), "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.Uint64("myflagUint64"), uint64(9))
+}
+
+func TestContext_GlobalInt(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Int("myflag", 12, "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.GlobalInt("myflag"), 12)
+ expect(t, c.GlobalInt("nope"), 0)
+}
+
+func TestContext_GlobalInt64(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Int64("myflagInt64", 12, "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.GlobalInt64("myflagInt64"), int64(12))
+ expect(t, c.GlobalInt64("nope"), int64(0))
+}
+
+func TestContext_Float64(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Float64("myflag", float64(17), "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.Float64("myflag"), float64(17))
+}
+
+func TestContext_GlobalFloat64(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Float64("myflag", float64(17), "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.GlobalFloat64("myflag"), float64(17))
+ expect(t, c.GlobalFloat64("nope"), float64(0))
+}
+
+func TestContext_Duration(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Duration("myflag", time.Duration(12*time.Second), "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.Duration("myflag"), time.Duration(12*time.Second))
+}
+
+func TestContext_String(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.String("myflag", "hello world", "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.String("myflag"), "hello world")
+}
+
+func TestContext_Bool(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Bool("myflag", false, "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.Bool("myflag"), false)
+}
+
+func TestContext_BoolT(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Bool("myflag", true, "doc")
+ c := NewContext(nil, set, nil)
+ expect(t, c.BoolT("myflag"), true)
+}
+
+func TestContext_GlobalBool(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+
+ globalSet := flag.NewFlagSet("test-global", 0)
+ globalSet.Bool("myflag", false, "doc")
+ globalCtx := NewContext(nil, globalSet, nil)
+
+ c := NewContext(nil, set, globalCtx)
+ expect(t, c.GlobalBool("myflag"), false)
+ expect(t, c.GlobalBool("nope"), false)
+}
+
+func TestContext_GlobalBoolT(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+
+ globalSet := flag.NewFlagSet("test-global", 0)
+ globalSet.Bool("myflag", true, "doc")
+ globalCtx := NewContext(nil, globalSet, nil)
+
+ c := NewContext(nil, set, globalCtx)
+ expect(t, c.GlobalBoolT("myflag"), true)
+ expect(t, c.GlobalBoolT("nope"), false)
+}
+
+func TestContext_Args(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Bool("myflag", false, "doc")
+ c := NewContext(nil, set, nil)
+ set.Parse([]string{"--myflag", "bat", "baz"})
+ expect(t, len(c.Args()), 2)
+ expect(t, c.Bool("myflag"), true)
+}
+
+func TestContext_NArg(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Bool("myflag", false, "doc")
+ c := NewContext(nil, set, nil)
+ set.Parse([]string{"--myflag", "bat", "baz"})
+ expect(t, c.NArg(), 2)
+}
+
+func TestContext_IsSet(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Bool("myflag", false, "doc")
+ set.String("otherflag", "hello world", "doc")
+ globalSet := flag.NewFlagSet("test", 0)
+ globalSet.Bool("myflagGlobal", true, "doc")
+ globalCtx := NewContext(nil, globalSet, nil)
+ c := NewContext(nil, set, globalCtx)
+ set.Parse([]string{"--myflag", "bat", "baz"})
+ globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
+ expect(t, c.IsSet("myflag"), true)
+ expect(t, c.IsSet("otherflag"), false)
+ expect(t, c.IsSet("bogusflag"), false)
+ expect(t, c.IsSet("myflagGlobal"), false)
+}
+
+func TestContext_GlobalIsSet(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Bool("myflag", false, "doc")
+ set.String("otherflag", "hello world", "doc")
+ globalSet := flag.NewFlagSet("test", 0)
+ globalSet.Bool("myflagGlobal", true, "doc")
+ globalSet.Bool("myflagGlobalUnset", true, "doc")
+ globalCtx := NewContext(nil, globalSet, nil)
+ c := NewContext(nil, set, globalCtx)
+ set.Parse([]string{"--myflag", "bat", "baz"})
+ globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
+ expect(t, c.GlobalIsSet("myflag"), false)
+ expect(t, c.GlobalIsSet("otherflag"), false)
+ expect(t, c.GlobalIsSet("bogusflag"), false)
+ expect(t, c.GlobalIsSet("myflagGlobal"), true)
+ expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
+ expect(t, c.GlobalIsSet("bogusGlobal"), false)
+}
+
+func TestContext_NumFlags(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Bool("myflag", false, "doc")
+ set.String("otherflag", "hello world", "doc")
+ globalSet := flag.NewFlagSet("test", 0)
+ globalSet.Bool("myflagGlobal", true, "doc")
+ globalCtx := NewContext(nil, globalSet, nil)
+ c := NewContext(nil, set, globalCtx)
+ set.Parse([]string{"--myflag", "--otherflag=foo"})
+ globalSet.Parse([]string{"--myflagGlobal"})
+ expect(t, c.NumFlags(), 2)
+}
+
+func TestContext_GlobalFlag(t *testing.T) {
+ var globalFlag string
+ var globalFlagSet bool
+ app := NewApp()
+ app.Flags = []Flag{
+ StringFlag{Name: "global, g", Usage: "global"},
+ }
+ app.Action = func(c *Context) error {
+ globalFlag = c.GlobalString("global")
+ globalFlagSet = c.GlobalIsSet("global")
+ return nil
+ }
+ app.Run([]string{"command", "-g", "foo"})
+ expect(t, globalFlag, "foo")
+ expect(t, globalFlagSet, true)
+
+}
+
+func TestContext_GlobalFlagsInSubcommands(t *testing.T) {
+ subcommandRun := false
+ parentFlag := false
+ app := NewApp()
+
+ app.Flags = []Flag{
+ BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
+ }
+
+ app.Commands = []Command{
+ {
+ Name: "foo",
+ Flags: []Flag{
+ BoolFlag{Name: "parent, p", Usage: "Parent flag"},
+ },
+ Subcommands: []Command{
+ {
+ Name: "bar",
+ Action: func(c *Context) error {
+ if c.GlobalBool("debug") {
+ subcommandRun = true
+ }
+ if c.GlobalBool("parent") {
+ parentFlag = true
+ }
+ return nil
+ },
+ },
+ },
+ },
+ }
+
+ app.Run([]string{"command", "-d", "foo", "-p", "bar"})
+
+ expect(t, subcommandRun, true)
+ expect(t, parentFlag, true)
+}
+
+func TestContext_Set(t *testing.T) {
+ set := flag.NewFlagSet("test", 0)
+ set.Int("int", 5, "an int")
+ c := NewContext(nil, set, nil)
+
+ c.Set("int", "1")
+ expect(t, c.Int("int"), 1)
+}
+
+func TestContext_GlobalSet(t *testing.T) {
+ gSet := flag.NewFlagSet("test", 0)
+ gSet.Int("int", 5, "an int")
+
+ set := flag.NewFlagSet("sub", 0)
+ set.Int("int", 3, "an int")
+
+ pc := NewContext(nil, gSet, nil)
+ c := NewContext(nil, set, pc)
+
+ c.Set("int", "1")
+ expect(t, c.Int("int"), 1)
+ expect(t, c.GlobalInt("int"), 5)
+
+ c.GlobalSet("int", "1")
+ expect(t, c.Int("int"), 1)
+ expect(t, c.GlobalInt("int"), 1)
+}
diff --git a/vendor/github.com/codegangsta/cli/errors.go b/vendor/github.com/codegangsta/cli/errors.go
new file mode 100644
index 0000000..ea551be
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/errors.go
@@ -0,0 +1,92 @@
+package cli
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+)
+
+// OsExiter is the function used when the app exits. If not set defaults to os.Exit.
+var OsExiter = os.Exit
+
+// ErrWriter is used to write errors to the user. This can be anything
+// implementing the io.Writer interface and defaults to os.Stderr.
+var ErrWriter io.Writer = os.Stderr
+
+// MultiError is an error that wraps multiple errors.
+type MultiError struct {
+ Errors []error
+}
+
+// NewMultiError creates a new MultiError. Pass in one or more errors.
+func NewMultiError(err ...error) MultiError {
+ return MultiError{Errors: err}
+}
+
+// Error implents the error interface.
+func (m MultiError) Error() string {
+ errs := make([]string, len(m.Errors))
+ for i, err := range m.Errors {
+ errs[i] = err.Error()
+ }
+
+ return strings.Join(errs, "\n")
+}
+
+// ExitCoder is the interface checked by `App` and `Command` for a custom exit
+// code
+type ExitCoder interface {
+ error
+ ExitCode() int
+}
+
+// ExitError fulfills both the builtin `error` interface and `ExitCoder`
+type ExitError struct {
+ exitCode int
+ message string
+}
+
+// NewExitError makes a new *ExitError
+func NewExitError(message string, exitCode int) *ExitError {
+ return &ExitError{
+ exitCode: exitCode,
+ message: message,
+ }
+}
+
+// Error returns the string message, fulfilling the interface required by
+// `error`
+func (ee *ExitError) Error() string {
+ return ee.message
+}
+
+// ExitCode returns the exit code, fulfilling the interface required by
+// `ExitCoder`
+func (ee *ExitError) ExitCode() int {
+ return ee.exitCode
+}
+
+// HandleExitCoder checks if the error fulfills the ExitCoder interface, and if
+// so prints the error to stderr (if it is non-empty) and calls OsExiter with the
+// given exit code. If the given error is a MultiError, then this func is
+// called on all members of the Errors slice.
+func HandleExitCoder(err error) {
+ if err == nil {
+ return
+ }
+
+ if exitErr, ok := err.(ExitCoder); ok {
+ if err.Error() != "" {
+ fmt.Fprintln(ErrWriter, err)
+ }
+ OsExiter(exitErr.ExitCode())
+ return
+ }
+
+ if multiErr, ok := err.(MultiError); ok {
+ for _, merr := range multiErr.Errors {
+ HandleExitCoder(merr)
+ }
+ }
+}
diff --git a/vendor/github.com/codegangsta/cli/errors_test.go b/vendor/github.com/codegangsta/cli/errors_test.go
new file mode 100644
index 0000000..8f5f284
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/errors_test.go
@@ -0,0 +1,60 @@
+package cli
+
+import (
+ "errors"
+ "os"
+ "testing"
+)
+
+func TestHandleExitCoder_nil(t *testing.T) {
+ exitCode := 0
+ called := false
+
+ OsExiter = func(rc int) {
+ exitCode = rc
+ called = true
+ }
+
+ defer func() { OsExiter = os.Exit }()
+
+ HandleExitCoder(nil)
+
+ expect(t, exitCode, 0)
+ expect(t, called, false)
+}
+
+func TestHandleExitCoder_ExitCoder(t *testing.T) {
+ exitCode := 0
+ called := false
+
+ OsExiter = func(rc int) {
+ exitCode = rc
+ called = true
+ }
+
+ defer func() { OsExiter = os.Exit }()
+
+ HandleExitCoder(NewExitError("galactic perimeter breach", 9))
+
+ expect(t, exitCode, 9)
+ expect(t, called, true)
+}
+
+func TestHandleExitCoder_MultiErrorWithExitCoder(t *testing.T) {
+ exitCode := 0
+ called := false
+
+ OsExiter = func(rc int) {
+ exitCode = rc
+ called = true
+ }
+
+ defer func() { OsExiter = os.Exit }()
+
+ exitErr := NewExitError("galactic perimeter breach", 9)
+ err := NewMultiError(errors.New("wowsa"), errors.New("egad"), exitErr)
+ HandleExitCoder(err)
+
+ expect(t, exitCode, 9)
+ expect(t, called, true)
+}
diff --git a/vendor/github.com/codegangsta/cli/flag.go b/vendor/github.com/codegangsta/cli/flag.go
new file mode 100644
index 0000000..f8a28d1
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/flag.go
@@ -0,0 +1,882 @@
+package cli
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "reflect"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+)
+
+const defaultPlaceholder = "value"
+
+// BashCompletionFlag enables bash-completion for all commands and subcommands
+var BashCompletionFlag = BoolFlag{
+ Name: "generate-bash-completion",
+ Hidden: true,
+}
+
+// VersionFlag prints the version for the application
+var VersionFlag = BoolFlag{
+ Name: "version, v",
+ Usage: "print the version",
+}
+
+// HelpFlag prints the help for all commands and subcommands
+// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
+// unless HideHelp is set to true)
+var HelpFlag = BoolFlag{
+ Name: "help, h",
+ Usage: "show help",
+}
+
+// FlagStringer converts a flag definition to a string. This is used by help
+// to display a flag.
+var FlagStringer FlagStringFunc = stringifyFlag
+
+// Flag is a common interface related to parsing flags in cli.
+// For more advanced flag parsing techniques, it is recommended that
+// this interface be implemented.
+type Flag interface {
+ fmt.Stringer
+ // Apply Flag settings to the given flag set
+ Apply(*flag.FlagSet)
+ GetName() string
+}
+
+func flagSet(name string, flags []Flag) *flag.FlagSet {
+ set := flag.NewFlagSet(name, flag.ContinueOnError)
+
+ for _, f := range flags {
+ f.Apply(set)
+ }
+ return set
+}
+
+func eachName(longName string, fn func(string)) {
+ parts := strings.Split(longName, ",")
+ for _, name := range parts {
+ name = strings.Trim(name, " ")
+ fn(name)
+ }
+}
+
+// Generic is a generic parseable type identified by a specific flag
+type Generic interface {
+ Set(value string) error
+ String() string
+}
+
+// GenericFlag is the flag type for types implementing Generic
+type GenericFlag struct {
+ Name string
+ Value Generic
+ Usage string
+ EnvVar string
+ Hidden bool
+}
+
+// String returns the string representation of the generic flag to display the
+// help text to the user (uses the String() method of the generic flag to show
+// the value)
+func (f GenericFlag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply takes the flagset and calls Set on the generic flag with the value
+// provided by the user for parsing by the flag
+func (f GenericFlag) Apply(set *flag.FlagSet) {
+ val := f.Value
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ val.Set(envVal)
+ break
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ set.Var(f.Value, name, f.Usage)
+ })
+}
+
+// GetName returns the name of a flag.
+func (f GenericFlag) GetName() string {
+ return f.Name
+}
+
+// StringSlice is an opaque type for []string to satisfy flag.Value
+type StringSlice []string
+
+// Set appends the string value to the list of values
+func (f *StringSlice) Set(value string) error {
+ *f = append(*f, value)
+ return nil
+}
+
+// String returns a readable representation of this value (for usage defaults)
+func (f *StringSlice) String() string {
+ return fmt.Sprintf("%s", *f)
+}
+
+// Value returns the slice of strings set by this flag
+func (f *StringSlice) Value() []string {
+ return *f
+}
+
+// StringSliceFlag is a string flag that can be specified multiple times on the
+// command-line
+type StringSliceFlag struct {
+ Name string
+ Value *StringSlice
+ Usage string
+ EnvVar string
+ Hidden bool
+}
+
+// String returns the usage
+func (f StringSliceFlag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f StringSliceFlag) Apply(set *flag.FlagSet) {
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ newVal := &StringSlice{}
+ for _, s := range strings.Split(envVal, ",") {
+ s = strings.TrimSpace(s)
+ newVal.Set(s)
+ }
+ f.Value = newVal
+ break
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Value == nil {
+ f.Value = &StringSlice{}
+ }
+ set.Var(f.Value, name, f.Usage)
+ })
+}
+
+// GetName returns the name of a flag.
+func (f StringSliceFlag) GetName() string {
+ return f.Name
+}
+
+// IntSlice is an opaque type for []int to satisfy flag.Value
+type IntSlice []int
+
+// Set parses the value into an integer and appends it to the list of values
+func (f *IntSlice) Set(value string) error {
+ tmp, err := strconv.Atoi(value)
+ if err != nil {
+ return err
+ }
+ *f = append(*f, tmp)
+ return nil
+}
+
+// String returns a readable representation of this value (for usage defaults)
+func (f *IntSlice) String() string {
+ return fmt.Sprintf("%#v", *f)
+}
+
+// Value returns the slice of ints set by this flag
+func (f *IntSlice) Value() []int {
+ return *f
+}
+
+// IntSliceFlag is an int flag that can be specified multiple times on the
+// command-line
+type IntSliceFlag struct {
+ Name string
+ Value *IntSlice
+ Usage string
+ EnvVar string
+ Hidden bool
+}
+
+// String returns the usage
+func (f IntSliceFlag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f IntSliceFlag) Apply(set *flag.FlagSet) {
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ newVal := &IntSlice{}
+ for _, s := range strings.Split(envVal, ",") {
+ s = strings.TrimSpace(s)
+ err := newVal.Set(s)
+ if err != nil {
+ fmt.Fprintf(ErrWriter, err.Error())
+ }
+ }
+ f.Value = newVal
+ break
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Value == nil {
+ f.Value = &IntSlice{}
+ }
+ set.Var(f.Value, name, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f IntSliceFlag) GetName() string {
+ return f.Name
+}
+
+// Int64Slice is an opaque type for []int to satisfy flag.Value
+type Int64Slice []int64
+
+// Set parses the value into an integer and appends it to the list of values
+func (f *Int64Slice) Set(value string) error {
+ tmp, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ *f = append(*f, tmp)
+ return nil
+}
+
+// String returns a readable representation of this value (for usage defaults)
+func (f *Int64Slice) String() string {
+ return fmt.Sprintf("%#v", *f)
+}
+
+// Value returns the slice of ints set by this flag
+func (f *Int64Slice) Value() []int64 {
+ return *f
+}
+
+// Int64SliceFlag is an int flag that can be specified multiple times on the
+// command-line
+type Int64SliceFlag struct {
+ Name string
+ Value *Int64Slice
+ Usage string
+ EnvVar string
+ Hidden bool
+}
+
+// String returns the usage
+func (f Int64SliceFlag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f Int64SliceFlag) Apply(set *flag.FlagSet) {
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ newVal := &Int64Slice{}
+ for _, s := range strings.Split(envVal, ",") {
+ s = strings.TrimSpace(s)
+ err := newVal.Set(s)
+ if err != nil {
+ fmt.Fprintf(ErrWriter, err.Error())
+ }
+ }
+ f.Value = newVal
+ break
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Value == nil {
+ f.Value = &Int64Slice{}
+ }
+ set.Var(f.Value, name, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f Int64SliceFlag) GetName() string {
+ return f.Name
+}
+
+// BoolFlag is a switch that defaults to false
+type BoolFlag struct {
+ Name string
+ Usage string
+ EnvVar string
+ Destination *bool
+ Hidden bool
+}
+
+// String returns a readable representation of this value (for usage defaults)
+func (f BoolFlag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f BoolFlag) Apply(set *flag.FlagSet) {
+ val := false
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ envValBool, err := strconv.ParseBool(envVal)
+ if err == nil {
+ val = envValBool
+ }
+ break
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.BoolVar(f.Destination, name, val, f.Usage)
+ return
+ }
+ set.Bool(name, val, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f BoolFlag) GetName() string {
+ return f.Name
+}
+
+// BoolTFlag this represents a boolean flag that is true by default, but can
+// still be set to false by --some-flag=false
+type BoolTFlag struct {
+ Name string
+ Usage string
+ EnvVar string
+ Destination *bool
+ Hidden bool
+}
+
+// String returns a readable representation of this value (for usage defaults)
+func (f BoolTFlag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f BoolTFlag) Apply(set *flag.FlagSet) {
+ val := true
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ envValBool, err := strconv.ParseBool(envVal)
+ if err == nil {
+ val = envValBool
+ break
+ }
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.BoolVar(f.Destination, name, val, f.Usage)
+ return
+ }
+ set.Bool(name, val, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f BoolTFlag) GetName() string {
+ return f.Name
+}
+
+// StringFlag represents a flag that takes as string value
+type StringFlag struct {
+ Name string
+ Value string
+ Usage string
+ EnvVar string
+ Destination *string
+ Hidden bool
+}
+
+// String returns the usage
+func (f StringFlag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f StringFlag) Apply(set *flag.FlagSet) {
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ f.Value = envVal
+ break
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.StringVar(f.Destination, name, f.Value, f.Usage)
+ return
+ }
+ set.String(name, f.Value, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f StringFlag) GetName() string {
+ return f.Name
+}
+
+// IntFlag is a flag that takes an integer
+type IntFlag struct {
+ Name string
+ Value int
+ Usage string
+ EnvVar string
+ Destination *int
+ Hidden bool
+}
+
+// String returns the usage
+func (f IntFlag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f IntFlag) Apply(set *flag.FlagSet) {
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ envValInt, err := strconv.ParseInt(envVal, 0, 64)
+ if err == nil {
+ f.Value = int(envValInt)
+ break
+ }
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.IntVar(f.Destination, name, f.Value, f.Usage)
+ return
+ }
+ set.Int(name, f.Value, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f IntFlag) GetName() string {
+ return f.Name
+}
+
+// Int64Flag is a flag that takes a 64-bit integer
+type Int64Flag struct {
+ Name string
+ Value int64
+ Usage string
+ EnvVar string
+ Destination *int64
+ Hidden bool
+}
+
+// String returns the usage
+func (f Int64Flag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f Int64Flag) Apply(set *flag.FlagSet) {
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ envValInt, err := strconv.ParseInt(envVal, 0, 64)
+ if err == nil {
+ f.Value = envValInt
+ break
+ }
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.Int64Var(f.Destination, name, f.Value, f.Usage)
+ return
+ }
+ set.Int64(name, f.Value, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f Int64Flag) GetName() string {
+ return f.Name
+}
+
+// UintFlag is a flag that takes an unsigned integer
+type UintFlag struct {
+ Name string
+ Value uint
+ Usage string
+ EnvVar string
+ Destination *uint
+ Hidden bool
+}
+
+// String returns the usage
+func (f UintFlag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f UintFlag) Apply(set *flag.FlagSet) {
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ envValInt, err := strconv.ParseUint(envVal, 0, 64)
+ if err == nil {
+ f.Value = uint(envValInt)
+ break
+ }
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.UintVar(f.Destination, name, f.Value, f.Usage)
+ return
+ }
+ set.Uint(name, f.Value, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f UintFlag) GetName() string {
+ return f.Name
+}
+
+// Uint64Flag is a flag that takes an unsigned 64-bit integer
+type Uint64Flag struct {
+ Name string
+ Value uint64
+ Usage string
+ EnvVar string
+ Destination *uint64
+ Hidden bool
+}
+
+// String returns the usage
+func (f Uint64Flag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f Uint64Flag) Apply(set *flag.FlagSet) {
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ envValInt, err := strconv.ParseUint(envVal, 0, 64)
+ if err == nil {
+ f.Value = uint64(envValInt)
+ break
+ }
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.Uint64Var(f.Destination, name, f.Value, f.Usage)
+ return
+ }
+ set.Uint64(name, f.Value, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f Uint64Flag) GetName() string {
+ return f.Name
+}
+
+// DurationFlag is a flag that takes a duration specified in Go's duration
+// format: https://golang.org/pkg/time/#ParseDuration
+type DurationFlag struct {
+ Name string
+ Value time.Duration
+ Usage string
+ EnvVar string
+ Destination *time.Duration
+ Hidden bool
+}
+
+// String returns a readable representation of this value (for usage defaults)
+func (f DurationFlag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f DurationFlag) Apply(set *flag.FlagSet) {
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ envValDuration, err := time.ParseDuration(envVal)
+ if err == nil {
+ f.Value = envValDuration
+ break
+ }
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.DurationVar(f.Destination, name, f.Value, f.Usage)
+ return
+ }
+ set.Duration(name, f.Value, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f DurationFlag) GetName() string {
+ return f.Name
+}
+
+// Float64Flag is a flag that takes an float value
+type Float64Flag struct {
+ Name string
+ Value float64
+ Usage string
+ EnvVar string
+ Destination *float64
+ Hidden bool
+}
+
+// String returns the usage
+func (f Float64Flag) String() string {
+ return FlagStringer(f)
+}
+
+// Apply populates the flag given the flag set and environment
+func (f Float64Flag) Apply(set *flag.FlagSet) {
+ if f.EnvVar != "" {
+ for _, envVar := range strings.Split(f.EnvVar, ",") {
+ envVar = strings.TrimSpace(envVar)
+ if envVal := os.Getenv(envVar); envVal != "" {
+ envValFloat, err := strconv.ParseFloat(envVal, 10)
+ if err == nil {
+ f.Value = float64(envValFloat)
+ }
+ }
+ }
+ }
+
+ eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.Float64Var(f.Destination, name, f.Value, f.Usage)
+ return
+ }
+ set.Float64(name, f.Value, f.Usage)
+ })
+}
+
+// GetName returns the name of the flag.
+func (f Float64Flag) GetName() string {
+ return f.Name
+}
+
+func visibleFlags(fl []Flag) []Flag {
+ visible := []Flag{}
+ for _, flag := range fl {
+ if !flagValue(flag).FieldByName("Hidden").Bool() {
+ visible = append(visible, flag)
+ }
+ }
+ return visible
+}
+
+func prefixFor(name string) (prefix string) {
+ if len(name) == 1 {
+ prefix = "-"
+ } else {
+ prefix = "--"
+ }
+
+ return
+}
+
+// Returns the placeholder, if any, and the unquoted usage string.
+func unquoteUsage(usage string) (string, string) {
+ for i := 0; i < len(usage); i++ {
+ if usage[i] == '`' {
+ for j := i + 1; j < len(usage); j++ {
+ if usage[j] == '`' {
+ name := usage[i+1 : j]
+ usage = usage[:i] + name + usage[j+1:]
+ return name, usage
+ }
+ }
+ break
+ }
+ }
+ return "", usage
+}
+
+func prefixedNames(fullName, placeholder string) string {
+ var prefixed string
+ parts := strings.Split(fullName, ",")
+ for i, name := range parts {
+ name = strings.Trim(name, " ")
+ prefixed += prefixFor(name) + name
+ if placeholder != "" {
+ prefixed += " " + placeholder
+ }
+ if i < len(parts)-1 {
+ prefixed += ", "
+ }
+ }
+ return prefixed
+}
+
+func withEnvHint(envVar, str string) string {
+ envText := ""
+ if envVar != "" {
+ prefix := "$"
+ suffix := ""
+ sep := ", $"
+ if runtime.GOOS == "windows" {
+ prefix = "%"
+ suffix = "%"
+ sep = "%, %"
+ }
+ envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix)
+ }
+ return str + envText
+}
+
+func flagValue(f Flag) reflect.Value {
+ fv := reflect.ValueOf(f)
+ for fv.Kind() == reflect.Ptr {
+ fv = reflect.Indirect(fv)
+ }
+ return fv
+}
+
+func stringifyFlag(f Flag) string {
+ fv := flagValue(f)
+
+ switch f.(type) {
+ case IntSliceFlag:
+ return withEnvHint(fv.FieldByName("EnvVar").String(),
+ stringifyIntSliceFlag(f.(IntSliceFlag)))
+ case Int64SliceFlag:
+ return withEnvHint(fv.FieldByName("EnvVar").String(),
+ stringifyInt64SliceFlag(f.(Int64SliceFlag)))
+ case StringSliceFlag:
+ return withEnvHint(fv.FieldByName("EnvVar").String(),
+ stringifyStringSliceFlag(f.(StringSliceFlag)))
+ }
+
+ placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
+
+ needsPlaceholder := false
+ defaultValueString := ""
+ val := fv.FieldByName("Value")
+
+ if val.IsValid() {
+ needsPlaceholder = true
+ defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface())
+
+ if val.Kind() == reflect.String && val.String() != "" {
+ defaultValueString = fmt.Sprintf(" (default: %q)", val.String())
+ }
+ }
+
+ if defaultValueString == " (default: )" {
+ defaultValueString = ""
+ }
+
+ if needsPlaceholder && placeholder == "" {
+ placeholder = defaultPlaceholder
+ }
+
+ usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString))
+
+ return withEnvHint(fv.FieldByName("EnvVar").String(),
+ fmt.Sprintf("%s\t%s", prefixedNames(fv.FieldByName("Name").String(), placeholder), usageWithDefault))
+}
+
+func stringifyIntSliceFlag(f IntSliceFlag) string {
+ defaultVals := []string{}
+ if f.Value != nil && len(f.Value.Value()) > 0 {
+ for _, i := range f.Value.Value() {
+ defaultVals = append(defaultVals, fmt.Sprintf("%d", i))
+ }
+ }
+
+ return stringifySliceFlag(f.Usage, f.Name, defaultVals)
+}
+
+func stringifyInt64SliceFlag(f Int64SliceFlag) string {
+ defaultVals := []string{}
+ if f.Value != nil && len(f.Value.Value()) > 0 {
+ for _, i := range f.Value.Value() {
+ defaultVals = append(defaultVals, fmt.Sprintf("%d", i))
+ }
+ }
+
+ return stringifySliceFlag(f.Usage, f.Name, defaultVals)
+}
+
+func stringifyStringSliceFlag(f StringSliceFlag) string {
+ defaultVals := []string{}
+ if f.Value != nil && len(f.Value.Value()) > 0 {
+ for _, s := range f.Value.Value() {
+ if len(s) > 0 {
+ defaultVals = append(defaultVals, fmt.Sprintf("%q", s))
+ }
+ }
+ }
+
+ return stringifySliceFlag(f.Usage, f.Name, defaultVals)
+}
+
+func stringifySliceFlag(usage, name string, defaultVals []string) string {
+ placeholder, usage := unquoteUsage(usage)
+ if placeholder == "" {
+ placeholder = defaultPlaceholder
+ }
+
+ defaultVal := ""
+ if len(defaultVals) > 0 {
+ defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", "))
+ }
+
+ usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
+ return fmt.Sprintf("%s\t%s", prefixedNames(name, placeholder), usageWithDefault)
+}
diff --git a/vendor/github.com/codegangsta/cli/flag_test.go b/vendor/github.com/codegangsta/cli/flag_test.go
new file mode 100644
index 0000000..a7afcc4
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/flag_test.go
@@ -0,0 +1,1092 @@
+package cli
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+)
+
+var boolFlagTests = []struct {
+ name string
+ expected string
+}{
+ {"help", "--help\t"},
+ {"h", "-h\t"},
+}
+
+func TestBoolFlagHelpOutput(t *testing.T) {
+ for _, test := range boolFlagTests {
+ flag := BoolFlag{Name: test.name}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%q does not match %q", output, test.expected)
+ }
+ }
+}
+
+var stringFlagTests = []struct {
+ name string
+ usage string
+ value string
+ expected string
+}{
+ {"foo", "", "", "--foo value\t"},
+ {"f", "", "", "-f value\t"},
+ {"f", "The total `foo` desired", "all", "-f foo\tThe total foo desired (default: \"all\")"},
+ {"test", "", "Something", "--test value\t(default: \"Something\")"},
+ {"config,c", "Load configuration from `FILE`", "", "--config FILE, -c FILE\tLoad configuration from FILE"},
+ {"config,c", "Load configuration from `CONFIG`", "config.json", "--config CONFIG, -c CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"},
+}
+
+func TestStringFlagHelpOutput(t *testing.T) {
+ for _, test := range stringFlagTests {
+ flag := StringFlag{Name: test.name, Usage: test.usage, Value: test.value}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%q does not match %q", output, test.expected)
+ }
+ }
+}
+
+func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_FOO", "derp")
+ for _, test := range stringFlagTests {
+ flag := StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_FOO]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_FOO%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%s does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+var stringSliceFlagTests = []struct {
+ name string
+ value *StringSlice
+ expected string
+}{
+ {"foo", func() *StringSlice {
+ s := &StringSlice{}
+ s.Set("")
+ return s
+ }(), "--foo value\t"},
+ {"f", func() *StringSlice {
+ s := &StringSlice{}
+ s.Set("")
+ return s
+ }(), "-f value\t"},
+ {"f", func() *StringSlice {
+ s := &StringSlice{}
+ s.Set("Lipstick")
+ return s
+ }(), "-f value\t(default: \"Lipstick\")"},
+ {"test", func() *StringSlice {
+ s := &StringSlice{}
+ s.Set("Something")
+ return s
+ }(), "--test value\t(default: \"Something\")"},
+}
+
+func TestStringSliceFlagHelpOutput(t *testing.T) {
+ for _, test := range stringSliceFlagTests {
+ flag := StringSliceFlag{Name: test.name, Value: test.value}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%q does not match %q", output, test.expected)
+ }
+ }
+}
+
+func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_QWWX", "11,4")
+ for _, test := range stringSliceFlagTests {
+ flag := StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_QWWX]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_QWWX%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%q does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+var intFlagTests = []struct {
+ name string
+ expected string
+}{
+ {"hats", "--hats value\t(default: 9)"},
+ {"H", "-H value\t(default: 9)"},
+}
+
+func TestIntFlagHelpOutput(t *testing.T) {
+ for _, test := range intFlagTests {
+ flag := IntFlag{Name: test.name, Value: 9}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%s does not match %s", output, test.expected)
+ }
+ }
+}
+
+func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_BAR", "2")
+ for _, test := range intFlagTests {
+ flag := IntFlag{Name: test.name, EnvVar: "APP_BAR"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_BAR]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_BAR%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%s does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+var int64FlagTests = []struct {
+ name string
+ expected string
+}{
+ {"hats", "--hats value\t(default: 8589934592)"},
+ {"H", "-H value\t(default: 8589934592)"},
+}
+
+func TestInt64FlagHelpOutput(t *testing.T) {
+ for _, test := range int64FlagTests {
+ flag := Int64Flag{Name: test.name, Value: 8589934592}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%s does not match %s", output, test.expected)
+ }
+ }
+}
+
+func TestInt64FlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_BAR", "2")
+ for _, test := range int64FlagTests {
+ flag := IntFlag{Name: test.name, EnvVar: "APP_BAR"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_BAR]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_BAR%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%s does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+var uintFlagTests = []struct {
+ name string
+ expected string
+}{
+ {"nerfs", "--nerfs value\t(default: 41)"},
+ {"N", "-N value\t(default: 41)"},
+}
+
+func TestUintFlagHelpOutput(t *testing.T) {
+ for _, test := range uintFlagTests {
+ flag := UintFlag{Name: test.name, Value: 41}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%s does not match %s", output, test.expected)
+ }
+ }
+}
+
+func TestUintFlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_BAR", "2")
+ for _, test := range uintFlagTests {
+ flag := UintFlag{Name: test.name, EnvVar: "APP_BAR"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_BAR]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_BAR%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%s does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+var uint64FlagTests = []struct {
+ name string
+ expected string
+}{
+ {"gerfs", "--gerfs value\t(default: 8589934582)"},
+ {"G", "-G value\t(default: 8589934582)"},
+}
+
+func TestUint64FlagHelpOutput(t *testing.T) {
+ for _, test := range uint64FlagTests {
+ flag := Uint64Flag{Name: test.name, Value: 8589934582}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%s does not match %s", output, test.expected)
+ }
+ }
+}
+
+func TestUint64FlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_BAR", "2")
+ for _, test := range uint64FlagTests {
+ flag := UintFlag{Name: test.name, EnvVar: "APP_BAR"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_BAR]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_BAR%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%s does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+var durationFlagTests = []struct {
+ name string
+ expected string
+}{
+ {"hooting", "--hooting value\t(default: 1s)"},
+ {"H", "-H value\t(default: 1s)"},
+}
+
+func TestDurationFlagHelpOutput(t *testing.T) {
+ for _, test := range durationFlagTests {
+ flag := DurationFlag{Name: test.name, Value: 1 * time.Second}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%q does not match %q", output, test.expected)
+ }
+ }
+}
+
+func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_BAR", "2h3m6s")
+ for _, test := range durationFlagTests {
+ flag := DurationFlag{Name: test.name, EnvVar: "APP_BAR"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_BAR]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_BAR%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%s does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+var intSliceFlagTests = []struct {
+ name string
+ value *IntSlice
+ expected string
+}{
+ {"heads", &IntSlice{}, "--heads value\t"},
+ {"H", &IntSlice{}, "-H value\t"},
+ {"H, heads", func() *IntSlice {
+ i := &IntSlice{}
+ i.Set("9")
+ i.Set("3")
+ return i
+ }(), "-H value, --heads value\t(default: 9, 3)"},
+}
+
+func TestIntSliceFlagHelpOutput(t *testing.T) {
+ for _, test := range intSliceFlagTests {
+ flag := IntSliceFlag{Name: test.name, Value: test.value}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%q does not match %q", output, test.expected)
+ }
+ }
+}
+
+func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_SMURF", "42,3")
+ for _, test := range intSliceFlagTests {
+ flag := IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_SMURF]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_SMURF%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%q does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+var int64SliceFlagTests = []struct {
+ name string
+ value *Int64Slice
+ expected string
+}{
+ {"heads", &Int64Slice{}, "--heads value\t"},
+ {"H", &Int64Slice{}, "-H value\t"},
+ {"H, heads", func() *Int64Slice {
+ i := &Int64Slice{}
+ i.Set("2")
+ i.Set("17179869184")
+ return i
+ }(), "-H value, --heads value\t(default: 2, 17179869184)"},
+}
+
+func TestInt64SliceFlagHelpOutput(t *testing.T) {
+ for _, test := range int64SliceFlagTests {
+ flag := Int64SliceFlag{Name: test.name, Value: test.value}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%q does not match %q", output, test.expected)
+ }
+ }
+}
+
+func TestInt64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_SMURF", "42,17179869184")
+ for _, test := range int64SliceFlagTests {
+ flag := Int64SliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_SMURF]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_SMURF%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%q does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+var float64FlagTests = []struct {
+ name string
+ expected string
+}{
+ {"hooting", "--hooting value\t(default: 0.1)"},
+ {"H", "-H value\t(default: 0.1)"},
+}
+
+func TestFloat64FlagHelpOutput(t *testing.T) {
+ for _, test := range float64FlagTests {
+ flag := Float64Flag{Name: test.name, Value: float64(0.1)}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%q does not match %q", output, test.expected)
+ }
+ }
+}
+
+func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_BAZ", "99.4")
+ for _, test := range float64FlagTests {
+ flag := Float64Flag{Name: test.name, EnvVar: "APP_BAZ"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_BAZ]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_BAZ%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%s does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+var genericFlagTests = []struct {
+ name string
+ value Generic
+ expected string
+}{
+ {"toads", &Parser{"abc", "def"}, "--toads value\ttest flag (default: abc,def)"},
+ {"t", &Parser{"abc", "def"}, "-t value\ttest flag (default: abc,def)"},
+}
+
+func TestGenericFlagHelpOutput(t *testing.T) {
+ for _, test := range genericFlagTests {
+ flag := GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
+ output := flag.String()
+
+ if output != test.expected {
+ t.Errorf("%q does not match %q", output, test.expected)
+ }
+ }
+}
+
+func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_ZAP", "3")
+ for _, test := range genericFlagTests {
+ flag := GenericFlag{Name: test.name, EnvVar: "APP_ZAP"}
+ output := flag.String()
+
+ expectedSuffix := " [$APP_ZAP]"
+ if runtime.GOOS == "windows" {
+ expectedSuffix = " [%APP_ZAP%]"
+ }
+ if !strings.HasSuffix(output, expectedSuffix) {
+ t.Errorf("%s does not end with"+expectedSuffix, output)
+ }
+ }
+}
+
+func TestParseMultiString(t *testing.T) {
+ (&App{
+ Flags: []Flag{
+ StringFlag{Name: "serve, s"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.String("serve") != "10" {
+ t.Errorf("main name not set")
+ }
+ if ctx.String("s") != "10" {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }).Run([]string{"run", "-s", "10"})
+}
+
+func TestParseDestinationString(t *testing.T) {
+ var dest string
+ a := App{
+ Flags: []Flag{
+ StringFlag{
+ Name: "dest",
+ Destination: &dest,
+ },
+ },
+ Action: func(ctx *Context) error {
+ if dest != "10" {
+ t.Errorf("expected destination String 10")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run", "--dest", "10"})
+}
+
+func TestParseMultiStringFromEnv(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_COUNT", "20")
+ (&App{
+ Flags: []Flag{
+ StringFlag{Name: "count, c", EnvVar: "APP_COUNT"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.String("count") != "20" {
+ t.Errorf("main name not set")
+ }
+ if ctx.String("c") != "20" {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }).Run([]string{"run"})
+}
+
+func TestParseMultiStringFromEnvCascade(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_COUNT", "20")
+ (&App{
+ Flags: []Flag{
+ StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.String("count") != "20" {
+ t.Errorf("main name not set")
+ }
+ if ctx.String("c") != "20" {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }).Run([]string{"run"})
+}
+
+func TestParseMultiStringSlice(t *testing.T) {
+ (&App{
+ Flags: []Flag{
+ StringSliceFlag{Name: "serve, s", Value: &StringSlice{}},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) {
+ t.Errorf("main name not set")
+ }
+ if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }).Run([]string{"run", "-s", "10", "-s", "20"})
+}
+
+func TestParseMultiStringSliceFromEnv(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_INTERVALS", "20,30,40")
+
+ (&App{
+ Flags: []Flag{
+ StringSliceFlag{Name: "intervals, i", Value: &StringSlice{}, EnvVar: "APP_INTERVALS"},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
+ t.Errorf("main name not set from env")
+ }
+ if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }).Run([]string{"run"})
+}
+
+func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_INTERVALS", "20,30,40")
+
+ (&App{
+ Flags: []Flag{
+ StringSliceFlag{Name: "intervals, i", Value: &StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
+ t.Errorf("main name not set from env")
+ }
+ if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }).Run([]string{"run"})
+}
+
+func TestParseMultiInt(t *testing.T) {
+ a := App{
+ Flags: []Flag{
+ IntFlag{Name: "serve, s"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Int("serve") != 10 {
+ t.Errorf("main name not set")
+ }
+ if ctx.Int("s") != 10 {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run", "-s", "10"})
+}
+
+func TestParseDestinationInt(t *testing.T) {
+ var dest int
+ a := App{
+ Flags: []Flag{
+ IntFlag{
+ Name: "dest",
+ Destination: &dest,
+ },
+ },
+ Action: func(ctx *Context) error {
+ if dest != 10 {
+ t.Errorf("expected destination Int 10")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run", "--dest", "10"})
+}
+
+func TestParseMultiIntFromEnv(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_TIMEOUT_SECONDS", "10")
+ a := App{
+ Flags: []Flag{
+ IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Int("timeout") != 10 {
+ t.Errorf("main name not set")
+ }
+ if ctx.Int("t") != 10 {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run"})
+}
+
+func TestParseMultiIntFromEnvCascade(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_TIMEOUT_SECONDS", "10")
+ a := App{
+ Flags: []Flag{
+ IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Int("timeout") != 10 {
+ t.Errorf("main name not set")
+ }
+ if ctx.Int("t") != 10 {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run"})
+}
+
+func TestParseMultiIntSlice(t *testing.T) {
+ (&App{
+ Flags: []Flag{
+ IntSliceFlag{Name: "serve, s", Value: &IntSlice{}},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
+ t.Errorf("main name not set")
+ }
+ if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }).Run([]string{"run", "-s", "10", "-s", "20"})
+}
+
+func TestParseMultiIntSliceFromEnv(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_INTERVALS", "20,30,40")
+
+ (&App{
+ Flags: []Flag{
+ IntSliceFlag{Name: "intervals, i", Value: &IntSlice{}, EnvVar: "APP_INTERVALS"},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
+ t.Errorf("main name not set from env")
+ }
+ if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }).Run([]string{"run"})
+}
+
+func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_INTERVALS", "20,30,40")
+
+ (&App{
+ Flags: []Flag{
+ IntSliceFlag{Name: "intervals, i", Value: &IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
+ t.Errorf("main name not set from env")
+ }
+ if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }).Run([]string{"run"})
+}
+
+func TestParseMultiInt64Slice(t *testing.T) {
+ (&App{
+ Flags: []Flag{
+ Int64SliceFlag{Name: "serve, s", Value: &Int64Slice{}},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.Int64Slice("serve"), []int64{10, 17179869184}) {
+ t.Errorf("main name not set")
+ }
+ if !reflect.DeepEqual(ctx.Int64Slice("s"), []int64{10, 17179869184}) {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }).Run([]string{"run", "-s", "10", "-s", "17179869184"})
+}
+
+func TestParseMultiInt64SliceFromEnv(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_INTERVALS", "20,30,17179869184")
+
+ (&App{
+ Flags: []Flag{
+ Int64SliceFlag{Name: "intervals, i", Value: &Int64Slice{}, EnvVar: "APP_INTERVALS"},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.Int64Slice("intervals"), []int64{20, 30, 17179869184}) {
+ t.Errorf("main name not set from env")
+ }
+ if !reflect.DeepEqual(ctx.Int64Slice("i"), []int64{20, 30, 17179869184}) {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }).Run([]string{"run"})
+}
+
+func TestParseMultiInt64SliceFromEnvCascade(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_INTERVALS", "20,30,17179869184")
+
+ (&App{
+ Flags: []Flag{
+ Int64SliceFlag{Name: "intervals, i", Value: &Int64Slice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.Int64Slice("intervals"), []int64{20, 30, 17179869184}) {
+ t.Errorf("main name not set from env")
+ }
+ if !reflect.DeepEqual(ctx.Int64Slice("i"), []int64{20, 30, 17179869184}) {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }).Run([]string{"run"})
+}
+
+func TestParseMultiFloat64(t *testing.T) {
+ a := App{
+ Flags: []Flag{
+ Float64Flag{Name: "serve, s"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Float64("serve") != 10.2 {
+ t.Errorf("main name not set")
+ }
+ if ctx.Float64("s") != 10.2 {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run", "-s", "10.2"})
+}
+
+func TestParseDestinationFloat64(t *testing.T) {
+ var dest float64
+ a := App{
+ Flags: []Flag{
+ Float64Flag{
+ Name: "dest",
+ Destination: &dest,
+ },
+ },
+ Action: func(ctx *Context) error {
+ if dest != 10.2 {
+ t.Errorf("expected destination Float64 10.2")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run", "--dest", "10.2"})
+}
+
+func TestParseMultiFloat64FromEnv(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
+ a := App{
+ Flags: []Flag{
+ Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Float64("timeout") != 15.5 {
+ t.Errorf("main name not set")
+ }
+ if ctx.Float64("t") != 15.5 {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run"})
+}
+
+func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
+ a := App{
+ Flags: []Flag{
+ Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Float64("timeout") != 15.5 {
+ t.Errorf("main name not set")
+ }
+ if ctx.Float64("t") != 15.5 {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run"})
+}
+
+func TestParseMultiBool(t *testing.T) {
+ a := App{
+ Flags: []Flag{
+ BoolFlag{Name: "serve, s"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Bool("serve") != true {
+ t.Errorf("main name not set")
+ }
+ if ctx.Bool("s") != true {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run", "--serve"})
+}
+
+func TestParseDestinationBool(t *testing.T) {
+ var dest bool
+ a := App{
+ Flags: []Flag{
+ BoolFlag{
+ Name: "dest",
+ Destination: &dest,
+ },
+ },
+ Action: func(ctx *Context) error {
+ if dest != true {
+ t.Errorf("expected destination Bool true")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run", "--dest"})
+}
+
+func TestParseMultiBoolFromEnv(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_DEBUG", "1")
+ a := App{
+ Flags: []Flag{
+ BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Bool("debug") != true {
+ t.Errorf("main name not set from env")
+ }
+ if ctx.Bool("d") != true {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run"})
+}
+
+func TestParseMultiBoolFromEnvCascade(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_DEBUG", "1")
+ a := App{
+ Flags: []Flag{
+ BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Bool("debug") != true {
+ t.Errorf("main name not set from env")
+ }
+ if ctx.Bool("d") != true {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run"})
+}
+
+func TestParseMultiBoolT(t *testing.T) {
+ a := App{
+ Flags: []Flag{
+ BoolTFlag{Name: "serve, s"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.BoolT("serve") != true {
+ t.Errorf("main name not set")
+ }
+ if ctx.BoolT("s") != true {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run", "--serve"})
+}
+
+func TestParseDestinationBoolT(t *testing.T) {
+ var dest bool
+ a := App{
+ Flags: []Flag{
+ BoolTFlag{
+ Name: "dest",
+ Destination: &dest,
+ },
+ },
+ Action: func(ctx *Context) error {
+ if dest != true {
+ t.Errorf("expected destination BoolT true")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run", "--dest"})
+}
+
+func TestParseMultiBoolTFromEnv(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_DEBUG", "0")
+ a := App{
+ Flags: []Flag{
+ BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.BoolT("debug") != false {
+ t.Errorf("main name not set from env")
+ }
+ if ctx.BoolT("d") != false {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run"})
+}
+
+func TestParseMultiBoolTFromEnvCascade(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_DEBUG", "0")
+ a := App{
+ Flags: []Flag{
+ BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.BoolT("debug") != false {
+ t.Errorf("main name not set from env")
+ }
+ if ctx.BoolT("d") != false {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run"})
+}
+
+type Parser [2]string
+
+func (p *Parser) Set(value string) error {
+ parts := strings.Split(value, ",")
+ if len(parts) != 2 {
+ return fmt.Errorf("invalid format")
+ }
+
+ (*p)[0] = parts[0]
+ (*p)[1] = parts[1]
+
+ return nil
+}
+
+func (p *Parser) String() string {
+ return fmt.Sprintf("%s,%s", p[0], p[1])
+}
+
+func TestParseGeneric(t *testing.T) {
+ a := App{
+ Flags: []Flag{
+ GenericFlag{Name: "serve, s", Value: &Parser{}},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
+ t.Errorf("main name not set")
+ }
+ if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
+ t.Errorf("short name not set")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run", "-s", "10,20"})
+}
+
+func TestParseGenericFromEnv(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_SERVE", "20,30")
+ a := App{
+ Flags: []Flag{
+ GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
+ t.Errorf("main name not set from env")
+ }
+ if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
+ t.Errorf("short name not set from env")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run"})
+}
+
+func TestParseGenericFromEnvCascade(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("APP_FOO", "99,2000")
+ a := App{
+ Flags: []Flag{
+ GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"},
+ },
+ Action: func(ctx *Context) error {
+ if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
+ t.Errorf("value not set from env")
+ }
+ return nil
+ },
+ }
+ a.Run([]string{"run"})
+}
diff --git a/vendor/github.com/codegangsta/cli/funcs.go b/vendor/github.com/codegangsta/cli/funcs.go
new file mode 100644
index 0000000..cba5e6c
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/funcs.go
@@ -0,0 +1,28 @@
+package cli
+
+// BashCompleteFunc is an action to execute when the bash-completion flag is set
+type BashCompleteFunc func(*Context)
+
+// BeforeFunc is an action to execute before any subcommands are run, but after
+// the context is ready if a non-nil error is returned, no subcommands are run
+type BeforeFunc func(*Context) error
+
+// AfterFunc is an action to execute after any subcommands are run, but after the
+// subcommand has finished it is run even if Action() panics
+type AfterFunc func(*Context) error
+
+// ActionFunc is the action to execute when no subcommands are specified
+type ActionFunc func(*Context) error
+
+// CommandNotFoundFunc is executed if the proper command cannot be found
+type CommandNotFoundFunc func(*Context, string)
+
+// OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying
+// customized usage error messages. This function is able to replace the
+// original error messages. If this function is not set, the "Incorrect usage"
+// is displayed and the execution is interrupted.
+type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error
+
+// FlagStringFunc is used by the help generation to display a flag, which is
+// expected to be a single line.
+type FlagStringFunc func(Flag) string
diff --git a/vendor/github.com/codegangsta/cli/help.go b/vendor/github.com/codegangsta/cli/help.go
new file mode 100644
index 0000000..0f4cf14
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/help.go
@@ -0,0 +1,267 @@
+package cli
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "text/tabwriter"
+ "text/template"
+)
+
+// AppHelpTemplate is the text template for the Default help topic.
+// cli.go uses text/template to render templates. You can
+// render custom help text by setting this variable.
+var AppHelpTemplate = `NAME:
+ {{.Name}} - {{.Usage}}
+
+USAGE:
+ {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
+ {{if .Version}}{{if not .HideVersion}}
+VERSION:
+ {{.Version}}
+ {{end}}{{end}}{{if len .Authors}}
+AUTHOR(S):
+ {{range .Authors}}{{.}}{{end}}
+ {{end}}{{if .VisibleCommands}}
+COMMANDS:{{range .VisibleCategories}}{{if .Name}}
+ {{.Name}}:{{end}}{{range .VisibleCommands}}
+ {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}
+{{end}}{{end}}{{if .VisibleFlags}}
+GLOBAL OPTIONS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}{{end}}{{if .Copyright}}
+COPYRIGHT:
+ {{.Copyright}}
+ {{end}}
+`
+
+// CommandHelpTemplate is the text template for the command help topic.
+// cli.go uses text/template to render templates. You can
+// render custom help text by setting this variable.
+var CommandHelpTemplate = `NAME:
+ {{.HelpName}} - {{.Usage}}
+
+USAGE:
+ {{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Category}}
+
+CATEGORY:
+ {{.Category}}{{end}}{{if .Description}}
+
+DESCRIPTION:
+ {{.Description}}{{end}}{{if .VisibleFlags}}
+
+OPTIONS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}{{end}}
+`
+
+// SubcommandHelpTemplate is the text template for the subcommand help topic.
+// cli.go uses text/template to render templates. You can
+// render custom help text by setting this variable.
+var SubcommandHelpTemplate = `NAME:
+ {{.HelpName}} - {{.Usage}}
+
+USAGE:
+ {{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
+
+COMMANDS:{{range .VisibleCategories}}{{if .Name}}
+ {{.Name}}:{{end}}{{range .VisibleCommands}}
+ {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}
+{{end}}{{if .VisibleFlags}}
+OPTIONS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}{{end}}
+`
+
+var helpCommand = Command{
+ Name: "help",
+ Aliases: []string{"h"},
+ Usage: "Shows a list of commands or help for one command",
+ ArgsUsage: "[command]",
+ Action: func(c *Context) error {
+ args := c.Args()
+ if args.Present() {
+ return ShowCommandHelp(c, args.First())
+ }
+
+ ShowAppHelp(c)
+ return nil
+ },
+}
+
+var helpSubcommand = Command{
+ Name: "help",
+ Aliases: []string{"h"},
+ Usage: "Shows a list of commands or help for one command",
+ ArgsUsage: "[command]",
+ Action: func(c *Context) error {
+ args := c.Args()
+ if args.Present() {
+ return ShowCommandHelp(c, args.First())
+ }
+
+ return ShowSubcommandHelp(c)
+ },
+}
+
+// Prints help for the App or Command
+type helpPrinter func(w io.Writer, templ string, data interface{})
+
+// HelpPrinter is a function that writes the help output. If not set a default
+// is used. The function signature is:
+// func(w io.Writer, templ string, data interface{})
+var HelpPrinter helpPrinter = printHelp
+
+// VersionPrinter prints the version for the App
+var VersionPrinter = printVersion
+
+// ShowAppHelp is an action that displays the help.
+func ShowAppHelp(c *Context) error {
+ HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
+ return nil
+}
+
+// DefaultAppComplete prints the list of subcommands as the default app completion method
+func DefaultAppComplete(c *Context) {
+ for _, command := range c.App.Commands {
+ if command.Hidden {
+ continue
+ }
+ for _, name := range command.Names() {
+ fmt.Fprintln(c.App.Writer, name)
+ }
+ }
+}
+
+// ShowCommandHelp prints help for the given command
+func ShowCommandHelp(ctx *Context, command string) error {
+ // show the subcommand help for a command with subcommands
+ if command == "" {
+ HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
+ return nil
+ }
+
+ for _, c := range ctx.App.Commands {
+ if c.HasName(command) {
+ HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
+ return nil
+ }
+ }
+
+ if ctx.App.CommandNotFound == nil {
+ return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3)
+ }
+
+ ctx.App.CommandNotFound(ctx, command)
+ return nil
+}
+
+// ShowSubcommandHelp prints help for the given subcommand
+func ShowSubcommandHelp(c *Context) error {
+ return ShowCommandHelp(c, c.Command.Name)
+}
+
+// ShowVersion prints the version number of the App
+func ShowVersion(c *Context) {
+ VersionPrinter(c)
+}
+
+func printVersion(c *Context) {
+ fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
+}
+
+// ShowCompletions prints the lists of commands within a given context
+func ShowCompletions(c *Context) {
+ a := c.App
+ if a != nil && a.BashComplete != nil {
+ a.BashComplete(c)
+ }
+}
+
+// ShowCommandCompletions prints the custom completions for a given command
+func ShowCommandCompletions(ctx *Context, command string) {
+ c := ctx.App.Command(command)
+ if c != nil && c.BashComplete != nil {
+ c.BashComplete(ctx)
+ }
+}
+
+func printHelp(out io.Writer, templ string, data interface{}) {
+ funcMap := template.FuncMap{
+ "join": strings.Join,
+ }
+
+ w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0)
+ t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
+ err := t.Execute(w, data)
+ if err != nil {
+ // If the writer is closed, t.Execute will fail, and there's nothing
+ // we can do to recover.
+ if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" {
+ fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err)
+ }
+ return
+ }
+ w.Flush()
+}
+
+func checkVersion(c *Context) bool {
+ found := false
+ if VersionFlag.Name != "" {
+ eachName(VersionFlag.Name, func(name string) {
+ if c.GlobalBool(name) || c.Bool(name) {
+ found = true
+ }
+ })
+ }
+ return found
+}
+
+func checkHelp(c *Context) bool {
+ found := false
+ if HelpFlag.Name != "" {
+ eachName(HelpFlag.Name, func(name string) {
+ if c.GlobalBool(name) || c.Bool(name) {
+ found = true
+ }
+ })
+ }
+ return found
+}
+
+func checkCommandHelp(c *Context, name string) bool {
+ if c.Bool("h") || c.Bool("help") {
+ ShowCommandHelp(c, name)
+ return true
+ }
+
+ return false
+}
+
+func checkSubcommandHelp(c *Context) bool {
+ if c.GlobalBool("h") || c.GlobalBool("help") {
+ ShowSubcommandHelp(c)
+ return true
+ }
+
+ return false
+}
+
+func checkCompletions(c *Context) bool {
+ if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion {
+ ShowCompletions(c)
+ return true
+ }
+
+ return false
+}
+
+func checkCommandCompletions(c *Context, name string) bool {
+ if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion {
+ ShowCommandCompletions(c, name)
+ return true
+ }
+
+ return false
+}
diff --git a/vendor/github.com/codegangsta/cli/help_test.go b/vendor/github.com/codegangsta/cli/help_test.go
new file mode 100644
index 0000000..7c15400
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/help_test.go
@@ -0,0 +1,289 @@
+package cli
+
+import (
+ "bytes"
+ "flag"
+ "strings"
+ "testing"
+)
+
+func Test_ShowAppHelp_NoAuthor(t *testing.T) {
+ output := new(bytes.Buffer)
+ app := NewApp()
+ app.Writer = output
+
+ c := NewContext(app, nil, nil)
+
+ ShowAppHelp(c)
+
+ if bytes.Index(output.Bytes(), []byte("AUTHOR(S):")) != -1 {
+ t.Errorf("expected\n%snot to include %s", output.String(), "AUTHOR(S):")
+ }
+}
+
+func Test_ShowAppHelp_NoVersion(t *testing.T) {
+ output := new(bytes.Buffer)
+ app := NewApp()
+ app.Writer = output
+
+ app.Version = ""
+
+ c := NewContext(app, nil, nil)
+
+ ShowAppHelp(c)
+
+ if bytes.Index(output.Bytes(), []byte("VERSION:")) != -1 {
+ t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:")
+ }
+}
+
+func Test_ShowAppHelp_HideVersion(t *testing.T) {
+ output := new(bytes.Buffer)
+ app := NewApp()
+ app.Writer = output
+
+ app.HideVersion = true
+
+ c := NewContext(app, nil, nil)
+
+ ShowAppHelp(c)
+
+ if bytes.Index(output.Bytes(), []byte("VERSION:")) != -1 {
+ t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:")
+ }
+}
+
+func Test_Help_Custom_Flags(t *testing.T) {
+ oldFlag := HelpFlag
+ defer func() {
+ HelpFlag = oldFlag
+ }()
+
+ HelpFlag = BoolFlag{
+ Name: "help, x",
+ Usage: "show help",
+ }
+
+ app := App{
+ Flags: []Flag{
+ BoolFlag{Name: "foo, h"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Bool("h") != true {
+ t.Errorf("custom help flag not set")
+ }
+ return nil
+ },
+ }
+ output := new(bytes.Buffer)
+ app.Writer = output
+ app.Run([]string{"test", "-h"})
+ if output.Len() > 0 {
+ t.Errorf("unexpected output: %s", output.String())
+ }
+}
+
+func Test_Version_Custom_Flags(t *testing.T) {
+ oldFlag := VersionFlag
+ defer func() {
+ VersionFlag = oldFlag
+ }()
+
+ VersionFlag = BoolFlag{
+ Name: "version, V",
+ Usage: "show version",
+ }
+
+ app := App{
+ Flags: []Flag{
+ BoolFlag{Name: "foo, v"},
+ },
+ Action: func(ctx *Context) error {
+ if ctx.Bool("v") != true {
+ t.Errorf("custom version flag not set")
+ }
+ return nil
+ },
+ }
+ output := new(bytes.Buffer)
+ app.Writer = output
+ app.Run([]string{"test", "-v"})
+ if output.Len() > 0 {
+ t.Errorf("unexpected output: %s", output.String())
+ }
+}
+
+func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) {
+ app := NewApp()
+
+ set := flag.NewFlagSet("test", 0)
+ set.Parse([]string{"foo"})
+
+ c := NewContext(app, set, nil)
+
+ err := helpCommand.Action.(func(*Context) error)(c)
+
+ if err == nil {
+ t.Fatalf("expected error from helpCommand.Action(), but got nil")
+ }
+
+ exitErr, ok := err.(*ExitError)
+ if !ok {
+ t.Fatalf("expected ExitError from helpCommand.Action(), but instead got: %v", err.Error())
+ }
+
+ if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
+ t.Fatalf("expected an unknown help topic error, but got: %v", exitErr.Error())
+ }
+
+ if exitErr.exitCode != 3 {
+ t.Fatalf("expected exit value = 3, got %d instead", exitErr.exitCode)
+ }
+}
+
+func Test_helpCommand_InHelpOutput(t *testing.T) {
+ app := NewApp()
+ output := &bytes.Buffer{}
+ app.Writer = output
+ app.Run([]string{"test", "--help"})
+
+ s := output.String()
+
+ if strings.Contains(s, "\nCOMMANDS:\nGLOBAL OPTIONS:\n") {
+ t.Fatalf("empty COMMANDS section detected: %q", s)
+ }
+
+ if !strings.Contains(s, "help, h") {
+ t.Fatalf("missing \"help, h\": %q", s)
+ }
+}
+
+func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
+ app := NewApp()
+
+ set := flag.NewFlagSet("test", 0)
+ set.Parse([]string{"foo"})
+
+ c := NewContext(app, set, nil)
+
+ err := helpSubcommand.Action.(func(*Context) error)(c)
+
+ if err == nil {
+ t.Fatalf("expected error from helpCommand.Action(), but got nil")
+ }
+
+ exitErr, ok := err.(*ExitError)
+ if !ok {
+ t.Fatalf("expected ExitError from helpCommand.Action(), but instead got: %v", err.Error())
+ }
+
+ if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
+ t.Fatalf("expected an unknown help topic error, but got: %v", exitErr.Error())
+ }
+
+ if exitErr.exitCode != 3 {
+ t.Fatalf("expected exit value = 3, got %d instead", exitErr.exitCode)
+ }
+}
+
+func TestShowAppHelp_CommandAliases(t *testing.T) {
+ app := &App{
+ Commands: []Command{
+ {
+ Name: "frobbly",
+ Aliases: []string{"fr", "frob"},
+ Action: func(ctx *Context) error {
+ return nil
+ },
+ },
+ },
+ }
+
+ output := &bytes.Buffer{}
+ app.Writer = output
+ app.Run([]string{"foo", "--help"})
+
+ if !strings.Contains(output.String(), "frobbly, fr, frob") {
+ t.Errorf("expected output to include all command aliases; got: %q", output.String())
+ }
+}
+
+func TestShowCommandHelp_CommandAliases(t *testing.T) {
+ app := &App{
+ Commands: []Command{
+ {
+ Name: "frobbly",
+ Aliases: []string{"fr", "frob", "bork"},
+ Action: func(ctx *Context) error {
+ return nil
+ },
+ },
+ },
+ }
+
+ output := &bytes.Buffer{}
+ app.Writer = output
+ app.Run([]string{"foo", "help", "fr"})
+
+ if !strings.Contains(output.String(), "frobbly") {
+ t.Errorf("expected output to include command name; got: %q", output.String())
+ }
+
+ if strings.Contains(output.String(), "bork") {
+ t.Errorf("expected output to exclude command aliases; got: %q", output.String())
+ }
+}
+
+func TestShowSubcommandHelp_CommandAliases(t *testing.T) {
+ app := &App{
+ Commands: []Command{
+ {
+ Name: "frobbly",
+ Aliases: []string{"fr", "frob", "bork"},
+ Action: func(ctx *Context) error {
+ return nil
+ },
+ },
+ },
+ }
+
+ output := &bytes.Buffer{}
+ app.Writer = output
+ app.Run([]string{"foo", "help"})
+
+ if !strings.Contains(output.String(), "frobbly, fr, frob, bork") {
+ t.Errorf("expected output to include all command aliases; got: %q", output.String())
+ }
+}
+
+func TestShowAppHelp_HiddenCommand(t *testing.T) {
+ app := &App{
+ Commands: []Command{
+ {
+ Name: "frobbly",
+ Action: func(ctx *Context) error {
+ return nil
+ },
+ },
+ {
+ Name: "secretfrob",
+ Hidden: true,
+ Action: func(ctx *Context) error {
+ return nil
+ },
+ },
+ },
+ }
+
+ output := &bytes.Buffer{}
+ app.Writer = output
+ app.Run([]string{"app", "--help"})
+
+ if strings.Contains(output.String(), "secretfrob") {
+ t.Errorf("expected output to exclude \"secretfrob\"; got: %q", output.String())
+ }
+
+ if !strings.Contains(output.String(), "frobbly") {
+ t.Errorf("expected output to include \"frobbly\"; got: %q", output.String())
+ }
+}
diff --git a/vendor/github.com/codegangsta/cli/helpers_test.go b/vendor/github.com/codegangsta/cli/helpers_test.go
new file mode 100644
index 0000000..109ea7a
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/helpers_test.go
@@ -0,0 +1,28 @@
+package cli
+
+import (
+ "os"
+ "reflect"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+var (
+ wd, _ = os.Getwd()
+)
+
+func expect(t *testing.T, a interface{}, b interface{}) {
+ _, fn, line, _ := runtime.Caller(1)
+ fn = strings.Replace(fn, wd+"/", "", -1)
+
+ if !reflect.DeepEqual(a, b) {
+ t.Errorf("(%s:%d) Expected %v (type %v) - Got %v (type %v)", fn, line, b, reflect.TypeOf(b), a, reflect.TypeOf(a))
+ }
+}
+
+func refute(t *testing.T, a interface{}, b interface{}) {
+ if reflect.DeepEqual(a, b) {
+ t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
+ }
+}
diff --git a/vendor/github.com/codegangsta/cli/runtests b/vendor/github.com/codegangsta/cli/runtests
new file mode 100644
index 0000000..0a7b483
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/runtests
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+from __future__ import print_function
+
+import argparse
+import os
+import sys
+import tempfile
+
+from subprocess import check_call, check_output
+
+
+PACKAGE_NAME = os.environ.get(
+ 'CLI_PACKAGE_NAME', 'github.com/urfave/cli'
+)
+
+
+def main(sysargs=sys.argv[:]):
+ targets = {
+ 'vet': _vet,
+ 'test': _test,
+ 'gfmxr': _gfmxr,
+ 'toc': _toc,
+ }
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ 'target', nargs='?', choices=tuple(targets.keys()), default='test'
+ )
+ args = parser.parse_args(sysargs[1:])
+
+ targets[args.target]()
+ return 0
+
+
+def _test():
+ if check_output('go version'.split()).split()[2] < 'go1.2':
+ _run('go test -v .'.split())
+ return
+
+ coverprofiles = []
+ for subpackage in ['', 'altsrc']:
+ coverprofile = 'cli.coverprofile'
+ if subpackage != '':
+ coverprofile = '{}.coverprofile'.format(subpackage)
+
+ coverprofiles.append(coverprofile)
+
+ _run('go test -v'.split() + [
+ '-coverprofile={}'.format(coverprofile),
+ ('{}/{}'.format(PACKAGE_NAME, subpackage)).rstrip('/')
+ ])
+
+ combined_name = _combine_coverprofiles(coverprofiles)
+ _run('go tool cover -func={}'.format(combined_name).split())
+ os.remove(combined_name)
+
+
+def _gfmxr():
+ _run(['gfmxr', '-c', str(_gfmxr_count()), '-s', 'README.md'])
+
+
+def _vet():
+ _run('go vet ./...'.split())
+
+
+def _toc():
+ _run(['node_modules/.bin/markdown-toc', '-i', 'README.md'])
+ _run(['git', 'diff', '--quiet'])
+
+
+def _run(command):
+ print('runtests: {}'.format(' '.join(command)), file=sys.stderr)
+ check_call(command)
+
+
+def _gfmxr_count():
+ with open('README.md') as infile:
+ lines = infile.read().splitlines()
+ return len(filter(_is_go_runnable, lines))
+
+
+def _is_go_runnable(line):
+ return line.startswith('package main')
+
+
+def _combine_coverprofiles(coverprofiles):
+ combined = tempfile.NamedTemporaryFile(
+ suffix='.coverprofile', delete=False
+ )
+ combined.write('mode: set\n')
+
+ for coverprofile in coverprofiles:
+ with open(coverprofile, 'r') as infile:
+ for line in infile.readlines():
+ if not line.startswith('mode: '):
+ combined.write(line)
+
+ combined.flush()
+ name = combined.name
+ combined.close()
+ return name
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/vendor/github.com/joho/godotenv/.gitignore b/vendor/github.com/joho/godotenv/.gitignore
new file mode 100644
index 0000000..e43b0f9
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/.gitignore
@@ -0,0 +1 @@
+.DS_Store
diff --git a/vendor/github.com/joho/godotenv/LICENCE b/vendor/github.com/joho/godotenv/LICENCE
new file mode 100644
index 0000000..e7ddd51
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/LICENCE
@@ -0,0 +1,23 @@
+Copyright (c) 2013 John Barton
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/vendor/github.com/joho/godotenv/README.md b/vendor/github.com/joho/godotenv/README.md
new file mode 100644
index 0000000..05c47e6
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/README.md
@@ -0,0 +1,127 @@
+# GoDotEnv [](https://app.wercker.com/project/bykey/507594c2ec7e60f19403a568dfea0f78)
+
+A Go (golang) port of the Ruby dotenv project (which loads env vars from a .env file)
+
+From the original Library:
+
+> Storing configuration in the environment is one of the tenets of a twelve-factor app. Anything that is likely to change between deployment environments–such as resource handles for databases or credentials for external services–should be extracted from the code into environment variables.
+>
+> But it is not always practical to set environment variables on development machines or continuous integration servers where multiple projects are run. Dotenv load variables from a .env file into ENV when the environment is bootstrapped.
+
+It can be used as a library (for loading in env for your own daemons etc) or as a bin command.
+
+There is test coverage and CI for both linuxish and windows environments, but I make no guarantees about the bin version working on windows.
+
+## Installation
+
+As a library
+
+```shell
+go get github.com/joho/godotenv
+```
+
+or if you want to use it as a bin command
+```shell
+go get github.com/joho/godotenv/cmd/godotenv
+```
+
+## Usage
+
+Add your application configuration to your `.env` file in the root of your project:
+
+```shell
+S3_BUCKET=YOURS3BUCKET
+SECRET_KEY=YOURSECRETKEYGOESHERE
+```
+
+Then in your Go app you can do something like
+
+```go
+package main
+
+import (
+ "github.com/joho/godotenv"
+ "log"
+ "os"
+)
+
+func main() {
+ err := godotenv.Load()
+ if err != nil {
+ log.Fatal("Error loading .env file")
+ }
+
+ s3Bucket := os.Getenv("S3_BUCKET")
+ secretKey := os.Getenv("SECRET_KEY")
+
+ // now do something with s3 or whatever
+}
+```
+
+If you're even lazier than that, you can just take advantage of the autoload package which will read in `.env` on import
+
+```go
+import _ "github.com/joho/godotenv/autoload"
+```
+
+While `.env` in the project root is the default, you don't have to be constrained, both examples below are 100% legit
+
+```go
+_ = godotenv.Load("somerandomfile")
+_ = godotenv.Load("filenumberone.env", "filenumbertwo.env")
+```
+
+If you want to be really fancy with your env file you can do comments and exports (below is a valid env file)
+
+```shell
+# I am a comment and that is OK
+SOME_VAR=someval
+FOO=BAR # comments at line end are OK too
+export BAR=BAZ
+```
+
+Or finally you can do YAML(ish) style
+
+```yaml
+FOO: bar
+BAR: baz
+```
+
+as a final aside, if you don't want godotenv munging your env you can just get a map back instead
+
+```go
+var myEnv map[string]string
+myEnv, err := godotenv.Read()
+
+s3Bucket := myEnv["S3_BUCKET"]
+```
+
+### Command Mode
+
+Assuming you've installed the command as above and you've got `$GOPATH/bin` in your `$PATH`
+
+```
+godotenv -f /some/path/to/.env some_command with some args
+```
+
+If you don't specify `-f` it will fall back on the default of loading `.env` in `PWD`
+
+## Contributing
+
+Contributions are most welcome! The parser itself is pretty stupidly naive and I wouldn't be surprised if it breaks with edge cases.
+
+*code changes without tests will not be accepted*
+
+1. Fork it
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Added some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
+
+## CI
+
+Linux: [](https://app.wercker.com/project/bykey/507594c2ec7e60f19403a568dfea0f78) Windows: [](https://ci.appveyor.com/project/joho/godotenv)
+
+## Who?
+
+The original library [dotenv](https://github.com/bkeepers/dotenv) was written by [Brandon Keepers](http://opensoul.org/), and this port was done by [John Barton](http://whoisjohnbarton.com) based off the tests/fixtures in the original library.
diff --git a/vendor/github.com/joho/godotenv/autoload/autoload.go b/vendor/github.com/joho/godotenv/autoload/autoload.go
new file mode 100644
index 0000000..fbcd2bd
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/autoload/autoload.go
@@ -0,0 +1,15 @@
+package autoload
+
+/*
+ You can just read the .env file on import just by doing
+
+ import _ "github.com/joho/godotenv/autoload"
+
+ And bob's your mother's brother
+*/
+
+import "github.com/joho/godotenv"
+
+func init() {
+ godotenv.Load()
+}
diff --git a/vendor/github.com/joho/godotenv/cmd/godotenv/cmd.go b/vendor/github.com/joho/godotenv/cmd/godotenv/cmd.go
new file mode 100644
index 0000000..04a9f64
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/cmd/godotenv/cmd.go
@@ -0,0 +1,54 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+
+ "strings"
+
+ "github.com/joho/godotenv"
+)
+
+func main() {
+ var showHelp bool
+ flag.BoolVar(&showHelp, "h", false, "show help")
+ var rawEnvFilenames string
+ flag.StringVar(&rawEnvFilenames, "f", "", "comma separated paths to .env files")
+
+ flag.Parse()
+
+ usage := `
+Run a process with a env setup from a .env file
+
+godotenv [-f ENV_FILE_PATHS] COMMAND_ARGS
+
+ENV_FILE_PATHS: comma separated paths to .env files
+COMMAND_ARGS: command and args you want to run
+
+example
+ godotenv -f /path/to/something/.env,/another/path/.env fortune
+`
+ // if no args or -h flag
+ // print usage and return
+ args := flag.Args()
+ if showHelp || len(args) == 0 {
+ fmt.Println(usage)
+ return
+ }
+
+ // load env
+ var envFilenames []string
+ if rawEnvFilenames != "" {
+ envFilenames = strings.Split(rawEnvFilenames, ",")
+ }
+
+ // take rest of args and "exec" them
+ cmd := args[0]
+ cmdArgs := args[1:]
+
+ err := godotenv.Exec(envFilenames, cmd, cmdArgs)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/vendor/github.com/joho/godotenv/fixtures/equals.env b/vendor/github.com/joho/godotenv/fixtures/equals.env
new file mode 100644
index 0000000..594c532
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/fixtures/equals.env
@@ -0,0 +1,2 @@
+export OPTION_A='postgres://localhost:5432/database?sslmode=disable'
+
diff --git a/vendor/github.com/joho/godotenv/fixtures/exported.env b/vendor/github.com/joho/godotenv/fixtures/exported.env
new file mode 100644
index 0000000..5821377
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/fixtures/exported.env
@@ -0,0 +1,2 @@
+export OPTION_A=2
+export OPTION_B='\n'
diff --git a/vendor/github.com/joho/godotenv/fixtures/plain.env b/vendor/github.com/joho/godotenv/fixtures/plain.env
new file mode 100644
index 0000000..c983b06
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/fixtures/plain.env
@@ -0,0 +1,5 @@
+OPTION_A=1
+OPTION_B=2
+OPTION_C= 3
+OPTION_D =4
+OPTION_E = 5
diff --git a/vendor/github.com/joho/godotenv/fixtures/quoted.env b/vendor/github.com/joho/godotenv/fixtures/quoted.env
new file mode 100644
index 0000000..a03ce24
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/fixtures/quoted.env
@@ -0,0 +1,8 @@
+OPTION_A='1'
+OPTION_B='2'
+OPTION_C=''
+OPTION_D='\n'
+OPTION_E="1"
+OPTION_F="2"
+OPTION_G=""
+OPTION_H="\n"
diff --git a/vendor/github.com/joho/godotenv/godotenv.go b/vendor/github.com/joho/godotenv/godotenv.go
new file mode 100644
index 0000000..94b2676
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/godotenv.go
@@ -0,0 +1,229 @@
+// Package godotenv is a go port of the ruby dotenv library (https://github.com/bkeepers/dotenv)
+//
+// Examples/readme can be found on the github page at https://github.com/joho/godotenv
+//
+// The TL;DR is that you make a .env file that looks something like
+//
+// SOME_ENV_VAR=somevalue
+//
+// and then in your go code you can call
+//
+// godotenv.Load()
+//
+// and all the env vars declared in .env will be avaiable through os.Getenv("SOME_ENV_VAR")
+package godotenv
+
+import (
+ "bufio"
+ "errors"
+ "os"
+ "os/exec"
+ "strings"
+)
+
+// Load will read your env file(s) and load them into ENV for this process.
+//
+// Call this function as close as possible to the start of your program (ideally in main)
+//
+// If you call Load without any args it will default to loading .env in the current path
+//
+// You can otherwise tell it which files to load (there can be more than one) like
+//
+// godotenv.Load("fileone", "filetwo")
+//
+// It's important to note that it WILL NOT OVERRIDE an env variable that already exists - consider the .env file to set dev vars or sensible defaults
+func Load(filenames ...string) (err error) {
+ filenames = filenamesOrDefault(filenames)
+
+ for _, filename := range filenames {
+ err = loadFile(filename, false)
+ if err != nil {
+ return // return early on a spazout
+ }
+ }
+ return
+}
+
+// Overload will read your env file(s) and load them into ENV for this process.
+//
+// Call this function as close as possible to the start of your program (ideally in main)
+//
+// If you call Overload without any args it will default to loading .env in the current path
+//
+// You can otherwise tell it which files to load (there can be more than one) like
+//
+// godotenv.Overload("fileone", "filetwo")
+//
+// It's important to note this WILL OVERRIDE an env variable that already exists - consider the .env file to forcefilly set all vars.
+func Overload(filenames ...string) (err error) {
+ filenames = filenamesOrDefault(filenames)
+
+ for _, filename := range filenames {
+ err = loadFile(filename, true)
+ if err != nil {
+ return // return early on a spazout
+ }
+ }
+ return
+}
+
+// Read all env (with same file loading semantics as Load) but return values as
+// a map rather than automatically writing values into env
+func Read(filenames ...string) (envMap map[string]string, err error) {
+ filenames = filenamesOrDefault(filenames)
+ envMap = make(map[string]string)
+
+ for _, filename := range filenames {
+ individualEnvMap, individualErr := readFile(filename)
+
+ if individualErr != nil {
+ err = individualErr
+ return // return early on a spazout
+ }
+
+ for key, value := range individualEnvMap {
+ envMap[key] = value
+ }
+ }
+
+ return
+}
+
+// Exec loads env vars from the specified filenames (empty map falls back to default)
+// then executes the cmd specified.
+//
+// Simply hooks up os.Stdin/err/out to the command and calls Run()
+//
+// If you want more fine grained control over your command it's recommended
+// that you use `Load()` or `Read()` and the `os/exec` package yourself.
+func Exec(filenames []string, cmd string, cmdArgs []string) error {
+ Load(filenames...)
+
+ command := exec.Command(cmd, cmdArgs...)
+ command.Stdin = os.Stdin
+ command.Stdout = os.Stdout
+ command.Stderr = os.Stderr
+ return command.Run()
+}
+
+func filenamesOrDefault(filenames []string) []string {
+ if len(filenames) == 0 {
+ return []string{".env"}
+ }
+ return filenames
+}
+
+func loadFile(filename string, overload bool) error {
+ envMap, err := readFile(filename)
+ if err != nil {
+ return err
+ }
+
+ for key, value := range envMap {
+ if os.Getenv(key) == "" || overload {
+ os.Setenv(key, value)
+ }
+ }
+
+ return nil
+}
+
+func readFile(filename string) (envMap map[string]string, err error) {
+ file, err := os.Open(filename)
+ if err != nil {
+ return
+ }
+ defer file.Close()
+
+ envMap = make(map[string]string)
+
+ var lines []string
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ lines = append(lines, scanner.Text())
+ }
+
+ for _, fullLine := range lines {
+ if !isIgnoredLine(fullLine) {
+ key, value, err := parseLine(fullLine)
+
+ if err == nil {
+ envMap[key] = value
+ }
+ }
+ }
+ return
+}
+
+func parseLine(line string) (key string, value string, err error) {
+ if len(line) == 0 {
+ err = errors.New("zero length string")
+ return
+ }
+
+ // ditch the comments (but keep quoted hashes)
+ if strings.Contains(line, "#") {
+ segmentsBetweenHashes := strings.Split(line, "#")
+ quotesAreOpen := false
+ var segmentsToKeep []string
+ for _, segment := range segmentsBetweenHashes {
+ if strings.Count(segment, "\"") == 1 || strings.Count(segment, "'") == 1 {
+ if quotesAreOpen {
+ quotesAreOpen = false
+ segmentsToKeep = append(segmentsToKeep, segment)
+ } else {
+ quotesAreOpen = true
+ }
+ }
+
+ if len(segmentsToKeep) == 0 || quotesAreOpen {
+ segmentsToKeep = append(segmentsToKeep, segment)
+ }
+ }
+
+ line = strings.Join(segmentsToKeep, "#")
+ }
+
+ // now split key from value
+ splitString := strings.SplitN(line, "=", 2)
+
+ if len(splitString) != 2 {
+ // try yaml mode!
+ splitString = strings.SplitN(line, ":", 2)
+ }
+
+ if len(splitString) != 2 {
+ err = errors.New("Can't separate key from value")
+ return
+ }
+
+ // Parse the key
+ key = splitString[0]
+ if strings.HasPrefix(key, "export") {
+ key = strings.TrimPrefix(key, "export")
+ }
+ key = strings.Trim(key, " ")
+
+ // Parse the value
+ value = splitString[1]
+ // trim
+ value = strings.Trim(value, " ")
+
+ // check if we've got quoted values
+ if strings.Count(value, "\"") == 2 || strings.Count(value, "'") == 2 {
+ // pull the quotes off the edges
+ value = strings.Trim(value, "\"'")
+
+ // expand quotes
+ value = strings.Replace(value, "\\\"", "\"", -1)
+ // expand newlines
+ value = strings.Replace(value, "\\n", "\n", -1)
+ }
+
+ return
+}
+
+func isIgnoredLine(line string) bool {
+ trimmedLine := strings.Trim(line, " \n\t")
+ return len(trimmedLine) == 0 || strings.HasPrefix(trimmedLine, "#")
+}
diff --git a/vendor/github.com/joho/godotenv/godotenv_test.go b/vendor/github.com/joho/godotenv/godotenv_test.go
new file mode 100644
index 0000000..e93539e
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/godotenv_test.go
@@ -0,0 +1,271 @@
+package godotenv
+
+import (
+ "os"
+ "testing"
+)
+
+var noopPresets = make(map[string]string)
+
+func parseAndCompare(t *testing.T, rawEnvLine string, expectedKey string, expectedValue string) {
+ key, value, _ := parseLine(rawEnvLine)
+ if key != expectedKey || value != expectedValue {
+ t.Errorf("Expected '%v' to parse as '%v' => '%v', got '%v' => '%v' instead", rawEnvLine, expectedKey, expectedValue, key, value)
+ }
+}
+
+func loadEnvAndCompareValues(t *testing.T, loader func(files ...string) error, envFileName string, expectedValues map[string]string, presets map[string]string) {
+ // first up, clear the env
+ os.Clearenv()
+
+ for k, v := range presets {
+ os.Setenv(k, v)
+ }
+
+ err := loader(envFileName)
+ if err != nil {
+ t.Fatalf("Error loading %v", envFileName)
+ }
+
+ for k := range expectedValues {
+ envValue := os.Getenv(k)
+ v := expectedValues[k]
+ if envValue != v {
+ t.Errorf("Mismatch for key '%v': expected '%v' got '%v'", k, v, envValue)
+ }
+ }
+}
+
+func TestLoadWithNoArgsLoadsDotEnv(t *testing.T) {
+ err := Load()
+ pathError := err.(*os.PathError)
+ if pathError == nil || pathError.Op != "open" || pathError.Path != ".env" {
+ t.Errorf("Didn't try and open .env by default")
+ }
+}
+
+func TestOverloadWithNoArgsOverloadsDotEnv(t *testing.T) {
+ err := Overload()
+ pathError := err.(*os.PathError)
+ if pathError == nil || pathError.Op != "open" || pathError.Path != ".env" {
+ t.Errorf("Didn't try and open .env by default")
+ }
+}
+
+func TestLoadFileNotFound(t *testing.T) {
+ err := Load("somefilethatwillneverexistever.env")
+ if err == nil {
+ t.Error("File wasn't found but Load didn't return an error")
+ }
+}
+
+func TestOverloadFileNotFound(t *testing.T) {
+ err := Overload("somefilethatwillneverexistever.env")
+ if err == nil {
+ t.Error("File wasn't found but Overload didn't return an error")
+ }
+}
+
+func TestReadPlainEnv(t *testing.T) {
+ envFileName := "fixtures/plain.env"
+ expectedValues := map[string]string{
+ "OPTION_A": "1",
+ "OPTION_B": "2",
+ "OPTION_C": "3",
+ "OPTION_D": "4",
+ "OPTION_E": "5",
+ }
+
+ envMap, err := Read(envFileName)
+ if err != nil {
+ t.Error("Error reading file")
+ }
+
+ if len(envMap) != len(expectedValues) {
+ t.Error("Didn't get the right size map back")
+ }
+
+ for key, value := range expectedValues {
+ if envMap[key] != value {
+ t.Error("Read got one of the keys wrong")
+ }
+ }
+}
+
+func TestLoadDoesNotOverride(t *testing.T) {
+ envFileName := "fixtures/plain.env"
+
+ // ensure NO overload
+ presets := map[string]string{
+ "OPTION_A": "do_not_override",
+ }
+
+ expectedValues := map[string]string{
+ "OPTION_A": "do_not_override",
+ }
+ loadEnvAndCompareValues(t, Load, envFileName, expectedValues, presets)
+}
+
+func TestOveroadDoesOverride(t *testing.T) {
+ envFileName := "fixtures/plain.env"
+
+ // ensure NO overload
+ presets := map[string]string{
+ "OPTION_A": "do_not_override",
+ }
+
+ expectedValues := map[string]string{
+ "OPTION_A": "1",
+ }
+ loadEnvAndCompareValues(t, Overload, envFileName, expectedValues, presets)
+}
+
+func TestLoadPlainEnv(t *testing.T) {
+ envFileName := "fixtures/plain.env"
+ expectedValues := map[string]string{
+ "OPTION_A": "1",
+ "OPTION_B": "2",
+ "OPTION_C": "3",
+ "OPTION_D": "4",
+ "OPTION_E": "5",
+ }
+
+ loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
+}
+
+func TestLoadExportedEnv(t *testing.T) {
+ envFileName := "fixtures/exported.env"
+ expectedValues := map[string]string{
+ "OPTION_A": "2",
+ "OPTION_B": "\n",
+ }
+
+ loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
+}
+
+func TestLoadEqualsEnv(t *testing.T) {
+ envFileName := "fixtures/equals.env"
+ expectedValues := map[string]string{
+ "OPTION_A": "postgres://localhost:5432/database?sslmode=disable",
+ }
+
+ loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
+}
+
+func TestLoadQuotedEnv(t *testing.T) {
+ envFileName := "fixtures/quoted.env"
+ expectedValues := map[string]string{
+ "OPTION_A": "1",
+ "OPTION_B": "2",
+ "OPTION_C": "",
+ "OPTION_D": "\n",
+ "OPTION_E": "1",
+ "OPTION_F": "2",
+ "OPTION_G": "",
+ "OPTION_H": "\n",
+ }
+
+ loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
+}
+
+func TestActualEnvVarsAreLeftAlone(t *testing.T) {
+ os.Clearenv()
+ os.Setenv("OPTION_A", "actualenv")
+ _ = Load("fixtures/plain.env")
+
+ if os.Getenv("OPTION_A") != "actualenv" {
+ t.Error("An ENV var set earlier was overwritten")
+ }
+}
+
+func TestParsing(t *testing.T) {
+ // unquoted values
+ parseAndCompare(t, "FOO=bar", "FOO", "bar")
+
+ // parses values with spaces around equal sign
+ parseAndCompare(t, "FOO =bar", "FOO", "bar")
+ parseAndCompare(t, "FOO= bar", "FOO", "bar")
+
+ // parses double quoted values
+ parseAndCompare(t, "FOO=\"bar\"", "FOO", "bar")
+
+ // parses single quoted values
+ parseAndCompare(t, "FOO='bar'", "FOO", "bar")
+
+ // parses escaped double quotes
+ parseAndCompare(t, "FOO=escaped\\\"bar\"", "FOO", "escaped\"bar")
+
+ // parses yaml style options
+ parseAndCompare(t, "OPTION_A: 1", "OPTION_A", "1")
+
+ // parses export keyword
+ parseAndCompare(t, "export OPTION_A=2", "OPTION_A", "2")
+ parseAndCompare(t, "export OPTION_B='\\n'", "OPTION_B", "\n")
+
+ // it 'expands newlines in quoted strings' do
+ // expect(env('FOO="bar\nbaz"')).to eql('FOO' => "bar\nbaz")
+ parseAndCompare(t, "FOO=\"bar\\nbaz\"", "FOO", "bar\nbaz")
+
+ // it 'parses varibales with "." in the name' do
+ // expect(env('FOO.BAR=foobar')).to eql('FOO.BAR' => 'foobar')
+ parseAndCompare(t, "FOO.BAR=foobar", "FOO.BAR", "foobar")
+
+ // it 'parses varibales with several "=" in the value' do
+ // expect(env('FOO=foobar=')).to eql('FOO' => 'foobar=')
+ parseAndCompare(t, "FOO=foobar=", "FOO", "foobar=")
+
+ // it 'strips unquoted values' do
+ // expect(env('foo=bar ')).to eql('foo' => 'bar') # not 'bar '
+ parseAndCompare(t, "FOO=bar ", "FOO", "bar")
+
+ // it 'ignores inline comments' do
+ // expect(env("foo=bar # this is foo")).to eql('foo' => 'bar')
+ parseAndCompare(t, "FOO=bar # this is foo", "FOO", "bar")
+
+ // it 'allows # in quoted value' do
+ // expect(env('foo="bar#baz" # comment')).to eql('foo' => 'bar#baz')
+ parseAndCompare(t, "FOO=\"bar#baz\" # comment", "FOO", "bar#baz")
+ parseAndCompare(t, "FOO='bar#baz' # comment", "FOO", "bar#baz")
+ parseAndCompare(t, "FOO=\"bar#baz#bang\" # comment", "FOO", "bar#baz#bang")
+
+ // it 'parses # in quoted values' do
+ // expect(env('foo="ba#r"')).to eql('foo' => 'ba#r')
+ // expect(env("foo='ba#r'")).to eql('foo' => 'ba#r')
+ parseAndCompare(t, "FOO=\"ba#r\"", "FOO", "ba#r")
+ parseAndCompare(t, "FOO='ba#r'", "FOO", "ba#r")
+
+ // it 'throws an error if line format is incorrect' do
+ // expect{env('lol$wut')}.to raise_error(Dotenv::FormatError)
+ badlyFormattedLine := "lol$wut"
+ _, _, err := parseLine(badlyFormattedLine)
+ if err == nil {
+ t.Errorf("Expected \"%v\" to return error, but it didn't", badlyFormattedLine)
+ }
+}
+
+func TestLinesToIgnore(t *testing.T) {
+ // it 'ignores empty lines' do
+ // expect(env("\n \t \nfoo=bar\n \nfizz=buzz")).to eql('foo' => 'bar', 'fizz' => 'buzz')
+ if !isIgnoredLine("\n") {
+ t.Error("Line with nothing but line break wasn't ignored")
+ }
+
+ if !isIgnoredLine("\t\t ") {
+ t.Error("Line full of whitespace wasn't ignored")
+ }
+
+ // it 'ignores comment lines' do
+ // expect(env("\n\n\n # HERE GOES FOO \nfoo=bar")).to eql('foo' => 'bar')
+ if !isIgnoredLine("# comment") {
+ t.Error("Comment wasn't ignored")
+ }
+
+ if !isIgnoredLine("\t#comment") {
+ t.Error("Indented comment wasn't ignored")
+ }
+
+ // make sure we're not getting false positives
+ if isIgnoredLine("export OPTION_B='\\n'") {
+ t.Error("ignoring a perfectly valid line to parse")
+ }
+}
diff --git a/vendor/github.com/joho/godotenv/wercker.yml b/vendor/github.com/joho/godotenv/wercker.yml
new file mode 100644
index 0000000..c716ac9
--- /dev/null
+++ b/vendor/github.com/joho/godotenv/wercker.yml
@@ -0,0 +1 @@
+box: pjvds/golang