From 96f4ceb3b698de47d874838e27e1ed4a8f4efaf1 Mon Sep 17 00:00:00 2001 From: Clara Fu Date: Thu, 15 Apr 2021 10:32:10 -0400 Subject: [PATCH] modify all custom types to enable yaml unmarshaling With concourse converting to starting up with a config file, we no longer use go-flags to unmarshal into these custom types but now it uses yaml unmarshalling. So I converted all the flags to have custom yaml unmarshallers. I also added yaml marshalers because I want to support generating a config file from an existing configuration struct. This can be useful to help users migrate from deploying with flags to a config file, without needing users to write up a config file from scratch. It can also be helpful for giving users their most up-to-date configuration field values. Lastly, this commit also adds support for three methods, Set, String and Type. These are used by cobra in order to support a custom type being used in parsing flags. Once we fully deprecate flags, we can delete these methods. [concourse/concourse#6434] Signed-off-by: Clara Fu --- authorized_keys.go | 109 ++++++++++++++++++++++++++++++++++++++++++--- cipher.go | 42 +++++++++++++++-- directory.go | 41 +++++++++++++++-- file.go | 74 ++++++++++++++++++++++++++++-- go.mod | 12 +++++ go.sum | 88 ++++++++++++++++++++++++++++++++++++ ip.go | 39 ++++++++++++++-- lager.go | 9 +++- postgres_config.go | 22 ++++----- private_key.go | 43 ++++++++++++++++-- url.go | 81 ++++++++++++++++++++++++++++----- url_test.go | 52 --------------------- 12 files changed, 514 insertions(+), 98 deletions(-) create mode 100644 go.mod create mode 100644 go.sum delete mode 100644 url_test.go diff --git a/authorized_keys.go b/authorized_keys.go index fba808d..0da9180 100644 --- a/authorized_keys.go +++ b/authorized_keys.go @@ -5,14 +5,102 @@ import ( "io/ioutil" "golang.org/x/crypto/ssh" + "gopkg.in/yaml.v2" ) +type AuthorizedKeysMap map[string]AuthorizedKeys + +// Can be removed once flags are deprecated +func (a AuthorizedKeysMap) Set(value string) error { + authorizedKeyPaths := make(map[string]string) + err := yaml.Unmarshal([]byte(value), &authorizedKeyPaths) + if err != nil { + return err + } + + if authorizedKeyPaths != nil { + return a.set(authorizedKeyPaths) + } + + return nil +} + +// Can be removed once flags are deprecated +func (a AuthorizedKeysMap) String() string { + if a == nil { + return "" + } + + authorizedKeysString, _ := a.convertToString() + return authorizedKeysString +} + +// Can be removed once flags are deprecated +func (a AuthorizedKeysMap) Type() string { + return "AuthorizedKeysMap" +} + +func (a AuthorizedKeysMap) convertToString() (string, error) { + authorizedKeysPaths := make(map[string]string) + for key, authorizedKey := range a { + authorizedKeysPaths[key] = authorizedKey.File + } + + authorizedKeysString, err := yaml.Marshal(authorizedKeysPaths) + if err != nil { + return "", err + } + + return string(authorizedKeysString), nil +} + +func (a *AuthorizedKeysMap) set(value map[string]string) error { + authorizedKeysMap := make(AuthorizedKeysMap) + for key, authorizedKeyPath := range value { + var authorizedKeys AuthorizedKeys + err := authorizedKeys.Set(authorizedKeyPath) + if err != nil { + return err + } + + authorizedKeysMap[key] = authorizedKeys + } + + a = &authorizedKeysMap + + return nil +} + type AuthorizedKeys struct { File string Keys []ssh.PublicKey } -func (f *AuthorizedKeys) UnmarshalFlag(value string) error { +// Reload reloads the value of the Keys +func (a *AuthorizedKeys) Reload() error { + return a.Set(a.File) +} + +func (a AuthorizedKeys) MarshalYAML() (interface{}, error) { + return a.File, nil +} + +func (a *AuthorizedKeys) UnmarshalYAML(unmarshal func(interface{}) error) error { + var path string + err := unmarshal(&path) + if err != nil { + return err + } + + if path != "" { + return a.Set(path) + } + + return nil +} + +// Can be removed once flags are deprecated +func (a *AuthorizedKeys) Set(value string) error { authorizedKeysBytes, err := ioutil.ReadFile(value) if err != nil { return fmt.Errorf("failed to read authorized keys: %s", err) @@ -32,13 +120,22 @@ func (f *AuthorizedKeys) UnmarshalFlag(value string) error { authorizedKeysBytes = rest } - f.File = value - f.Keys = authorizedKeys + a.File = value + a.Keys = authorizedKeys return nil } -// Reload reloads the value of the Keys -func (f *AuthorizedKeys) Reload() error { - return f.UnmarshalFlag(f.File) +// Can be removed once flags are deprecated +func (a *AuthorizedKeys) String() string { + if a == nil { + return "" + } + + return a.File +} + +// Can be removed once flags are deprecated +func (a *AuthorizedKeys) Type() string { + return "AuthorizedKeys" } diff --git a/cipher.go b/cipher.go index d20e733..b2a877b 100644 --- a/cipher.go +++ b/cipher.go @@ -8,18 +8,54 @@ import ( type Cipher struct { cipher.AEAD + originalCipher string } -func (flag *Cipher) UnmarshalFlag(val string) error { - block, err := aes.NewCipher([]byte(val)) +func (c Cipher) MarshalYAML() (interface{}, error) { + return c.originalCipher, nil +} + +func (c *Cipher) UnmarshalYAML(unmarshal func(interface{}) error) error { + var value string + err := unmarshal(&value) + if err != nil { + return err + } + + if value != "" { + return c.Set(value) + } + + return nil +} + +// Can be removed once flags are deprecated +func (c *Cipher) Set(value string) error { + block, err := aes.NewCipher([]byte(value)) if err != nil { return fmt.Errorf("failed to construct AES cipher: %s", err) } - flag.AEAD, err = cipher.NewGCM(block) + c.AEAD, err = cipher.NewGCM(block) if err != nil { return fmt.Errorf("failed to construct GCM: %s", err) } + c.originalCipher = value + return nil } + +// Can be removed once flags are deprecated +func (c *Cipher) String() string { + if c == nil { + return "" + } + + return c.originalCipher +} + +// Can be removed once flags are deprecated +func (c *Cipher) Type() string { + return "AEAD" +} diff --git a/directory.go b/directory.go index d6f18e8..f4e064f 100644 --- a/directory.go +++ b/directory.go @@ -8,7 +8,26 @@ import ( type Dir string -func (f *Dir) UnmarshalFlag(value string) error { +func (d Dir) MarshalYAML() (interface{}, error) { + return string(d), nil +} + +func (d *Dir) UnmarshalYAML(unmarshal func(interface{}) error) error { + var value string + err := unmarshal(&value) + if err != nil { + return err + } + + if value != "" { + return d.Set(value) + } + + return nil +} + +// Can be removed once flags are deprecated +func (d *Dir) Set(value string) error { stat, err := os.Stat(value) if err == nil { if !stat.IsDir() { @@ -21,11 +40,25 @@ func (f *Dir) UnmarshalFlag(value string) error { return err } - *f = Dir(abs) + *d = Dir(abs) return nil } -func (f Dir) Path() string { - return string(f) +// Can be removed once flags are deprecated +func (d *Dir) String() string { + if d == nil { + return "" + } + + return string(*d) +} + +// Can be removed once flags are deprecated +func (d *Dir) Type() string { + return "Dir" +} + +func (d *Dir) Path() string { + return string(*d) } diff --git a/file.go b/file.go index 0e74369..fb13cbc 100644 --- a/file.go +++ b/file.go @@ -4,11 +4,65 @@ import ( "fmt" "os" "path/filepath" + "strings" ) +type Files []File + +// Can be removed once flags are deprecated +func (f *Files) Set(value string) error { + unparsedFiles := strings.Split(value, ",") + + var parsedFiles Files + for _, unparsedFile := range unparsedFiles { + var file File + err := file.Set(strings.TrimSpace(unparsedFile)) + if err != nil { + return err + } + + parsedFiles = append(parsedFiles, file) + } + + return nil +} + +// Can be removed once flags are deprecated +func (f *Files) String() string { + if f == nil { + return "" + } + + return fmt.Sprintf("%v", *f) +} + +// Can be removed once flags are deprecated +func (f *Files) Type() string { + return "Files" +} + type File string -func (f *File) UnmarshalFlag(value string) error { +func (f File) MarshalYAML() (interface{}, error) { + return string(f), nil +} + +func (f *File) UnmarshalYAML(unmarshal func(interface{}) error) error { + var value string + err := unmarshal(&value) + if err != nil { + return err + } + + if value != "" { + return f.Set(value) + } + + return nil +} + +// Can be removed once flags are deprecated +func (f *File) Set(value string) error { stat, err := os.Stat(value) if err != nil { return err @@ -28,6 +82,20 @@ func (f *File) UnmarshalFlag(value string) error { return nil } -func (f File) Path() string { - return string(f) +// Can be removed once flags are deprecated +func (f *File) String() string { + if f == nil { + return "" + } + + return string(*f) +} + +// Can be removed once flags are deprecated +func (f *File) Type() string { + return "File" +} + +func (f *File) Path() string { + return string(*f) } diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d14bbb5 --- /dev/null +++ b/go.mod @@ -0,0 +1,12 @@ +module github.com/concourse/flag + +go 1.16 + +require ( + code.cloudfoundry.org/lager v2.0.0+incompatible + github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/onsi/ginkgo v1.15.2 + github.com/onsi/gomega v1.11.0 + golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 + gopkg.in/yaml.v2 v2.4.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..6b8d139 --- /dev/null +++ b/go.sum @@ -0,0 +1,88 @@ +code.cloudfoundry.org/lager v2.0.0+incompatible h1:WZwDKDB2PLd/oL+USK4b4aEjUymIej9My2nUQ9oWEwQ= +code.cloudfoundry.org/lager v2.0.0+incompatible/go.mod h1:O2sS7gKP3HM2iemG+EnwvyNQK7pTSC6Foi4QiMp9sSk= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +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/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +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/ginkgo v1.15.2 h1:l77YT15o814C2qVL47NOyjV/6RbaP7kKdrvZnxQ3Org= +github.com/onsi/ginkgo v1.15.2/go.mod h1:Dd6YFfwBW84ETqqtL0CPyPXillHgY6XhQH3uuCCTr/o= +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/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug= +github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/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/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +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= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/ip.go b/ip.go index fd5557e..9e8a1a3 100644 --- a/ip.go +++ b/ip.go @@ -9,13 +9,46 @@ type IP struct { net.IP } -func (f *IP) UnmarshalFlag(value string) error { +func (i IP) MarshalYAML() (interface{}, error) { + return i.String(), nil +} + +func (i *IP) UnmarshalYAML(unmarshal func(interface{}) error) error { + var value string + err := unmarshal(&value) + if err != nil { + return err + } + + if value != "" { + return i.Set(value) + } + + return nil +} + +// Can be removed once flags are deprecated +func (i *IP) Set(value string) error { parsedIP := net.ParseIP(value) if parsedIP == nil { - return fmt.Errorf("invalid IP: '%s'", value) + return fmt.Errorf("parse IP: '%s'", i) } - f.IP = parsedIP + i.IP = parsedIP return nil } + +// Can be removed once flags are deprecated +func (i *IP) String() string { + if i == nil || i.IP == nil { + return "" + } + + return i.String() +} + +// Can be removed once flags are deprecated +func (i *IP) Type() string { + return "IP" +} diff --git a/lager.go b/lager.go index 7cf872d..84ebf2e 100644 --- a/lager.go +++ b/lager.go @@ -15,8 +15,15 @@ const ( LogLevelFatal = "fatal" ) +var ValidLogLevels = []string{ + LogLevelDebug, + LogLevelInfo, + LogLevelError, + LogLevelFatal, +} + type Lager struct { - LogLevel string `long:"log-level" default:"info" choice:"debug" choice:"info" choice:"error" choice:"fatal" description:"Minimum level of logs to see."` + LogLevel string `yaml:"log_level,omitempty" validate:"log_level" env:"CONCOURSE_WORKER_GATEWAY_LOG_LEVEL,CONCOURSE_TSA_LOG_LEVEL"` writerSink io.Writer } diff --git a/postgres_config.go b/postgres_config.go index 86ef011..0926015 100644 --- a/postgres_config.go +++ b/postgres_config.go @@ -10,22 +10,22 @@ import ( ) type PostgresConfig struct { - Host string `long:"host" description:"The host to connect to." default:"127.0.0.1"` - Port uint16 `long:"port" description:"The port to connect to." default:"5432"` + Host string `yaml:"host,omitempty"` + Port uint16 `yaml:"port,omitempty"` - Socket string `long:"socket" description:"Path to a UNIX domain socket to connect to."` + Socket string `yaml:"socket,omitempty"` - User string `long:"user" description:"The user to sign in as."` - Password string `long:"password" description:"The user's password."` + User string `yaml:"user,omitempty"` + Password string `yaml:"password,omitempty"` - SSLMode string `long:"sslmode" description:"Whether or not to use SSL." default:"disable" choice:"disable" choice:"require" choice:"verify-ca" choice:"verify-full"` - CACert File `long:"ca-cert" description:"CA cert file location, to verify when connecting with SSL."` - ClientCert File `long:"client-cert" description:"Client cert file location."` - ClientKey File `long:"client-key" description:"Client key file location."` + SSLMode string `yaml:"sslmode,omitempty"` + CACert File `yaml:"ca_cert,omitempty"` + ClientCert File `yaml:"client_cert,omitempty"` + ClientKey File `yaml:"client_key,omitempty"` - ConnectTimeout time.Duration `long:"connect-timeout" description:"Dialing timeout. (0 means wait indefinitely)" default:"5m"` + ConnectTimeout time.Duration `yaml:"connect_timeout,omitempty"` - Database string `long:"database" description:"The name of the database to use." default:"atc"` + Database string `yaml:"database,omitempty"` } func (config PostgresConfig) ConnectionString() string { diff --git a/private_key.go b/private_key.go index 5add2a7..c6f9a2e 100644 --- a/private_key.go +++ b/private_key.go @@ -10,12 +10,32 @@ import ( type PrivateKey struct { *rsa.PrivateKey + originalKey string } -func (f *PrivateKey) UnmarshalFlag(path string) error { - rsaKeyBlob, err := ioutil.ReadFile(path) +func (p PrivateKey) MarshalYAML() (interface{}, error) { + return p.originalKey, nil +} + +func (p *PrivateKey) UnmarshalYAML(unmarshal func(interface{}) error) error { + var value string + err := unmarshal(&value) if err != nil { - return fmt.Errorf("failed to read private key file (%s): %s", path, err) + return err + } + + if value != "" { + return p.Set(value) + } + + return nil +} + +// Can be removed once flags are deprecated +func (p *PrivateKey) Set(value string) error { + rsaKeyBlob, err := ioutil.ReadFile(value) + if err != nil { + return fmt.Errorf("failed to read private key file (%s): %s", value, err) } key, err := jwt.ParseRSAPrivateKeyFromPEM(rsaKeyBlob) @@ -23,7 +43,22 @@ func (f *PrivateKey) UnmarshalFlag(path string) error { return err } - f.PrivateKey = key + p.originalKey = value + p.PrivateKey = key return nil } + +// Can be removed once flags are deprecated +func (p *PrivateKey) String() string { + if p == nil { + return "" + } + + return p.originalKey +} + +// Can be removed once flags are deprecated +func (p *PrivateKey) Type() string { + return "PrivateKey" +} diff --git a/url.go b/url.go index a723fe7..554252b 100644 --- a/url.go +++ b/url.go @@ -6,22 +6,79 @@ import ( "strings" ) +type URLs []URL + +// Can be removed once flags are deprecated +func (u *URLs) Set(value string) error { + unparsedURLs := strings.Split(value, ",") + + var parsedURLs URLs + for _, unparsedURL := range unparsedURLs { + urlVal := strings.TrimRight(strings.TrimSpace(unparsedURL), "/") + parsedURL, err := url.Parse(urlVal) + if err != nil { + return err + } + + parsedURLs = append(parsedURLs, URL{parsedURL}) + } + + u = &parsedURLs + + return nil +} + +// Can be removed once flags are deprecated +func (u *URLs) String() string { + if u == nil { + return "" + } + + var urlsString string + for _, parsedURL := range *u { + urlsString = fmt.Sprintf("%s,%s", urlsString, parsedURL.String()) + } + + return urlsString +} + +// Can be removed once flags are deprecated +func (u *URLs) Type() string { + return "URLs" +} + type URL struct { *url.URL } -func (u *URL) UnmarshalFlag(value string) error { - value = normalizeURL(value) - parsedURL, err := url.Parse(value) +func (u URL) MarshalYAML() (interface{}, error) { + if u.URL == nil { + return "", nil + } + + return u.URL.String(), nil +} +func (u *URL) UnmarshalYAML(unmarshal func(interface{}) error) error { + var value string + err := unmarshal(&value) if err != nil { return err } - // localhost URLs that do not start with http:// are interpreted - // with `localhost` as the Scheme, not the Host - if parsedURL.Scheme == "" || parsedURL.Host == "" { - return fmt.Errorf("missing scheme in '%s'", value) + if value != "" { + return u.Set(value) + } + + return nil +} + +// Can be removed once flags are deprecated +func (u *URL) Set(value string) error { + value = strings.TrimRight(value, "/") + parsedURL, err := url.Parse(value) + if err != nil { + return err } u.URL = parsedURL @@ -29,14 +86,16 @@ func (u *URL) UnmarshalFlag(value string) error { return nil } -func (u URL) String() string { - if u.URL == nil { +// Can be removed once flags are deprecated +func (u *URL) String() string { + if u == nil || u.URL == nil { return "" } return u.URL.String() } -func normalizeURL(urlIn string) string { - return strings.TrimRight(urlIn, "/") +// Can be removed once flags are deprecated +func (u *URL) Type() string { + return "URL" } diff --git a/url_test.go b/url_test.go deleted file mode 100644 index 8323c95..0000000 --- a/url_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package flag_test - -import ( - "github.com/concourse/flag" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("URLFlag", func() { - It("strips slashes from the end of urls", func() { - flag := flag.URL{} - - err := flag.UnmarshalFlag("http://example.com/") - Expect(err).ToNot(HaveOccurred()) - - Expect(flag.String()).To(Equal("http://example.com")) - }) - - It("doesn't strip anything from urls with no slashes", func() { - flag := flag.URL{} - - err := flag.UnmarshalFlag("https://example.com") - Expect(err).ToNot(HaveOccurred()) - - Expect(flag.String()).To(Equal("https://example.com")) - }) - - It("returns an error when a scheme is not specified", func() { - flag := flag.URL{} - - err := flag.UnmarshalFlag("example.com/") - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(Equal("missing scheme in 'example.com'")) - }) - - It("returns an error for localhost without scheme", func() { - flag := flag.URL{} - - err := flag.UnmarshalFlag("localhost:8080") - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(Equal("missing scheme in 'localhost:8080'")) - }) - - It("unmarshalls localhost with scheme correctly", func() { - flag := flag.URL{} - - err := flag.UnmarshalFlag("http://localhost:8080") - Expect(err).ToNot(HaveOccurred()) - - Expect(flag.String()).To(Equal("http://localhost:8080")) - }) -})