refactor: switch to go mod
This hopefully makes it a little easier to work with as the tooling is now based on something in golang core. - move columnize usage to common plugin - remove old vendor files
This commit is contained in:
8
plugins/config/glide.lock
generated
8
plugins/config/glide.lock
generated
@@ -1,8 +0,0 @@
|
||||
hash: dd48defef474bdf5c6e47281a256ca941d71fe1e637d11443fb49acf3e4b5326
|
||||
updated: 2017-09-23T16:25:15.559883959-04:00
|
||||
imports:
|
||||
- name: github.com/joho/godotenv
|
||||
version: a79fa1e548e2c689c241d10173efd51e5d689d5b
|
||||
- name: github.com/ryanuber/columnize
|
||||
version: abc90934186a77966e2beeac62ed966aac0561d5
|
||||
testImports: []
|
||||
@@ -1,8 +0,0 @@
|
||||
package: github.com/dokku/dokku/plugins/config
|
||||
ignore:
|
||||
- github.com/dokku/dokku/plugins/common
|
||||
- github.com/onsi/gomega
|
||||
import:
|
||||
- package: github.com/ryanuber/columnize
|
||||
- package: github.com/joho/godotenv
|
||||
version: ^1.2.0
|
||||
12
plugins/config/go.mod
Normal file
12
plugins/config/go.mod
Normal file
@@ -0,0 +1,12 @@
|
||||
module github.com/dokku/dokku/plugins/config
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect
|
||||
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3
|
||||
)
|
||||
|
||||
replace github.com/dokku/dokku/plugins/common => ../common
|
||||
47
plugins/config/go.sum
Normal file
47
plugins/config/go.sum
Normal file
@@ -0,0 +1,47 @@
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA=
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3 h1:utdYOikI1XjNtTFGCwSM6OmFJblU4ld4gACoJsbadJg=
|
||||
github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
columnize "github.com/ryanuber/columnize"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -74,11 +73,5 @@ func main() {
|
||||
}
|
||||
|
||||
func usage() {
|
||||
config := columnize.DefaultConfig()
|
||||
config.Delim = ","
|
||||
config.Prefix = " "
|
||||
config.Empty = ""
|
||||
content := strings.Split(helpContent, "\n")[1:]
|
||||
fmt.Println(helpHeader)
|
||||
fmt.Println(columnize.Format(content, config))
|
||||
common.CommandUsage(helpHeader, helpContent)
|
||||
}
|
||||
|
||||
1
plugins/config/vendor/github.com/joho/godotenv/.gitignore
generated
vendored
1
plugins/config/vendor/github.com/joho/godotenv/.gitignore
generated
vendored
@@ -1 +0,0 @@
|
||||
.DS_Store
|
||||
8
plugins/config/vendor/github.com/joho/godotenv/.travis.yml
generated
vendored
8
plugins/config/vendor/github.com/joho/godotenv/.travis.yml
generated
vendored
@@ -1,8 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
23
plugins/config/vendor/github.com/joho/godotenv/LICENCE
generated
vendored
23
plugins/config/vendor/github.com/joho/godotenv/LICENCE
generated
vendored
@@ -1,23 +0,0 @@
|
||||
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.
|
||||
|
||||
163
plugins/config/vendor/github.com/joho/godotenv/README.md
generated
vendored
163
plugins/config/vendor/github.com/joho/godotenv/README.md
generated
vendored
@@ -1,163 +0,0 @@
|
||||
# GoDotEnv [](https://travis-ci.org/joho/godotenv) [](https://ci.appveyor.com/project/joho/godotenv) [](https://goreportcard.com/report/github.com/joho/godotenv)
|
||||
|
||||
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"]
|
||||
```
|
||||
|
||||
... or from an `io.Reader` instead of a local file
|
||||
|
||||
```go
|
||||
reader := getRemoteFile()
|
||||
myEnv, err := godotenv.Parse(reader)
|
||||
```
|
||||
|
||||
... or from a `string` if you so desire
|
||||
|
||||
```go
|
||||
content := getRemoteFileContent()
|
||||
myEnv, err := godotenv.Unmarshal(content)
|
||||
```
|
||||
|
||||
### 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`
|
||||
|
||||
### Writing Env Files
|
||||
|
||||
Godotenv can also write a map representing the environment to a correctly-formatted and escaped file
|
||||
|
||||
```go
|
||||
env, err := godotenv.Unmarshal("KEY=value")
|
||||
err := godotenv.Write(env, "./.env")
|
||||
```
|
||||
|
||||
... or to a string
|
||||
|
||||
```go
|
||||
env, err := godotenv.Unmarshal("KEY=value")
|
||||
content, err := godotenv.Marshal(env)
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
## Releases
|
||||
|
||||
Releases should follow [Semver](http://semver.org/) though the first couple of releases are `v1` and `v1.1`.
|
||||
|
||||
Use [annotated tags for all releases](https://github.com/joho/godotenv/issues/30). Example `git tag -a v1.2.1`
|
||||
|
||||
## CI
|
||||
|
||||
Linux: [](https://travis-ci.org/joho/godotenv) 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.
|
||||
15
plugins/config/vendor/github.com/joho/godotenv/autoload/autoload.go
generated
vendored
15
plugins/config/vendor/github.com/joho/godotenv/autoload/autoload.go
generated
vendored
@@ -1,15 +0,0 @@
|
||||
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()
|
||||
}
|
||||
54
plugins/config/vendor/github.com/joho/godotenv/cmd/godotenv/cmd.go
generated
vendored
54
plugins/config/vendor/github.com/joho/godotenv/cmd/godotenv/cmd.go
generated
vendored
@@ -1,54 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/equals.env
generated
vendored
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/equals.env
generated
vendored
@@ -1,2 +0,0 @@
|
||||
export OPTION_A='postgres://localhost:5432/database?sslmode=disable'
|
||||
|
||||
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/exported.env
generated
vendored
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/exported.env
generated
vendored
@@ -1,2 +0,0 @@
|
||||
export OPTION_A=2
|
||||
export OPTION_B='\n'
|
||||
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/invalid1.env
generated
vendored
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/invalid1.env
generated
vendored
@@ -1,2 +0,0 @@
|
||||
INVALID LINE
|
||||
foo=bar
|
||||
7
plugins/config/vendor/github.com/joho/godotenv/fixtures/plain.env
generated
vendored
7
plugins/config/vendor/github.com/joho/godotenv/fixtures/plain.env
generated
vendored
@@ -1,7 +0,0 @@
|
||||
OPTION_A=1
|
||||
OPTION_B=2
|
||||
OPTION_C= 3
|
||||
OPTION_D =4
|
||||
OPTION_E = 5
|
||||
OPTION_F =
|
||||
OPTION_G=
|
||||
8
plugins/config/vendor/github.com/joho/godotenv/fixtures/quoted.env
generated
vendored
8
plugins/config/vendor/github.com/joho/godotenv/fixtures/quoted.env
generated
vendored
@@ -1,8 +0,0 @@
|
||||
OPTION_A='1'
|
||||
OPTION_B='2'
|
||||
OPTION_C=''
|
||||
OPTION_D='\n'
|
||||
OPTION_E="1"
|
||||
OPTION_F="2"
|
||||
OPTION_G=""
|
||||
OPTION_H="\n"
|
||||
314
plugins/config/vendor/github.com/joho/godotenv/godotenv.go
generated
vendored
314
plugins/config/vendor/github.com/joho/godotenv/godotenv.go
generated
vendored
@@ -1,314 +0,0 @@
|
||||
// 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 available through os.Getenv("SOME_ENV_VAR")
|
||||
package godotenv
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const doubleQuoteSpecialChars = "\\\n\r\"!$`"
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Parse reads an env file from io.Reader, returning a map of keys and values.
|
||||
func Parse(r io.Reader) (envMap map[string]string, err error) {
|
||||
envMap = make(map[string]string)
|
||||
|
||||
var lines []string
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
lines = append(lines, scanner.Text())
|
||||
}
|
||||
|
||||
if err = scanner.Err(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, fullLine := range lines {
|
||||
if !isIgnoredLine(fullLine) {
|
||||
var key, value string
|
||||
key, value, err = parseLine(fullLine)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
envMap[key] = value
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//Unmarshal reads an env file from a string, returning a map of keys and values.
|
||||
func Unmarshal(str string) (envMap map[string]string, err error) {
|
||||
return Parse(strings.NewReader(str))
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
// Write serializes the given environment and writes it to a file
|
||||
func Write(envMap map[string]string, filename string) error {
|
||||
content, error := Marshal(envMap)
|
||||
if error != nil {
|
||||
return error
|
||||
}
|
||||
file, error := os.Create(filename)
|
||||
if error != nil {
|
||||
return error
|
||||
}
|
||||
_, err := file.WriteString(content)
|
||||
return err
|
||||
}
|
||||
|
||||
// Marshal outputs the given environment as a dotenv-formatted environment file.
|
||||
// Each line is in the format: KEY="VALUE" where VALUE is backslash-escaped.
|
||||
func Marshal(envMap map[string]string) (string, error) {
|
||||
lines := make([]string, 0, len(envMap))
|
||||
for k, v := range envMap {
|
||||
lines = append(lines, fmt.Sprintf(`%s="%s"`, k, doubleQuoteEscape(v)))
|
||||
}
|
||||
sort.Strings(lines)
|
||||
return strings.Join(lines, "\n"), nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
currentEnv := map[string]bool{}
|
||||
rawEnv := os.Environ()
|
||||
for _, rawEnvLine := range rawEnv {
|
||||
key := strings.Split(rawEnvLine, "=")[0]
|
||||
currentEnv[key] = true
|
||||
}
|
||||
|
||||
for key, value := range envMap {
|
||||
if !currentEnv[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()
|
||||
|
||||
return Parse(file)
|
||||
}
|
||||
|
||||
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, "#")
|
||||
}
|
||||
|
||||
firstEquals := strings.Index(line, "=")
|
||||
firstColon := strings.Index(line, ":")
|
||||
splitString := strings.SplitN(line, "=", 2)
|
||||
if firstColon != -1 && (firstColon < firstEquals || firstEquals == -1) {
|
||||
//this is a yaml-style line
|
||||
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 = parseValue(splitString[1])
|
||||
return
|
||||
}
|
||||
|
||||
func parseValue(value string) string {
|
||||
|
||||
// trim
|
||||
value = strings.Trim(value, " ")
|
||||
|
||||
// check if we've got quoted values or possible escapes
|
||||
if len(value) > 1 {
|
||||
first := string(value[0:1])
|
||||
last := string(value[len(value)-1:])
|
||||
if first == last && strings.ContainsAny(first, `"'`) {
|
||||
// pull the quotes off the edges
|
||||
value = value[1 : len(value)-1]
|
||||
// handle escapes
|
||||
escapeRegex := regexp.MustCompile(`\\.`)
|
||||
value = escapeRegex.ReplaceAllStringFunc(value, func(match string) string {
|
||||
c := strings.TrimPrefix(match, `\`)
|
||||
switch c {
|
||||
case "n":
|
||||
return "\n"
|
||||
case "r":
|
||||
return "\r"
|
||||
default:
|
||||
return c
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func isIgnoredLine(line string) bool {
|
||||
trimmedLine := strings.Trim(line, " \n\t")
|
||||
return len(trimmedLine) == 0 || strings.HasPrefix(trimmedLine, "#")
|
||||
}
|
||||
|
||||
func doubleQuoteEscape(line string) string {
|
||||
for _, c := range doubleQuoteSpecialChars {
|
||||
toReplace := "\\" + string(c)
|
||||
if c == '\n' {
|
||||
toReplace = `\n`
|
||||
}
|
||||
if c == '\r' {
|
||||
toReplace = `\r`
|
||||
}
|
||||
line = strings.Replace(line, string(c), toReplace, -1)
|
||||
}
|
||||
return line
|
||||
}
|
||||
375
plugins/config/vendor/github.com/joho/godotenv/godotenv_test.go
generated
vendored
375
plugins/config/vendor/github.com/joho/godotenv/godotenv_test.go
generated
vendored
@@ -1,375 +0,0 @@
|
||||
package godotenv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"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",
|
||||
"OPTION_F": "",
|
||||
"OPTION_G": "",
|
||||
}
|
||||
|
||||
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 TestParse(t *testing.T) {
|
||||
envMap, err := Parse(bytes.NewReader([]byte("ONE=1\nTWO='2'\nTHREE = \"3\"")))
|
||||
expectedValues := map[string]string{
|
||||
"ONE": "1",
|
||||
"TWO": "2",
|
||||
"THREE": "3",
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing env: %v", err)
|
||||
}
|
||||
for key, value := range expectedValues {
|
||||
if envMap[key] != value {
|
||||
t.Errorf("expected %s to be %s, got %s", key, value, envMap[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadDoesNotOverride(t *testing.T) {
|
||||
envFileName := "fixtures/plain.env"
|
||||
|
||||
// ensure NO overload
|
||||
presets := map[string]string{
|
||||
"OPTION_A": "do_not_override",
|
||||
"OPTION_B": "",
|
||||
}
|
||||
|
||||
expectedValues := map[string]string{
|
||||
"OPTION_A": "do_not_override",
|
||||
"OPTION_B": "",
|
||||
}
|
||||
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 single quotes inside double quotes
|
||||
parseAndCompare(t, `FOO="'d'"`, "FOO", `'d'`)
|
||||
|
||||
// parses yaml style options
|
||||
parseAndCompare(t, "OPTION_A: 1", "OPTION_A", "1")
|
||||
|
||||
//parses yaml values with equal signs
|
||||
parseAndCompare(t, "OPTION_A: Foo=bar", "OPTION_A", "Foo=bar")
|
||||
|
||||
// parses non-yaml options with colons
|
||||
parseAndCompare(t, "OPTION_A=1:B", "OPTION_A", "1:B")
|
||||
|
||||
// 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")
|
||||
|
||||
//newlines and backslashes should be escaped
|
||||
parseAndCompare(t, `FOO="bar\n\ b\az"`, "FOO", "bar\n baz")
|
||||
parseAndCompare(t, `FOO="bar\\\n\ b\az"`, "FOO", "bar\\\n baz")
|
||||
parseAndCompare(t, `FOO="bar\\r\ b\az"`, "FOO", "bar\\r baz")
|
||||
|
||||
parseAndCompare(t, `="value"`, "", "value")
|
||||
parseAndCompare(t, `KEY="`, "KEY", "\"")
|
||||
parseAndCompare(t, `KEY="value`, "KEY", "\"value")
|
||||
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorReadDirectory(t *testing.T) {
|
||||
envFileName := "fixtures/"
|
||||
envMap, err := Read(envFileName)
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("Expected error, got %v", envMap)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorParsing(t *testing.T) {
|
||||
envFileName := "fixtures/invalid1.env"
|
||||
envMap, err := Read(envFileName)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error, got %v", envMap)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
writeAndCompare := func(env string, expected string) {
|
||||
envMap, _ := Unmarshal(env)
|
||||
actual, _ := Marshal(envMap)
|
||||
if expected != actual {
|
||||
t.Errorf("Expected '%v' (%v) to write as '%v', got '%v' instead.", env, envMap, expected, actual)
|
||||
}
|
||||
}
|
||||
//just test some single lines to show the general idea
|
||||
//TestRoundtrip makes most of the good assertions
|
||||
|
||||
//values are always double-quoted
|
||||
writeAndCompare(`key=value`, `key="value"`)
|
||||
//double-quotes are escaped
|
||||
writeAndCompare(`key=va"lu"e`, `key="va\"lu\"e"`)
|
||||
//but single quotes are left alone
|
||||
writeAndCompare(`key=va'lu'e`, `key="va'lu'e"`)
|
||||
// newlines, backslashes, and some other special chars are escaped
|
||||
writeAndCompare(`foo="$ba\n\r\\r!"`, `foo="\$ba\n\r\\r\!"`)
|
||||
// lines should be sorted
|
||||
writeAndCompare("foo=bar\nbaz=buzz", "baz=\"buzz\"\nfoo=\"bar\"")
|
||||
}
|
||||
|
||||
func TestRoundtrip(t *testing.T) {
|
||||
fixtures := []string{"equals.env", "exported.env", "plain.env", "quoted.env"}
|
||||
for _, fixture := range fixtures {
|
||||
fixtureFilename := fmt.Sprintf("fixtures/%s", fixture)
|
||||
env, err := readFile(fixtureFilename)
|
||||
if err != nil {
|
||||
t.Errorf("Expected '%s' to read without error (%v)", fixtureFilename, err)
|
||||
}
|
||||
rep, err := Marshal(env)
|
||||
if err != nil {
|
||||
t.Errorf("Expected '%s' to Marshal (%v)", fixtureFilename, err)
|
||||
}
|
||||
roundtripped, err := Unmarshal(rep)
|
||||
if err != nil {
|
||||
t.Errorf("Expected '%s' to Mashal and Unmarshal (%v)", fixtureFilename, err)
|
||||
}
|
||||
if !reflect.DeepEqual(env, roundtripped) {
|
||||
t.Errorf("Expected '%s' to roundtrip as '%v', got '%v' instead", fixtureFilename, env, roundtripped)
|
||||
}
|
||||
}
|
||||
}
|
||||
3
plugins/config/vendor/github.com/ryanuber/columnize/.travis.yml
generated
vendored
3
plugins/config/vendor/github.com/ryanuber/columnize/.travis.yml
generated
vendored
@@ -1,3 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- tip
|
||||
20
plugins/config/vendor/github.com/ryanuber/columnize/LICENSE
generated
vendored
20
plugins/config/vendor/github.com/ryanuber/columnize/LICENSE
generated
vendored
@@ -1,20 +0,0 @@
|
||||
Copyright (c) 2016 Ryan Uber
|
||||
|
||||
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.
|
||||
71
plugins/config/vendor/github.com/ryanuber/columnize/README.md
generated
vendored
71
plugins/config/vendor/github.com/ryanuber/columnize/README.md
generated
vendored
@@ -1,71 +0,0 @@
|
||||
Columnize
|
||||
=========
|
||||
|
||||
Easy column-formatted output for golang
|
||||
|
||||
[](https://travis-ci.org/ryanuber/columnize)
|
||||
[](https://godoc.org/github.com/ryanuber/columnize)
|
||||
|
||||
Columnize is a really small Go package that makes building CLI's a little bit
|
||||
easier. In some CLI designs, you want to output a number similar items in a
|
||||
human-readable way with nicely aligned columns. However, figuring out how wide
|
||||
to make each column is a boring problem to solve and eats your valuable time.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ryanuber/columnize"
|
||||
)
|
||||
|
||||
func main() {
|
||||
output := []string{
|
||||
"Name | Gender | Age",
|
||||
"Bob | Male | 38",
|
||||
"Sally | Female | 26",
|
||||
}
|
||||
result := columnize.SimpleFormat(output)
|
||||
fmt.Println(result)
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, you just pass in a list of strings. And the result:
|
||||
|
||||
```
|
||||
Name Gender Age
|
||||
Bob Male 38
|
||||
Sally Female 26
|
||||
```
|
||||
|
||||
Columnize is tolerant of missing or empty fields, or even empty lines, so
|
||||
passing in extra lines for spacing should show up as you would expect.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Columnize is configured using a `Config`, which can be obtained by calling the
|
||||
`DefaultConfig()` method. You can then tweak the settings in the resulting
|
||||
`Config`:
|
||||
|
||||
```
|
||||
config := columnize.DefaultConfig()
|
||||
config.Delim = "|"
|
||||
config.Glue = " "
|
||||
config.Prefix = ""
|
||||
config.Empty = ""
|
||||
config.NoTrim = false
|
||||
```
|
||||
|
||||
* `Delim` is the string by which columns of **input** are delimited
|
||||
* `Glue` is the string by which columns of **output** are delimited
|
||||
* `Prefix` is a string by which each line of **output** is prefixed
|
||||
* `Empty` is a string used to replace blank values found in output
|
||||
* `NoTrim` is a boolean used to disable the automatic trimming of input values
|
||||
|
||||
You can then pass the `Config` in using the `Format` method (signature below) to
|
||||
have text formatted to your liking.
|
||||
|
||||
See the [godoc](https://godoc.org/github.com/ryanuber/columnize) page for usage.
|
||||
191
plugins/config/vendor/github.com/ryanuber/columnize/columnize.go
generated
vendored
191
plugins/config/vendor/github.com/ryanuber/columnize/columnize.go
generated
vendored
@@ -1,191 +0,0 @@
|
||||
package columnize
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Config can be used to tune certain parameters which affect the way
|
||||
// in which Columnize will format output text.
|
||||
type Config struct {
|
||||
// The string by which the lines of input will be split.
|
||||
Delim string
|
||||
|
||||
// The string by which columns of output will be separated.
|
||||
Glue string
|
||||
|
||||
// The string by which columns of output will be prefixed.
|
||||
Prefix string
|
||||
|
||||
// A replacement string to replace empty fields.
|
||||
Empty string
|
||||
|
||||
// NoTrim disables automatic trimming of inputs.
|
||||
NoTrim bool
|
||||
}
|
||||
|
||||
// DefaultConfig returns a *Config with default values.
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
Delim: "|",
|
||||
Glue: " ",
|
||||
Prefix: "",
|
||||
Empty: "",
|
||||
NoTrim: false,
|
||||
}
|
||||
}
|
||||
|
||||
// MergeConfig merges two config objects together and returns the resulting
|
||||
// configuration. Values from the right take precedence over the left side.
|
||||
func MergeConfig(a, b *Config) *Config {
|
||||
// Return quickly if either side was nil
|
||||
if a == nil {
|
||||
return b
|
||||
}
|
||||
if b == nil {
|
||||
return a
|
||||
}
|
||||
|
||||
var result Config = *a
|
||||
|
||||
if b.Delim != "" {
|
||||
result.Delim = b.Delim
|
||||
}
|
||||
if b.Glue != "" {
|
||||
result.Glue = b.Glue
|
||||
}
|
||||
if b.Prefix != "" {
|
||||
result.Prefix = b.Prefix
|
||||
}
|
||||
if b.Empty != "" {
|
||||
result.Empty = b.Empty
|
||||
}
|
||||
if b.NoTrim {
|
||||
result.NoTrim = true
|
||||
}
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
// stringFormat, given a set of column widths and the number of columns in
|
||||
// the current line, returns a sprintf-style format string which can be used
|
||||
// to print output aligned properly with other lines using the same widths set.
|
||||
func stringFormat(c *Config, widths []int, columns int) string {
|
||||
// Create the buffer with an estimate of the length
|
||||
buf := bytes.NewBuffer(make([]byte, 0, (6+len(c.Glue))*columns))
|
||||
|
||||
// Start with the prefix, if any was given. The buffer will not return an
|
||||
// error so it does not need to be handled
|
||||
buf.WriteString(c.Prefix)
|
||||
|
||||
// Create the format string from the discovered widths
|
||||
for i := 0; i < columns && i < len(widths); i++ {
|
||||
if i == columns-1 {
|
||||
buf.WriteString("%s\n")
|
||||
} else {
|
||||
fmt.Fprintf(buf, "%%-%ds%s", widths[i], c.Glue)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// elementsFromLine returns a list of elements, each representing a single
|
||||
// item which will belong to a column of output.
|
||||
func elementsFromLine(config *Config, line string) []interface{} {
|
||||
separated := strings.Split(line, config.Delim)
|
||||
elements := make([]interface{}, len(separated))
|
||||
for i, field := range separated {
|
||||
value := field
|
||||
if !config.NoTrim {
|
||||
value = strings.TrimSpace(field)
|
||||
}
|
||||
|
||||
// Apply the empty value, if configured.
|
||||
if value == "" && config.Empty != "" {
|
||||
value = config.Empty
|
||||
}
|
||||
elements[i] = value
|
||||
}
|
||||
return elements
|
||||
}
|
||||
|
||||
// runeLen calculates the number of visible "characters" in a string
|
||||
func runeLen(s string) int {
|
||||
l := 0
|
||||
for _ = range s {
|
||||
l++
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// widthsFromLines examines a list of strings and determines how wide each
|
||||
// column should be considering all of the elements that need to be printed
|
||||
// within it.
|
||||
func widthsFromLines(config *Config, lines []string) []int {
|
||||
widths := make([]int, 0, 8)
|
||||
|
||||
for _, line := range lines {
|
||||
elems := elementsFromLine(config, line)
|
||||
for i := 0; i < len(elems); i++ {
|
||||
l := runeLen(elems[i].(string))
|
||||
if len(widths) <= i {
|
||||
widths = append(widths, l)
|
||||
} else if widths[i] < l {
|
||||
widths[i] = l
|
||||
}
|
||||
}
|
||||
}
|
||||
return widths
|
||||
}
|
||||
|
||||
// Format is the public-facing interface that takes a list of strings and
|
||||
// returns nicely aligned column-formatted text.
|
||||
func Format(lines []string, config *Config) string {
|
||||
conf := MergeConfig(DefaultConfig(), config)
|
||||
widths := widthsFromLines(conf, lines)
|
||||
|
||||
// Estimate the buffer size
|
||||
glueSize := len(conf.Glue)
|
||||
var size int
|
||||
for _, w := range widths {
|
||||
size += w + glueSize
|
||||
}
|
||||
size *= len(lines)
|
||||
|
||||
// Create the buffer
|
||||
buf := bytes.NewBuffer(make([]byte, 0, size))
|
||||
|
||||
// Create a cache for the string formats
|
||||
fmtCache := make(map[int]string, 16)
|
||||
|
||||
// Create the formatted output using the format string
|
||||
for _, line := range lines {
|
||||
elems := elementsFromLine(conf, line)
|
||||
|
||||
// Get the string format using cache
|
||||
numElems := len(elems)
|
||||
stringfmt, ok := fmtCache[numElems]
|
||||
if !ok {
|
||||
stringfmt = stringFormat(conf, widths, numElems)
|
||||
fmtCache[numElems] = stringfmt
|
||||
}
|
||||
|
||||
fmt.Fprintf(buf, stringfmt, elems...)
|
||||
}
|
||||
|
||||
// Get the string result
|
||||
result := buf.String()
|
||||
|
||||
// Remove trailing newline without removing leading/trailing space
|
||||
if n := len(result); n > 0 && result[n-1] == '\n' {
|
||||
result = result[:n-1]
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// SimpleFormat is a convenience function to format text with the defaults.
|
||||
func SimpleFormat(lines []string) string {
|
||||
return Format(lines, nil)
|
||||
}
|
||||
340
plugins/config/vendor/github.com/ryanuber/columnize/columnize_test.go
generated
vendored
340
plugins/config/vendor/github.com/ryanuber/columnize/columnize_test.go
generated
vendored
@@ -1,340 +0,0 @@
|
||||
package columnize
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
crand "crypto/rand"
|
||||
)
|
||||
|
||||
func TestListOfStringsInput(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A | Column B | Column C",
|
||||
"x | y | z",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
output := Format(input, config)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "x y z"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyLinesOutput(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A | Column B | Column C",
|
||||
"",
|
||||
"x | y | z",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
output := Format(input, config)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "\n"
|
||||
expected += "x y z"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLeadingSpacePreserved(t *testing.T) {
|
||||
input := []string{
|
||||
"| Column B | Column C",
|
||||
"x | y | z",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
output := Format(input, config)
|
||||
|
||||
expected := " Column B Column C\n"
|
||||
expected += "x y z"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestColumnWidthCalculator(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A | Column B | Column C",
|
||||
"Longer than A | Longer than B | Longer than C",
|
||||
"short | short | short",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
output := Format(input, config)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "Longer than A Longer than B Longer than C\n"
|
||||
expected += "short short short"
|
||||
|
||||
if output != expected {
|
||||
printableProof := fmt.Sprintf("\nGot: %+q", output)
|
||||
printableProof += fmt.Sprintf("\nExpected: %+q", expected)
|
||||
t.Fatalf("\n%s", printableProof)
|
||||
}
|
||||
}
|
||||
|
||||
func TestColumnWidthCalculatorNonASCII(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A | Column B | Column C",
|
||||
"⌘⌘⌘⌘⌘⌘⌘⌘ | Longer than B | Longer than C",
|
||||
"short | short | short",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
output := Format(input, config)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "⌘⌘⌘⌘⌘⌘⌘⌘ Longer than B Longer than C\n"
|
||||
expected += "short short short"
|
||||
|
||||
if output != expected {
|
||||
printableProof := fmt.Sprintf("\nGot: %+q", output)
|
||||
printableProof += fmt.Sprintf("\nExpected: %+q", expected)
|
||||
t.Fatalf("\n%s", printableProof)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkColumnWidthCalculator(b *testing.B) {
|
||||
// Generate the input
|
||||
input := []string{
|
||||
"UUID A | UUID B | UUID C | Column D | Column E",
|
||||
}
|
||||
|
||||
format := "%s|%s|%s|%s"
|
||||
short := "short"
|
||||
|
||||
uuid := func() string {
|
||||
buf := make([]byte, 16)
|
||||
if _, err := crand.Read(buf); err != nil {
|
||||
panic(fmt.Errorf("failed to read random bytes: %v", err))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x",
|
||||
buf[0:4],
|
||||
buf[4:6],
|
||||
buf[6:8],
|
||||
buf[8:10],
|
||||
buf[10:16])
|
||||
}
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
l := fmt.Sprintf(format, uuid()[:8], uuid()[:12], uuid(), short, short)
|
||||
input = append(input, l)
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
Format(input, config)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVariedInputSpacing(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A |Column B| Column C",
|
||||
"x|y| z",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
output := Format(input, config)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "x y z"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVariedInputSpacing_NoTrim(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A|Column B|Column C",
|
||||
"x|y| z",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
config.NoTrim = true
|
||||
output := Format(input, config)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "x y z"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmatchedColumnCounts(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A | Column B | Column C",
|
||||
"Value A | Value B",
|
||||
"Value A | Value B | Value C | Value D",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
output := Format(input, config)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "Value A Value B\n"
|
||||
expected += "Value A Value B Value C Value D"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlternateDelimiter(t *testing.T) {
|
||||
input := []string{
|
||||
"Column | A % Column | B % Column | C",
|
||||
"Value A % Value B % Value C",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
config.Delim = "%"
|
||||
output := Format(input, config)
|
||||
|
||||
expected := "Column | A Column | B Column | C\n"
|
||||
expected += "Value A Value B Value C"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlternateSpacingString(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A | Column B | Column C",
|
||||
"x | y | z",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
config.Glue = " "
|
||||
output := Format(input, config)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "x y z"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleFormat(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A | Column B | Column C",
|
||||
"x | y | z",
|
||||
}
|
||||
|
||||
output := SimpleFormat(input)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "x y z"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlternatePrefixString(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A | Column B | Column C",
|
||||
"x | y | z",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
config.Prefix = " "
|
||||
output := Format(input, config)
|
||||
|
||||
expected := " Column A Column B Column C\n"
|
||||
expected += " x y z"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyFieldReplacement(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A | Column B | Column C",
|
||||
"x | | z",
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
config.Empty = "<none>"
|
||||
output := Format(input, config)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "x <none> z"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyConfigValues(t *testing.T) {
|
||||
input := []string{
|
||||
"Column A | Column B | Column C",
|
||||
"x | y | z",
|
||||
}
|
||||
|
||||
config := Config{}
|
||||
output := Format(input, &config)
|
||||
|
||||
expected := "Column A Column B Column C\n"
|
||||
expected += "x y z"
|
||||
|
||||
if output != expected {
|
||||
t.Fatalf("\nexpected:\n%s\n\ngot:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeConfig(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
desc string
|
||||
configA *Config
|
||||
configB *Config
|
||||
expect *Config
|
||||
}{
|
||||
{
|
||||
"merges b over a",
|
||||
&Config{Delim: "a", Glue: "a", Prefix: "a", Empty: "a"},
|
||||
&Config{Delim: "b", Glue: "b", Prefix: "b", Empty: "b"},
|
||||
&Config{Delim: "b", Glue: "b", Prefix: "b", Empty: "b"},
|
||||
},
|
||||
{
|
||||
"merges only non-empty config values",
|
||||
&Config{Delim: "a", Glue: "a", Prefix: "a", Empty: "a"},
|
||||
&Config{Delim: "b", Prefix: "b"},
|
||||
&Config{Delim: "b", Glue: "a", Prefix: "b", Empty: "a"},
|
||||
},
|
||||
{
|
||||
"takes b if a is nil",
|
||||
nil,
|
||||
&Config{Delim: "b", Glue: "b", Prefix: "b", Empty: "b"},
|
||||
&Config{Delim: "b", Glue: "b", Prefix: "b", Empty: "b"},
|
||||
},
|
||||
{
|
||||
"takes a if b is nil",
|
||||
&Config{Delim: "a", Glue: "a", Prefix: "a", Empty: "a"},
|
||||
nil,
|
||||
&Config{Delim: "a", Glue: "a", Prefix: "a", Empty: "a"},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
m := MergeConfig(tc.configA, tc.configB)
|
||||
if !reflect.DeepEqual(m, tc.expect) {
|
||||
t.Fatalf("\nexpect:\n%#v\n\nactual:\n%#v", tc.expect, m)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user