Merge branch 'v1.5' into master
This commit is contained in:
commit
a2db3e0499
18 changed files with 684 additions and 486 deletions
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -1,5 +1,27 @@
|
|||
# Change Log
|
||||
|
||||
## [v1.5.3](https://github.com/containous/traefik/tree/v1.5.3) (2018-02-27)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.2...v1.5.3)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** Check all the C/N and SANs of provided certificates before generating ACME certificates ([#2913](https://github.com/containous/traefik/pull/2913) by [nmengin](https://github.com/nmengin))
|
||||
- **[docker/swarm]** Empty IP address when use endpoint mode dnsrr ([#2887](https://github.com/containous/traefik/pull/2887) by [mmatur](https://github.com/mmatur))
|
||||
- **[middleware]** Infinite entry point redirection. ([#2929](https://github.com/containous/traefik/pull/2929) by [ldez](https://github.com/ldez))
|
||||
- **[provider]** Isolate backend with same name on different provider ([#2862](https://github.com/containous/traefik/pull/2862) by [Juliens](https://github.com/Juliens))
|
||||
- **[tls]** Starting Træfik even if TLS certificates are in error ([#2909](https://github.com/containous/traefik/pull/2909) by [nmengin](https://github.com/nmengin))
|
||||
- **[tls]** Add DEBUG log when no provided certificate can check a domain ([#2938](https://github.com/containous/traefik/pull/2938) by [nmengin](https://github.com/nmengin))
|
||||
- **[webui]** Smooth dashboard refresh. ([#2871](https://github.com/containous/traefik/pull/2871) by [ldez](https://github.com/ldez))
|
||||
- Fix Duration JSON unmarshal ([#2935](https://github.com/containous/traefik/pull/2935) by [ldez](https://github.com/ldez))
|
||||
- Default value for lifecycle ([#2934](https://github.com/containous/traefik/pull/2934) by [Juliens](https://github.com/Juliens))
|
||||
- Check ping configuration. ([#2852](https://github.com/containous/traefik/pull/2852) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Documentation:**
|
||||
- **[docker]** it's -> its ([#2901](https://github.com/containous/traefik/pull/2901) by [piec](https://github.com/piec))
|
||||
- **[tls]** Fix doc cipher suites ([#2894](https://github.com/containous/traefik/pull/2894) by [emilevauge](https://github.com/emilevauge))
|
||||
- Add a CLI help command for Docker. ([#2921](https://github.com/containous/traefik/pull/2921) by [ldez](https://github.com/ldez))
|
||||
- Fix traffic pronounce dead link ([#2870](https://github.com/containous/traefik/pull/2870) by [emilevauge](https://github.com/emilevauge))
|
||||
- Update documentation on onHostRule, ping examples, and web deprecation ([#2863](https://github.com/containous/traefik/pull/2863) by [Juliens](https://github.com/Juliens))
|
||||
|
||||
## [v1.5.2](https://github.com/containous/traefik/tree/v1.5.2) (2018-02-12)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.1...v1.5.2)
|
||||
|
||||
|
|
9
Gopkg.lock
generated
9
Gopkg.lock
generated
|
@ -225,9 +225,12 @@
|
|||
|
||||
[[projects]]
|
||||
name = "github.com/containous/flaeg"
|
||||
packages = ["."]
|
||||
revision = "60c87a513a955ca7225e1b1c772581cea8420cb4"
|
||||
version = "v1.0.1"
|
||||
packages = [
|
||||
".",
|
||||
"parse"
|
||||
]
|
||||
revision = "963366c29a7acc2d6e02f4f9bcf260d5a1cf4968"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
|
|
@ -222,6 +222,24 @@ func (dc *DomainsCertificates) exists(domainToFind Domain) (*DomainsCertificate,
|
|||
return nil, false
|
||||
}
|
||||
|
||||
func (dc *DomainsCertificates) toDomainsMap() map[string]*tls.Certificate {
|
||||
domainsCertificatesMap := make(map[string]*tls.Certificate)
|
||||
for _, domainCertificate := range dc.Certs {
|
||||
certKey := domainCertificate.Domains.Main
|
||||
if domainCertificate.Domains.SANs != nil {
|
||||
sort.Strings(domainCertificate.Domains.SANs)
|
||||
for _, dnsName := range domainCertificate.Domains.SANs {
|
||||
if dnsName != domainCertificate.Domains.Main {
|
||||
certKey += fmt.Sprintf(",%s", dnsName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
domainsCertificatesMap[certKey] = domainCertificate.tlsCert
|
||||
}
|
||||
return domainsCertificatesMap
|
||||
}
|
||||
|
||||
// DomainsCertificate contains a certificate for multiple domains
|
||||
type DomainsCertificate struct {
|
||||
Domains Domain
|
||||
|
|
118
acme/acme.go
118
acme/acme.go
|
@ -391,7 +391,7 @@ func (a *ACME) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificat
|
|||
domain := types.CanonicalDomain(clientHello.ServerName)
|
||||
account := a.store.Get().(*Account)
|
||||
|
||||
if providedCertificate := a.getProvidedCertificate([]string{domain}); providedCertificate != nil {
|
||||
if providedCertificate := a.getProvidedCertificate(domain); providedCertificate != nil {
|
||||
return providedCertificate, nil
|
||||
}
|
||||
|
||||
|
@ -625,11 +625,6 @@ func (a *ACME) LoadCertificateForDomains(domains []string) {
|
|||
|
||||
domains = fun.Map(types.CanonicalDomain, domains).([]string)
|
||||
|
||||
// Check provided certificates
|
||||
if a.getProvidedCertificate(domains) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
operation := func() error {
|
||||
if a.client == nil {
|
||||
return errors.New("ACME client still not built")
|
||||
|
@ -647,32 +642,34 @@ func (a *ACME) LoadCertificateForDomains(domains []string) {
|
|||
return
|
||||
}
|
||||
account := a.store.Get().(*Account)
|
||||
var domain Domain
|
||||
if len(domains) > 1 {
|
||||
domain = Domain{Main: domains[0], SANs: domains[1:]}
|
||||
} else {
|
||||
domain = Domain{Main: domains[0]}
|
||||
}
|
||||
if _, exists := account.DomainsCertificate.exists(domain); exists {
|
||||
// domain already exists
|
||||
|
||||
// Check provided certificates
|
||||
uncheckedDomains := a.getUncheckedDomains(domains, account)
|
||||
if len(uncheckedDomains) == 0 {
|
||||
return
|
||||
}
|
||||
certificate, err := a.getDomainsCertificates(domains)
|
||||
certificate, err := a.getDomainsCertificates(uncheckedDomains)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting ACME certificates %+v : %v", domains, err)
|
||||
log.Errorf("Error getting ACME certificates %+v : %v", uncheckedDomains, err)
|
||||
return
|
||||
}
|
||||
log.Debugf("Got certificate for domains %+v", domains)
|
||||
log.Debugf("Got certificate for domains %+v", uncheckedDomains)
|
||||
transaction, object, err := a.store.Begin()
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Error creating transaction %+v : %v", domains, err)
|
||||
log.Errorf("Error creating transaction %+v : %v", uncheckedDomains, err)
|
||||
return
|
||||
}
|
||||
var domain Domain
|
||||
if len(uncheckedDomains) > 1 {
|
||||
domain = Domain{Main: uncheckedDomains[0], SANs: uncheckedDomains[1:]}
|
||||
} else {
|
||||
domain = Domain{Main: uncheckedDomains[0]}
|
||||
}
|
||||
account = object.(*Account)
|
||||
_, err = account.DomainsCertificate.addCertificateForDomains(certificate, domain)
|
||||
if err != nil {
|
||||
log.Errorf("Error adding ACME certificates %+v : %v", domains, err)
|
||||
log.Errorf("Error adding ACME certificates %+v : %v", uncheckedDomains, err)
|
||||
return
|
||||
}
|
||||
if err = transaction.Commit(account); err != nil {
|
||||
|
@ -684,36 +681,95 @@ func (a *ACME) LoadCertificateForDomains(domains []string) {
|
|||
|
||||
// Get provided certificate which check a domains list (Main and SANs)
|
||||
// from static and dynamic provided certificates
|
||||
func (a *ACME) getProvidedCertificate(domains []string) *tls.Certificate {
|
||||
func (a *ACME) getProvidedCertificate(domains string) *tls.Certificate {
|
||||
log.Debugf("Looking for provided certificate to validate %s...", domains)
|
||||
cert := searchProvidedCertificateForDomains(domains, a.TLSConfig.NameToCertificate)
|
||||
if cert == nil && a.dynamicCerts != nil && a.dynamicCerts.Get() != nil {
|
||||
cert = searchProvidedCertificateForDomains(domains, a.dynamicCerts.Get().(*traefikTls.DomainsCertificates).Get().(map[string]*tls.Certificate))
|
||||
}
|
||||
if cert == nil {
|
||||
log.Debugf("No provided certificate found for domains %s, get ACME certificate.", domains)
|
||||
}
|
||||
return cert
|
||||
}
|
||||
|
||||
func searchProvidedCertificateForDomains(domains []string, certs map[string]*tls.Certificate) *tls.Certificate {
|
||||
func searchProvidedCertificateForDomains(domain string, certs map[string]*tls.Certificate) *tls.Certificate {
|
||||
// Use regex to test for provided certs that might have been added into TLSConfig
|
||||
providedCertMatch := false
|
||||
for k := range certs {
|
||||
selector := "^" + strings.Replace(k, "*.", "[^\\.]*\\.?", -1) + "$"
|
||||
for _, domainToCheck := range domains {
|
||||
providedCertMatch, _ = regexp.MatchString(selector, domainToCheck)
|
||||
if !providedCertMatch {
|
||||
for certDomains := range certs {
|
||||
domainCheck := false
|
||||
for _, certDomain := range strings.Split(certDomains, ",") {
|
||||
selector := "^" + strings.Replace(certDomain, "*.", "[^\\.]*\\.?", -1) + "$"
|
||||
domainCheck, _ = regexp.MatchString(selector, domain)
|
||||
if domainCheck {
|
||||
break
|
||||
}
|
||||
}
|
||||
if providedCertMatch {
|
||||
log.Debugf("Got provided certificate for domains %s", domains)
|
||||
return certs[k]
|
||||
|
||||
if domainCheck {
|
||||
log.Debugf("Domain %q checked by provided certificate %q", domain, certDomains)
|
||||
return certs[certDomains]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get provided certificate which check a domains list (Main and SANs)
|
||||
// from static and dynamic provided certificates
|
||||
func (a *ACME) getUncheckedDomains(domains []string, account *Account) []string {
|
||||
log.Debugf("Looking for provided certificate to validate %s...", domains)
|
||||
allCerts := make(map[string]*tls.Certificate)
|
||||
|
||||
// Get static certificates
|
||||
for domains, certificate := range a.TLSConfig.NameToCertificate {
|
||||
allCerts[domains] = certificate
|
||||
}
|
||||
|
||||
// Get dynamic certificates
|
||||
if a.dynamicCerts != nil && a.dynamicCerts.Get() != nil {
|
||||
for domains, certificate := range a.dynamicCerts.Get().(*traefikTls.DomainsCertificates).Get().(map[string]*tls.Certificate) {
|
||||
allCerts[domains] = certificate
|
||||
}
|
||||
}
|
||||
|
||||
// Get ACME certificates
|
||||
if account != nil {
|
||||
for domains, certificate := range account.DomainsCertificate.toDomainsMap() {
|
||||
allCerts[domains] = certificate
|
||||
}
|
||||
}
|
||||
|
||||
return searchUncheckedDomains(domains, allCerts)
|
||||
}
|
||||
|
||||
func searchUncheckedDomains(domains []string, certs map[string]*tls.Certificate) []string {
|
||||
uncheckedDomains := []string{}
|
||||
for _, domainToCheck := range domains {
|
||||
domainCheck := false
|
||||
for certDomains := range certs {
|
||||
domainCheck = false
|
||||
for _, certDomain := range strings.Split(certDomains, ",") {
|
||||
// Use regex to test for provided certs that might have been added into TLSConfig
|
||||
selector := "^" + strings.Replace(certDomain, "*.", "[^\\.]*\\.?", -1) + "$"
|
||||
domainCheck, _ = regexp.MatchString(selector, domainToCheck)
|
||||
if domainCheck {
|
||||
break
|
||||
}
|
||||
}
|
||||
if domainCheck {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !domainCheck {
|
||||
uncheckedDomains = append(uncheckedDomains, domainToCheck)
|
||||
}
|
||||
}
|
||||
if len(uncheckedDomains) == 0 {
|
||||
log.Debugf("No ACME certificate to generate for domains %q.", domains)
|
||||
} else {
|
||||
log.Debugf("Domains %q need ACME certificates generation for domains %q.", domains, strings.Join(uncheckedDomains, ","))
|
||||
}
|
||||
return uncheckedDomains
|
||||
}
|
||||
|
||||
func (a *ACME) getDomainsCertificates(domains []string) (*Certificate, error) {
|
||||
domains = fun.Map(types.CanonicalDomain, domains).([]string)
|
||||
log.Debugf("Loading ACME certificates %s...", domains)
|
||||
|
|
|
@ -281,7 +281,7 @@ cijFkALeQp/qyeXdFld2v9gUN3eCgljgcl0QweRoIc=---`)
|
|||
}
|
||||
}
|
||||
|
||||
func TestAcme_getProvidedCertificate(t *testing.T) {
|
||||
func TestAcme_getUncheckedCertificates(t *testing.T) {
|
||||
mm := make(map[string]*tls.Certificate)
|
||||
mm["*.containo.us"] = &tls.Certificate{}
|
||||
mm["traefik.acme.io"] = &tls.Certificate{}
|
||||
|
@ -289,9 +289,36 @@ func TestAcme_getProvidedCertificate(t *testing.T) {
|
|||
a := ACME{TLSConfig: &tls.Config{NameToCertificate: mm}}
|
||||
|
||||
domains := []string{"traefik.containo.us", "trae.containo.us"}
|
||||
certificate := a.getProvidedCertificate(domains)
|
||||
assert.NotNil(t, certificate)
|
||||
uncheckedDomains := a.getUncheckedDomains(domains, nil)
|
||||
assert.Empty(t, uncheckedDomains)
|
||||
domains = []string{"traefik.acme.io", "trae.acme.io"}
|
||||
certificate = a.getProvidedCertificate(domains)
|
||||
uncheckedDomains = a.getUncheckedDomains(domains, nil)
|
||||
assert.Len(t, uncheckedDomains, 1)
|
||||
domainsCertificates := DomainsCertificates{Certs: []*DomainsCertificate{
|
||||
{
|
||||
tlsCert: &tls.Certificate{},
|
||||
Domains: Domain{
|
||||
Main: "*.acme.wtf",
|
||||
SANs: []string{"trae.acme.io"},
|
||||
},
|
||||
},
|
||||
}}
|
||||
account := Account{DomainsCertificate: domainsCertificates}
|
||||
uncheckedDomains = a.getUncheckedDomains(domains, &account)
|
||||
assert.Empty(t, uncheckedDomains)
|
||||
}
|
||||
|
||||
func TestAcme_getProvidedCertificate(t *testing.T) {
|
||||
mm := make(map[string]*tls.Certificate)
|
||||
mm["*.containo.us"] = &tls.Certificate{}
|
||||
mm["traefik.acme.io"] = &tls.Certificate{}
|
||||
|
||||
a := ACME{TLSConfig: &tls.Config{NameToCertificate: mm}}
|
||||
|
||||
domain := "traefik.containo.us"
|
||||
certificate := a.getProvidedCertificate(domain)
|
||||
assert.NotNil(t, certificate)
|
||||
domain = "trae.acme.io"
|
||||
certificate = a.getProvidedCertificate(domain)
|
||||
assert.Nil(t, certificate)
|
||||
}
|
||||
|
|
|
@ -308,6 +308,9 @@ func NewTraefikConfiguration() *TraefikConfiguration {
|
|||
HealthCheck: &configuration.HealthCheckConfig{
|
||||
Interval: flaeg.Duration(configuration.DefaultHealthCheckInterval),
|
||||
},
|
||||
LifeCycle: &configuration.LifeCycle{
|
||||
GraceTimeOut: flaeg.Duration(configuration.DefaultGraceTimeout),
|
||||
},
|
||||
CheckNewVersion: true,
|
||||
},
|
||||
ConfigFile: "",
|
||||
|
|
|
@ -569,6 +569,11 @@ Each command is described at the beginning of the help section:
|
|||
|
||||
```bash
|
||||
traefik --help
|
||||
|
||||
# or
|
||||
|
||||
docker run traefik[:version] --help
|
||||
# ex: docker run traefik:1.5 --help
|
||||
```
|
||||
|
||||
### Command: bug
|
||||
|
|
|
@ -69,7 +69,7 @@ networks:
|
|||
```
|
||||
|
||||
As you can see, we're mounting the `traefik.toml` file as well as the (empty) `acme.json` file in the container.
|
||||
Also, we're mounting the `/var/run/docker.sock` Docker socket in the container as well, so Træfik can listen to Docker events and reconfigure it's own internal configuration when containers are created (or shut down).
|
||||
Also, we're mounting the `/var/run/docker.sock` Docker socket in the container as well, so Træfik can listen to Docker events and reconfigure its own internal configuration when containers are created (or shut down).
|
||||
Also, we're making sure the container is automatically restarted by the Docker engine in case of problems (or: if the server is rebooted).
|
||||
We're publishing the default HTTP ports `80` and `443` on the host, and making sure the container is placed within the `web` network we've created earlier on.
|
||||
Finally, we're giving this container a static name called `traefik`.
|
||||
|
@ -199,7 +199,7 @@ Since the `traefik` container we've created and started earlier is also attached
|
|||
As mentioned earlier, we don't want containers exposed automatically by Træfik.
|
||||
|
||||
The reason behind this is simple: we want to have control over this process ourselves.
|
||||
Thanks to Docker labels, we can tell Træfik how to create it's internal routing configuration.
|
||||
Thanks to Docker labels, we can tell Træfik how to create its internal routing configuration.
|
||||
|
||||
Let's take a look at the labels themselves for the `app` service, which is a HTTP webservice listing on port 9000:
|
||||
|
||||
|
@ -222,7 +222,7 @@ We use both `container labels` and `service labels`.
|
|||
First, we specify the `backend` name which corresponds to the actual service we're routing **to**.
|
||||
|
||||
We also tell Træfik to use the `web` network to route HTTP traffic to this container.
|
||||
With the `traefik.enable` label, we tell Træfik to include this container in it's internal configuration.
|
||||
With the `traefik.enable` label, we tell Træfik to include this container in its internal configuration.
|
||||
|
||||
With the `frontend.rule` label, we tell Træfik that we want to route to this container if the incoming HTTP request contains the `Host` `app.my-awesome-app.org`.
|
||||
Essentially, this is the actual rule used for Layer-7 load balancing.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
|
@ -13,7 +14,6 @@ import (
|
|||
"github.com/containous/traefik/integration/helloworld"
|
||||
"github.com/containous/traefik/integration/try"
|
||||
"github.com/go-check/check"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
|
|
@ -20,7 +20,8 @@ import fmt "fmt"
|
|||
import math "math"
|
||||
|
||||
import (
|
||||
context "golang.org/x/net/context"
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ func NewEntryPointHandler(dstEntryPoint *configuration.EntryPoint, permanent boo
|
|||
protocol = "https"
|
||||
}
|
||||
|
||||
replacement := protocol + "://$1" + match[0] + "$2"
|
||||
replacement := protocol + "://${1}" + match[0] + "${2}"
|
||||
|
||||
return NewRegexHandler(defaultRedirectRegex, replacement, permanent)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -11,7 +12,6 @@ import (
|
|||
"github.com/docker/docker/api/types/swarm"
|
||||
dockerclient "github.com/docker/docker/client"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type fakeTasksClient struct {
|
||||
|
|
|
@ -486,6 +486,7 @@ func (s *serverEntryPoint) getCertificate(clientHello *tls.ClientHelloInfo) (*tl
|
|||
}
|
||||
}
|
||||
}
|
||||
log.Debugf("No certificate provided dynamically can check the domain %q, a per default certificate will be used.", domainToCheck)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -904,7 +905,7 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
|||
|
||||
entryPoint := globalConfiguration.EntryPoints[entryPointName]
|
||||
n := negroni.New()
|
||||
if entryPoint.Redirect != nil {
|
||||
if entryPoint.Redirect != nil && entryPointName != entryPoint.Redirect.EntryPoint {
|
||||
if redirectHandlers[entryPointName] != nil {
|
||||
n.Use(redirectHandlers[entryPointName])
|
||||
} else if handler, err := s.buildRedirectHandler(entryPointName, entryPoint.Redirect); err != nil {
|
||||
|
@ -1102,7 +1103,7 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
|||
log.Infof("Configured IP Whitelists: %s", frontend.WhitelistSourceRange)
|
||||
}
|
||||
|
||||
if frontend.Redirect != nil {
|
||||
if frontend.Redirect != nil && entryPointName != frontend.Redirect.EntryPoint {
|
||||
rewrite, err := s.buildRedirectHandler(entryPointName, frontend.Redirect)
|
||||
if err != nil {
|
||||
log.Errorf("Error creating Frontend Redirect: %v", err)
|
||||
|
|
|
@ -101,7 +101,8 @@ func (c *Certificates) CreateTLSConfig(entryPointName string) (*tls.Config, map[
|
|||
for _, certificate := range *c {
|
||||
err := certificate.AppendCertificates(domainsCertificates, entryPointName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
log.Errorf("Unable to add a certificate to the entryPoint %q : %v", entryPointName, err)
|
||||
continue
|
||||
}
|
||||
for _, certDom := range domainsCertificates {
|
||||
for _, cert := range certDom.Get().(map[string]*tls.Certificate) {
|
||||
|
@ -133,16 +134,16 @@ func (c *Certificate) AppendCertificates(certs map[string]*DomainsCertificates,
|
|||
|
||||
certContent, err := c.CertFile.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("unable to read CertFile : %v", err)
|
||||
}
|
||||
|
||||
keyContent, err := c.KeyFile.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("uUnable to read KeyFile : %v", err)
|
||||
}
|
||||
tlsCert, err := tls.X509KeyPair(certContent, keyContent)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("unable to generate TLS certificate : %v", err)
|
||||
}
|
||||
|
||||
parsedCert, _ := x509.ParseCertificate(tlsCert.Certificate[0])
|
||||
|
|
400
vendor/github.com/containous/flaeg/flaeg.go
generated
vendored
400
vendor/github.com/containous/flaeg/flaeg.go
generated
vendored
|
@ -12,64 +12,63 @@ import (
|
|||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/containous/flaeg/parse"
|
||||
flag "github.com/ogier/pflag"
|
||||
)
|
||||
|
||||
// ErrParserNotFound is thrown when a field is flaged but not parser match its type
|
||||
var ErrParserNotFound = errors.New("Parser not found or custom parser missing")
|
||||
var ErrParserNotFound = errors.New("parser not found or custom parser missing")
|
||||
|
||||
// GetTypesRecursive links in flagmap a flag with its reflect.StructField
|
||||
// GetTypesRecursive links in flagMap a flag with its reflect.StructField
|
||||
// You can whether provide objValue on a structure or a pointer to structure as first argument
|
||||
// Flags are genereted from field name or from StructTag
|
||||
func getTypesRecursive(objValue reflect.Value, flagmap map[string]reflect.StructField, key string) error {
|
||||
// Flags are generated from field name or from StructTag
|
||||
func getTypesRecursive(objValue reflect.Value, flagMap map[string]reflect.StructField, key string) error {
|
||||
name := key
|
||||
switch objValue.Kind() {
|
||||
case reflect.Struct:
|
||||
|
||||
for i := 0; i < objValue.NumField(); i++ {
|
||||
if objValue.Type().Field(i).Anonymous {
|
||||
if err := getTypesRecursive(objValue.Field(i), flagmap, name); err != nil {
|
||||
if err := getTypesRecursive(objValue.Field(i), flagMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(objValue.Type().Field(i).Tag.Get("description")) > 0 {
|
||||
fieldName := objValue.Type().Field(i).Name
|
||||
if !isExported(fieldName) {
|
||||
return fmt.Errorf("Field %s is an unexported field", fieldName)
|
||||
return fmt.Errorf("field %s is an unexported field", fieldName)
|
||||
}
|
||||
|
||||
name += objValue.Type().Name()
|
||||
if tag := objValue.Type().Field(i).Tag.Get("long"); len(tag) > 0 {
|
||||
fieldName = tag
|
||||
}
|
||||
|
||||
if len(key) == 0 {
|
||||
//Lower Camel Case
|
||||
//name = strings.ToLower(string(fieldName[0])) + fieldName[1:]
|
||||
name = strings.ToLower(fieldName)
|
||||
} else {
|
||||
name = key + "." + strings.ToLower(fieldName)
|
||||
}
|
||||
if _, ok := flagmap[name]; ok {
|
||||
return errors.New("Tag already exists: " + name)
|
||||
}
|
||||
flagmap[name] = objValue.Type().Field(i)
|
||||
|
||||
if err := getTypesRecursive(objValue.Field(i), flagmap, name); err != nil {
|
||||
if _, ok := flagMap[name]; ok {
|
||||
return fmt.Errorf("tag already exists: %s", name)
|
||||
}
|
||||
flagMap[name] = objValue.Type().Field(i)
|
||||
|
||||
if err := getTypesRecursive(objValue.Field(i), flagMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if len(key) > 0 {
|
||||
field := flagmap[name]
|
||||
field := flagMap[name]
|
||||
field.Type = reflect.TypeOf(false)
|
||||
flagmap[name] = field
|
||||
flagMap[name] = field
|
||||
}
|
||||
|
||||
typ := objValue.Type().Elem()
|
||||
inst := reflect.New(typ).Elem()
|
||||
if err := getTypesRecursive(inst, flagmap, name); err != nil {
|
||||
|
||||
if err := getTypesRecursive(inst, flagMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
|
@ -78,14 +77,15 @@ func getTypesRecursive(objValue reflect.Value, flagmap map[string]reflect.Struct
|
|||
return nil
|
||||
}
|
||||
|
||||
//GetPointerFlags returns flags on pointers
|
||||
// GetBoolFlags returns flags on pointers
|
||||
func GetBoolFlags(config interface{}) ([]string, error) {
|
||||
flagmap := make(map[string]reflect.StructField)
|
||||
if err := getTypesRecursive(reflect.ValueOf(config), flagmap, ""); err != nil {
|
||||
flagMap := make(map[string]reflect.StructField)
|
||||
if err := getTypesRecursive(reflect.ValueOf(config), flagMap, ""); err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
flags := make([]string, 0, len(flagmap))
|
||||
for f, structField := range flagmap {
|
||||
|
||||
flags := make([]string, 0, len(flagMap))
|
||||
for f, structField := range flagMap {
|
||||
if structField.Type.Kind() == reflect.Bool {
|
||||
flags = append(flags, f)
|
||||
}
|
||||
|
@ -93,86 +93,42 @@ func GetBoolFlags(config interface{}) ([]string, error) {
|
|||
return flags, nil
|
||||
}
|
||||
|
||||
//GetFlags returns flags
|
||||
// GetFlags returns flags
|
||||
func GetFlags(config interface{}) ([]string, error) {
|
||||
flagmap := make(map[string]reflect.StructField)
|
||||
if err := getTypesRecursive(reflect.ValueOf(config), flagmap, ""); err != nil {
|
||||
flagMap := make(map[string]reflect.StructField)
|
||||
if err := getTypesRecursive(reflect.ValueOf(config), flagMap, ""); err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
flags := make([]string, 0, len(flagmap))
|
||||
for f := range flagmap {
|
||||
|
||||
flags := make([]string, 0, len(flagMap))
|
||||
for f := range flagMap {
|
||||
flags = append(flags, f)
|
||||
}
|
||||
return flags, nil
|
||||
}
|
||||
|
||||
//loadParsers loads default parsers and custom parsers given as parameter. Return a map [reflect.Type]parsers
|
||||
// bool, int, int64, uint, uint64, float64,
|
||||
func loadParsers(customParsers map[reflect.Type]Parser) (map[reflect.Type]Parser, error) {
|
||||
parsers := map[reflect.Type]Parser{}
|
||||
|
||||
var boolParser boolValue
|
||||
parsers[reflect.TypeOf(true)] = &boolParser
|
||||
|
||||
var intParser intValue
|
||||
parsers[reflect.TypeOf(1)] = &intParser
|
||||
|
||||
var int64Parser int64Value
|
||||
parsers[reflect.TypeOf(int64(1))] = &int64Parser
|
||||
|
||||
var uintParser uintValue
|
||||
parsers[reflect.TypeOf(uint(1))] = &uintParser
|
||||
|
||||
var uint64Parser uint64Value
|
||||
parsers[reflect.TypeOf(uint64(1))] = &uint64Parser
|
||||
|
||||
var stringParser stringValue
|
||||
parsers[reflect.TypeOf("")] = &stringParser
|
||||
|
||||
var float64Parser float64Value
|
||||
parsers[reflect.TypeOf(float64(1.5))] = &float64Parser
|
||||
|
||||
var durationParser Duration
|
||||
parsers[reflect.TypeOf(Duration(time.Second))] = &durationParser
|
||||
|
||||
var timeParser timeValue
|
||||
parsers[reflect.TypeOf(time.Now())] = &timeParser
|
||||
|
||||
for rType, parser := range customParsers {
|
||||
parsers[rType] = parser
|
||||
}
|
||||
return parsers, nil
|
||||
}
|
||||
|
||||
//ParseArgs : parses args return valmap map[flag]Getter, using parsers map[type]Getter
|
||||
//args must be formated as like as flag documentation. See https://golang.org/pkg/flag
|
||||
func parseArgs(args []string, flagmap map[string]reflect.StructField, parsers map[reflect.Type]Parser) (map[string]Parser, error) {
|
||||
//Return var
|
||||
valmap := make(map[string]Parser)
|
||||
//Visitor in flag.Parse
|
||||
flagList := []*flag.Flag{}
|
||||
visitor := func(fl *flag.Flag) {
|
||||
flagList = append(flagList, fl)
|
||||
}
|
||||
newParsers := map[string]Parser{}
|
||||
// ParseArgs : parses args return a map[flag]Getter, using parsers map[type]Getter
|
||||
// args must be formatted as like as flag documentation. See https://golang.org/pkg/flag
|
||||
func parseArgs(args []string, flagMap map[string]reflect.StructField, parsers map[reflect.Type]parse.Parser) (map[string]parse.Parser, error) {
|
||||
newParsers := map[string]parse.Parser{}
|
||||
flagSet := flag.NewFlagSet("flaeg.Load", flag.ContinueOnError)
|
||||
//Disable output
|
||||
|
||||
// Disable output
|
||||
flagSet.SetOutput(ioutil.Discard)
|
||||
|
||||
var err error
|
||||
for flag, structField := range flagmap {
|
||||
//for _, flag := range flags {
|
||||
//structField := flagmap[flag]
|
||||
for flg, structField := range flagMap {
|
||||
if parser, ok := parsers[structField.Type]; ok {
|
||||
newparserValue := reflect.New(reflect.TypeOf(parser).Elem())
|
||||
newparserValue.Elem().Set(reflect.ValueOf(parser).Elem())
|
||||
newparser := newparserValue.Interface().(Parser)
|
||||
newParserValue := reflect.New(reflect.TypeOf(parser).Elem())
|
||||
newParserValue.Elem().Set(reflect.ValueOf(parser).Elem())
|
||||
newParser := newParserValue.Interface().(parse.Parser)
|
||||
|
||||
if short := structField.Tag.Get("short"); len(short) == 1 {
|
||||
// fmt.Printf("short : %s long : %s\n", short, flag)
|
||||
flagSet.VarP(newparser, flag, short, structField.Tag.Get("description"))
|
||||
flagSet.VarP(newParser, flg, short, structField.Tag.Get("description"))
|
||||
} else {
|
||||
flagSet.Var(newparser, flag, structField.Tag.Get("description"))
|
||||
flagSet.Var(newParser, flg, structField.Tag.Get("description"))
|
||||
}
|
||||
newParsers[flag] = newparser
|
||||
newParsers[flg] = newParser
|
||||
} else {
|
||||
err = ErrParserNotFound
|
||||
}
|
||||
|
@ -180,24 +136,35 @@ func parseArgs(args []string, flagmap map[string]reflect.StructField, parsers ma
|
|||
|
||||
// prevents case sensitivity issue
|
||||
args = argsToLower(args)
|
||||
if err := flagSet.Parse(args); err != nil {
|
||||
return nil, err
|
||||
if errParse := flagSet.Parse(args); errParse != nil {
|
||||
return nil, errParse
|
||||
}
|
||||
|
||||
//Fill flagList with parsed flags
|
||||
// Visitor in flag.Parse
|
||||
var flagList []*flag.Flag
|
||||
visitor := func(fl *flag.Flag) {
|
||||
flagList = append(flagList, fl)
|
||||
}
|
||||
|
||||
// Fill flagList with parsed flags
|
||||
flagSet.Visit(visitor)
|
||||
//Return parsers on parsed flag
|
||||
for _, flag := range flagList {
|
||||
valmap[flag.Name] = newParsers[flag.Name]
|
||||
|
||||
// Return var
|
||||
valMap := make(map[string]parse.Parser)
|
||||
|
||||
// Return parsers on parsed flag
|
||||
for _, flg := range flagList {
|
||||
valMap[flg.Name] = newParsers[flg.Name]
|
||||
}
|
||||
|
||||
return valmap, err
|
||||
return valMap, err
|
||||
}
|
||||
|
||||
func getDefaultValue(defaultValue reflect.Value, defaultPointersValue reflect.Value, defaultValmap map[string]reflect.Value, key string) error {
|
||||
if defaultValue.Type() != defaultPointersValue.Type() {
|
||||
return fmt.Errorf("Parameters defaultValue and defaultPointersValue must be the same struct. defaultValue type : %s is not defaultPointersValue type : %s", defaultValue.Type().String(), defaultPointersValue.Type().String())
|
||||
return fmt.Errorf("parameters defaultValue and defaultPointersValue must be the same struct. defaultValue type: %s is not defaultPointersValue type: %s", defaultValue.Type().String(), defaultPointersValue.Type().String())
|
||||
}
|
||||
|
||||
name := key
|
||||
switch defaultValue.Kind() {
|
||||
case reflect.Struct:
|
||||
|
@ -207,22 +174,19 @@ func getDefaultValue(defaultValue reflect.Value, defaultPointersValue reflect.Va
|
|||
return err
|
||||
}
|
||||
} else if len(defaultValue.Type().Field(i).Tag.Get("description")) > 0 {
|
||||
name += defaultValue.Type().Name()
|
||||
fieldName := defaultValue.Type().Field(i).Name
|
||||
if tag := defaultValue.Type().Field(i).Tag.Get("long"); len(tag) > 0 {
|
||||
fieldName = tag
|
||||
}
|
||||
|
||||
if len(key) == 0 {
|
||||
name = strings.ToLower(fieldName)
|
||||
} else {
|
||||
name = key + "." + strings.ToLower(fieldName)
|
||||
}
|
||||
|
||||
if defaultValue.Field(i).Kind() != reflect.Ptr {
|
||||
// if _, ok := defaultValmap[name]; ok {
|
||||
// return errors.New("Tag already exists: " + name)
|
||||
// }
|
||||
defaultValmap[name] = defaultValue.Field(i)
|
||||
// fmt.Printf("%s: got default value %+v\n", name, defaultValue.Field(i))
|
||||
}
|
||||
if err := getDefaultValue(defaultValue.Field(i), defaultPointersValue.Field(i), defaultValmap, name); err != nil {
|
||||
return err
|
||||
|
@ -232,14 +196,14 @@ func getDefaultValue(defaultValue reflect.Value, defaultPointersValue reflect.Va
|
|||
case reflect.Ptr:
|
||||
if !defaultPointersValue.IsNil() {
|
||||
if len(key) != 0 {
|
||||
//turn ptr fields to nil
|
||||
// turn ptr fields to nil
|
||||
defaultPointersNilValue, err := setPointersNil(defaultPointersValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defaultValmap[name] = defaultPointersNilValue
|
||||
// fmt.Printf("%s: got default value %+v\n", name, defaultPointersNilValue)
|
||||
}
|
||||
|
||||
if !defaultValue.IsNil() {
|
||||
if err := getDefaultValue(defaultValue.Elem(), defaultPointersValue.Elem(), defaultValmap, name); err != nil {
|
||||
return err
|
||||
|
@ -253,8 +217,8 @@ func getDefaultValue(defaultValue reflect.Value, defaultPointersValue reflect.Va
|
|||
instValue := reflect.New(defaultPointersValue.Type().Elem())
|
||||
if len(key) != 0 {
|
||||
defaultValmap[name] = instValue
|
||||
// fmt.Printf("%s: got default value %+v\n", name, instValue)
|
||||
}
|
||||
|
||||
if !defaultValue.IsNil() {
|
||||
if err := getDefaultValue(defaultValue.Elem(), instValue.Elem(), defaultValmap, name); err != nil {
|
||||
return err
|
||||
|
@ -271,17 +235,18 @@ func getDefaultValue(defaultValue reflect.Value, defaultPointersValue reflect.Va
|
|||
return nil
|
||||
}
|
||||
|
||||
//objValue a reflect.Value of a not-nil pointer on a struct
|
||||
// objValue a reflect.Value of a not-nil pointer on a struct
|
||||
func setPointersNil(objValue reflect.Value) (reflect.Value, error) {
|
||||
if objValue.Kind() != reflect.Ptr {
|
||||
return objValue, fmt.Errorf("Parameters objValue must be a not-nil pointer on a struct, not a %s", objValue.Kind().String())
|
||||
return objValue, fmt.Errorf("parameters objValue must be a not-nil pointer on a struct, not a %s", objValue.Kind())
|
||||
} else if objValue.IsNil() {
|
||||
return objValue, fmt.Errorf("Parameters objValue must be a not-nil pointer")
|
||||
return objValue, errors.New("parameters objValue must be a not-nil pointer")
|
||||
} else if objValue.Elem().Kind() != reflect.Struct {
|
||||
// fmt.Printf("Parameters objValue must be a not-nil pointer on a struct, not a pointer on a %s\n", objValue.Elem().Kind().String())
|
||||
return objValue, nil
|
||||
}
|
||||
//Clone
|
||||
|
||||
// Clone
|
||||
starObjValue := objValue.Elem()
|
||||
nilPointersObjVal := reflect.New(starObjValue.Type())
|
||||
starNilPointersObjVal := nilPointersObjVal.Elem()
|
||||
|
@ -295,39 +260,38 @@ func setPointersNil(objValue reflect.Value) (reflect.Value, error) {
|
|||
return nilPointersObjVal, nil
|
||||
}
|
||||
|
||||
//FillStructRecursive initialize a value of any taged Struct given by reference
|
||||
func fillStructRecursive(objValue reflect.Value, defaultPointerValmap map[string]reflect.Value, valmap map[string]Parser, key string) error {
|
||||
// FillStructRecursive initialize a value of any tagged Struct given by reference
|
||||
func fillStructRecursive(objValue reflect.Value, defaultPointerValMap map[string]reflect.Value, valMap map[string]parse.Parser, key string) error {
|
||||
name := key
|
||||
switch objValue.Kind() {
|
||||
case reflect.Struct:
|
||||
|
||||
for i := 0; i < objValue.Type().NumField(); i++ {
|
||||
if objValue.Type().Field(i).Anonymous {
|
||||
if err := fillStructRecursive(objValue.Field(i), defaultPointerValmap, valmap, name); err != nil {
|
||||
if err := fillStructRecursive(objValue.Field(i), defaultPointerValMap, valMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(objValue.Type().Field(i).Tag.Get("description")) > 0 {
|
||||
name += objValue.Type().Name()
|
||||
fieldName := objValue.Type().Field(i).Name
|
||||
if tag := objValue.Type().Field(i).Tag.Get("long"); len(tag) > 0 {
|
||||
fieldName = tag
|
||||
}
|
||||
|
||||
if len(key) == 0 {
|
||||
name = strings.ToLower(fieldName)
|
||||
} else {
|
||||
name = key + "." + strings.ToLower(fieldName)
|
||||
}
|
||||
// fmt.Println(name)
|
||||
if objValue.Field(i).Kind() != reflect.Ptr {
|
||||
|
||||
if val, ok := valmap[name]; ok {
|
||||
// fmt.Printf("%s : set def val\n", name)
|
||||
if objValue.Field(i).Kind() != reflect.Ptr {
|
||||
if val, ok := valMap[name]; ok {
|
||||
if err := setFields(objValue.Field(i), val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := fillStructRecursive(objValue.Field(i), defaultPointerValmap, valmap, name); err != nil {
|
||||
|
||||
if err := fillStructRecursive(objValue.Field(i), defaultPointerValMap, valMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -335,39 +299,38 @@ func fillStructRecursive(objValue reflect.Value, defaultPointerValmap map[string
|
|||
|
||||
case reflect.Ptr:
|
||||
if len(key) == 0 && !objValue.IsNil() {
|
||||
if err := fillStructRecursive(objValue.Elem(), defaultPointerValmap, valmap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return fillStructRecursive(objValue.Elem(), defaultPointerValMap, valMap, name)
|
||||
}
|
||||
|
||||
contains := false
|
||||
for flag := range valmap {
|
||||
for flg := range valMap {
|
||||
// TODO replace by regexp
|
||||
if strings.HasPrefix(flag, name+".") {
|
||||
if strings.HasPrefix(flg, name+".") {
|
||||
contains = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
needDefault := false
|
||||
if _, ok := valmap[name]; ok {
|
||||
needDefault = valmap[name].Get().(bool)
|
||||
if _, ok := valMap[name]; ok {
|
||||
needDefault = valMap[name].Get().(bool)
|
||||
}
|
||||
if contains && objValue.IsNil() {
|
||||
needDefault = true
|
||||
}
|
||||
|
||||
if needDefault {
|
||||
if defVal, ok := defaultPointerValmap[name]; ok {
|
||||
//set default pointer value
|
||||
// fmt.Printf("%s : set default value %+v\n", name, defVal)
|
||||
if defVal, ok := defaultPointerValMap[name]; ok {
|
||||
// set default pointer value
|
||||
objValue.Set(defVal)
|
||||
} else {
|
||||
return fmt.Errorf("flag %s default value not provided", name)
|
||||
}
|
||||
}
|
||||
|
||||
if !objValue.IsNil() && contains {
|
||||
if objValue.Type().Elem().Kind() == reflect.Struct {
|
||||
if err := fillStructRecursive(objValue.Elem(), defaultPointerValmap, valmap, name); err != nil {
|
||||
if err := fillStructRecursive(objValue.Elem(), defaultPointerValMap, valMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -378,35 +341,35 @@ func fillStructRecursive(objValue reflect.Value, defaultPointerValmap map[string
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetFields sets value to fieldValue using tag as key in valmap
|
||||
func setFields(fieldValue reflect.Value, val Parser) error {
|
||||
// SetFields sets value to fieldValue using tag as key in valMap
|
||||
func setFields(fieldValue reflect.Value, val parse.Parser) error {
|
||||
if fieldValue.CanSet() {
|
||||
fieldValue.Set(reflect.ValueOf(val).Elem().Convert(fieldValue.Type()))
|
||||
} else {
|
||||
return errors.New(fieldValue.Type().String() + " is not settable.")
|
||||
return fmt.Errorf("%s is not settable", fieldValue.Type().String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//PrintHelp generates and prints command line help
|
||||
func PrintHelp(flagmap map[string]reflect.StructField, defaultValmap map[string]reflect.Value, parsers map[reflect.Type]Parser) error {
|
||||
return PrintHelpWithCommand(flagmap, defaultValmap, parsers, nil, nil)
|
||||
// PrintHelp generates and prints command line help
|
||||
func PrintHelp(flagMap map[string]reflect.StructField, defaultValmap map[string]reflect.Value, parsers map[reflect.Type]parse.Parser) error {
|
||||
return PrintHelpWithCommand(flagMap, defaultValmap, parsers, nil, nil)
|
||||
}
|
||||
|
||||
//PrintError takes a not nil error and prints command line help
|
||||
func PrintError(err error, flagmap map[string]reflect.StructField, defaultValmap map[string]reflect.Value, parsers map[reflect.Type]Parser) error {
|
||||
// PrintError takes a not nil error and prints command line help
|
||||
func PrintError(err error, flagMap map[string]reflect.StructField, defaultValmap map[string]reflect.Value, parsers map[reflect.Type]parse.Parser) error {
|
||||
if err != flag.ErrHelp {
|
||||
fmt.Printf("Error : %s\n", err)
|
||||
fmt.Printf("Error: %s\n", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), ":No parser for type") {
|
||||
PrintHelp(flagmap, defaultValmap, parsers)
|
||||
PrintHelp(flagMap, defaultValmap, parsers)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//LoadWithParsers initializes config : struct fields given by reference, with args : arguments.
|
||||
//Some custom parsers may be given.
|
||||
func LoadWithParsers(config interface{}, defaultValue interface{}, args []string, customParsers map[reflect.Type]Parser) error {
|
||||
// LoadWithParsers initializes config : struct fields given by reference, with args : arguments.
|
||||
// Some custom parsers may be given.
|
||||
func LoadWithParsers(config interface{}, defaultValue interface{}, args []string, customParsers map[reflect.Type]parse.Parser) error {
|
||||
cmd := &Command{
|
||||
Config: config,
|
||||
DefaultPointersConfig: defaultValue,
|
||||
|
@ -415,8 +378,8 @@ func LoadWithParsers(config interface{}, defaultValue interface{}, args []string
|
|||
return LoadWithCommand(cmd, args, customParsers, nil)
|
||||
}
|
||||
|
||||
//Load initializes config : struct fields given by reference, with args : arguments.
|
||||
//Some custom parsers may be given.
|
||||
// Load initializes config : struct fields given by reference, with args : arguments.
|
||||
// Some custom parsers may be given.
|
||||
func Load(config interface{}, defaultValue interface{}, args []string) error {
|
||||
return LoadWithParsers(config, defaultValue, args, nil)
|
||||
}
|
||||
|
@ -430,35 +393,34 @@ type Command struct {
|
|||
Name string
|
||||
Description string
|
||||
Config interface{}
|
||||
DefaultPointersConfig interface{} //TODO:case DefaultPointersConfig is nil
|
||||
DefaultPointersConfig interface{} // TODO: case DefaultPointersConfig is nil
|
||||
Run func() error
|
||||
Metadata map[string]string
|
||||
}
|
||||
|
||||
//LoadWithCommand initializes config : struct fields given by reference, with args : arguments.
|
||||
//Some custom parsers and some subCommand may be given.
|
||||
func LoadWithCommand(cmd *Command, cmdArgs []string, customParsers map[reflect.Type]Parser, subCommand []*Command) error {
|
||||
|
||||
parsers, err := loadParsers(customParsers)
|
||||
// LoadWithCommand initializes config : struct fields given by reference, with args : arguments.
|
||||
// Some custom parsers and some subCommand may be given.
|
||||
func LoadWithCommand(cmd *Command, cmdArgs []string, customParsers map[reflect.Type]parse.Parser, subCommand []*Command) error {
|
||||
parsers, err := parse.LoadParsers(customParsers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tagsmap := make(map[string]reflect.StructField)
|
||||
if err := getTypesRecursive(reflect.ValueOf(cmd.Config), tagsmap, ""); err != nil {
|
||||
tagsMap := make(map[string]reflect.StructField)
|
||||
if err := getTypesRecursive(reflect.ValueOf(cmd.Config), tagsMap, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
defaultValmap := make(map[string]reflect.Value)
|
||||
if err := getDefaultValue(reflect.ValueOf(cmd.Config), reflect.ValueOf(cmd.DefaultPointersConfig), defaultValmap, ""); err != nil {
|
||||
defaultValMap := make(map[string]reflect.Value)
|
||||
if err := getDefaultValue(reflect.ValueOf(cmd.Config), reflect.ValueOf(cmd.DefaultPointersConfig), defaultValMap, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
valmap, errParseArgs := parseArgs(cmdArgs, tagsmap, parsers)
|
||||
valMap, errParseArgs := parseArgs(cmdArgs, tagsMap, parsers)
|
||||
if errParseArgs != nil && errParseArgs != ErrParserNotFound {
|
||||
return PrintErrorWithCommand(errParseArgs, tagsmap, defaultValmap, parsers, cmd, subCommand)
|
||||
return PrintErrorWithCommand(errParseArgs, tagsMap, defaultValMap, parsers, cmd, subCommand)
|
||||
}
|
||||
|
||||
if err := fillStructRecursive(reflect.ValueOf(cmd.Config), defaultValmap, valmap, ""); err != nil {
|
||||
if err := fillStructRecursive(reflect.ValueOf(cmd.Config), defaultValMap, valMap, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -469,8 +431,8 @@ func LoadWithCommand(cmd *Command, cmdArgs []string, customParsers map[reflect.T
|
|||
return nil
|
||||
}
|
||||
|
||||
//PrintHelpWithCommand generates and prints command line help for a Command
|
||||
func PrintHelpWithCommand(flagmap map[string]reflect.StructField, defaultValmap map[string]reflect.Value, parsers map[reflect.Type]Parser, cmd *Command, subCmd []*Command) error {
|
||||
// PrintHelpWithCommand generates and prints command line help for a Command
|
||||
func PrintHelpWithCommand(flagMap map[string]reflect.StructField, defaultValMap map[string]reflect.Value, parsers map[reflect.Type]parse.Parser, cmd *Command, subCmd []*Command) error {
|
||||
// Define a templates
|
||||
// Using POSXE STD : http://pubs.opengroup.org/onlinepubs/9699919799/
|
||||
const helper = `{{if .ProgDescription}}{{.ProgDescription}}
|
||||
|
@ -504,7 +466,7 @@ Flags:
|
|||
_, tempStruct.ProgName = path.Split(os.Args[0])
|
||||
}
|
||||
|
||||
//Run Template
|
||||
// Run Template
|
||||
tmplHelper, err := template.New("helper").Parse(helper)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -514,38 +476,38 @@ Flags:
|
|||
return err
|
||||
}
|
||||
|
||||
return printFlagsDescriptionsDefaultValues(flagmap, defaultValmap, parsers, os.Stdout)
|
||||
return printFlagsDescriptionsDefaultValues(flagMap, defaultValMap, parsers, os.Stdout)
|
||||
}
|
||||
|
||||
func printFlagsDescriptionsDefaultValues(flagmap map[string]reflect.StructField, defaultValmap map[string]reflect.Value, parsers map[reflect.Type]Parser, output io.Writer) error {
|
||||
func printFlagsDescriptionsDefaultValues(flagMap map[string]reflect.StructField, defaultValMap map[string]reflect.Value, parsers map[reflect.Type]parse.Parser, output io.Writer) error {
|
||||
// Sort alphabetically & Delete unparsable flags in a slice
|
||||
flags := []string{}
|
||||
for flag, field := range flagmap {
|
||||
var flags []string
|
||||
for flg, field := range flagMap {
|
||||
if _, ok := parsers[field.Type]; ok {
|
||||
flags = append(flags, flag)
|
||||
flags = append(flags, flg)
|
||||
}
|
||||
}
|
||||
sort.Strings(flags)
|
||||
|
||||
// Process data
|
||||
descriptions := []string{}
|
||||
defaultValues := []string{}
|
||||
flagsWithDashs := []string{}
|
||||
shortFlagsWithDash := []string{}
|
||||
for _, flag := range flags {
|
||||
field := flagmap[flag]
|
||||
var descriptions []string
|
||||
var defaultValues []string
|
||||
var flagsWithDash []string
|
||||
var shortFlagsWithDash []string
|
||||
for _, flg := range flags {
|
||||
field := flagMap[flg]
|
||||
if short := field.Tag.Get("short"); len(short) == 1 {
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "-"+short+",")
|
||||
} else {
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "")
|
||||
}
|
||||
flagsWithDashs = append(flagsWithDashs, "--"+flag)
|
||||
flagsWithDash = append(flagsWithDash, "--"+flg)
|
||||
|
||||
//flag on pointer ?
|
||||
if defVal, ok := defaultValmap[flag]; ok {
|
||||
// flag on pointer ?
|
||||
if defVal, ok := defaultValMap[flg]; ok {
|
||||
if defVal.Kind() != reflect.Ptr {
|
||||
// Set defaultValue on parsers
|
||||
parsers[field.Type].SetValue(defaultValmap[flag].Interface())
|
||||
parsers[field.Type].SetValue(defaultValMap[flg].Interface())
|
||||
}
|
||||
|
||||
if defVal := parsers[field.Type].String(); len(defVal) > 0 {
|
||||
|
@ -560,17 +522,19 @@ func printFlagsDescriptionsDefaultValues(flagmap map[string]reflect.StructField,
|
|||
descriptions = append(descriptions, description)
|
||||
if i != 0 {
|
||||
defaultValues = append(defaultValues, "")
|
||||
flagsWithDashs = append(flagsWithDashs, "")
|
||||
flagsWithDash = append(flagsWithDash, "")
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//add help flag
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "-h,")
|
||||
flagsWithDashs = append(flagsWithDashs, "--help")
|
||||
flagsWithDash = append(flagsWithDash, "--help")
|
||||
descriptions = append(descriptions, "Print Help (this message) and exit")
|
||||
defaultValues = append(defaultValues, "")
|
||||
return displayTab(output, shortFlagsWithDash, flagsWithDashs, descriptions, defaultValues)
|
||||
|
||||
return displayTab(output, shortFlagsWithDash, flagsWithDash, descriptions, defaultValues)
|
||||
}
|
||||
func split(str string, width int) []string {
|
||||
if len(str) > width {
|
||||
|
@ -578,16 +542,19 @@ func split(str string, width int) []string {
|
|||
if index == -1 {
|
||||
index = width
|
||||
}
|
||||
|
||||
return append([]string{strings.TrimSpace(str[:index])}, split(strings.TrimSpace(str[index:]), width)...)
|
||||
}
|
||||
return []string{str}
|
||||
}
|
||||
|
||||
func displayTab(output io.Writer, columns ...[]string) error {
|
||||
nbRow := len(columns[0])
|
||||
nbCol := len(columns)
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(output, 0, 4, 1, ' ', 0)
|
||||
|
||||
nbRow := len(columns[0])
|
||||
nbCol := len(columns)
|
||||
|
||||
for i := 0; i < nbRow; i++ {
|
||||
row := ""
|
||||
for j, col := range columns {
|
||||
|
@ -598,56 +565,58 @@ func displayTab(output io.Writer, columns ...[]string) error {
|
|||
}
|
||||
fmt.Fprintln(w, row)
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
//PrintErrorWithCommand takes a not nil error and prints command line help
|
||||
func PrintErrorWithCommand(err error, flagmap map[string]reflect.StructField, defaultValmap map[string]reflect.Value, parsers map[reflect.Type]Parser, cmd *Command, subCmd []*Command) error {
|
||||
// PrintErrorWithCommand takes a not nil error and prints command line help
|
||||
func PrintErrorWithCommand(err error, flagMap map[string]reflect.StructField, defaultValMap map[string]reflect.Value, parsers map[reflect.Type]parse.Parser, cmd *Command, subCmd []*Command) error {
|
||||
if err != flag.ErrHelp {
|
||||
fmt.Printf("Error here : %s\n", err)
|
||||
}
|
||||
PrintHelpWithCommand(flagmap, defaultValmap, parsers, cmd, subCmd)
|
||||
|
||||
PrintHelpWithCommand(flagMap, defaultValMap, parsers, cmd, subCmd)
|
||||
return err
|
||||
}
|
||||
|
||||
//Flaeg struct contains commands (at least the root one)
|
||||
//and row arguments (command and/or flags)
|
||||
//a map of custom parsers could be use
|
||||
// Flaeg struct contains commands (at least the root one)
|
||||
// and row arguments (command and/or flags)
|
||||
// a map of custom parsers could be use
|
||||
type Flaeg struct {
|
||||
calledCommand *Command
|
||||
commands []*Command ///rootCommand is th fist one in this slice
|
||||
args []string
|
||||
commmandArgs []string
|
||||
customParsers map[reflect.Type]Parser
|
||||
commandArgs []string
|
||||
customParsers map[reflect.Type]parse.Parser
|
||||
}
|
||||
|
||||
//New creats and initialize a pointer on Flaeg
|
||||
// New creates and initialize a pointer on Flaeg
|
||||
func New(rootCommand *Command, args []string) *Flaeg {
|
||||
var f Flaeg
|
||||
f.commands = []*Command{rootCommand}
|
||||
f.args = args
|
||||
f.customParsers = map[reflect.Type]Parser{}
|
||||
f.customParsers = map[reflect.Type]parse.Parser{}
|
||||
return &f
|
||||
}
|
||||
|
||||
//AddCommand adds sub-command to the root command
|
||||
// AddCommand adds sub-command to the root command
|
||||
func (f *Flaeg) AddCommand(command *Command) {
|
||||
f.commands = append(f.commands, command)
|
||||
}
|
||||
|
||||
//AddParser adds custom parser for a type to the map of custom parsers
|
||||
func (f *Flaeg) AddParser(typ reflect.Type, parser Parser) {
|
||||
// AddParser adds custom parser for a type to the map of custom parsers
|
||||
func (f *Flaeg) AddParser(typ reflect.Type, parser parse.Parser) {
|
||||
f.customParsers[typ] = parser
|
||||
}
|
||||
|
||||
// Run calls the command with flags given as agruments
|
||||
// Run calls the command with flags given as arguments
|
||||
func (f *Flaeg) Run() error {
|
||||
if f.calledCommand == nil {
|
||||
if _, _, err := f.findCommandWithCommandArgs(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := f.Parse(f.calledCommand); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -658,15 +627,16 @@ func (f *Flaeg) Run() error {
|
|||
// It returns nil and a not nil error if it fails
|
||||
func (f *Flaeg) Parse(cmd *Command) (*Command, error) {
|
||||
if f.calledCommand == nil {
|
||||
f.commmandArgs = f.args
|
||||
f.commandArgs = f.args
|
||||
}
|
||||
if err := LoadWithCommand(cmd, f.commmandArgs, f.customParsers, f.commands); err != nil {
|
||||
|
||||
if err := LoadWithCommand(cmd, f.commandArgs, f.customParsers, f.commands); err != nil {
|
||||
return cmd, err
|
||||
}
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
//splitArgs takes args (type []string) and return command ("" if rootCommand) and command's args
|
||||
// splitArgs takes args (type []string) and return command ("" if rootCommand) and command's args
|
||||
func splitArgs(args []string) (string, []string) {
|
||||
if len(args) >= 1 && len(args[0]) >= 1 && string(args[0][0]) != "-" {
|
||||
if len(args) == 1 {
|
||||
|
@ -680,20 +650,20 @@ func splitArgs(args []string) (string, []string) {
|
|||
// findCommandWithCommandArgs returns the called command (by reference) and command's args
|
||||
// the error returned is not nil if it fails
|
||||
func (f *Flaeg) findCommandWithCommandArgs() (*Command, []string, error) {
|
||||
commandName := ""
|
||||
commandName, f.commmandArgs = splitArgs(f.args)
|
||||
var commandName string
|
||||
commandName, f.commandArgs = splitArgs(f.args)
|
||||
if len(commandName) > 0 {
|
||||
for _, command := range f.commands {
|
||||
if commandName == command.Name {
|
||||
f.calledCommand = command
|
||||
return f.calledCommand, f.commmandArgs, nil
|
||||
return f.calledCommand, f.commandArgs, nil
|
||||
}
|
||||
}
|
||||
return nil, []string{}, fmt.Errorf("Command %s not found", commandName)
|
||||
return nil, []string{}, fmt.Errorf("command %s not found", commandName)
|
||||
}
|
||||
|
||||
f.calledCommand = f.commands[0]
|
||||
return f.calledCommand, f.commmandArgs, nil
|
||||
return f.calledCommand, f.commandArgs, nil
|
||||
}
|
||||
|
||||
// GetCommand splits args and returns the called command (by reference)
|
||||
|
@ -706,15 +676,17 @@ func (f *Flaeg) GetCommand() (*Command, error) {
|
|||
return f.calledCommand, nil
|
||||
}
|
||||
|
||||
//isExported return true is the field (from fieldName) is exported,
|
||||
//else false
|
||||
// isExported return true is the field (from fieldName) is exported,
|
||||
// else false
|
||||
func isExported(fieldName string) bool {
|
||||
if len(fieldName) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
if string(fieldName[0]) == strings.ToUpper(string(fieldName[0])) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -722,22 +694,24 @@ func argToLower(inArg string) string {
|
|||
if len(inArg) < 2 {
|
||||
return strings.ToLower(inArg)
|
||||
}
|
||||
|
||||
var outArg string
|
||||
dashIndex := strings.Index(inArg, "--")
|
||||
if dashIndex == -1 {
|
||||
if dashIndex = strings.Index(inArg, "-"); dashIndex == -1 {
|
||||
return inArg
|
||||
}
|
||||
//-fValue
|
||||
// -fValue
|
||||
outArg = strings.ToLower(inArg[dashIndex:dashIndex+2]) + inArg[dashIndex+2:]
|
||||
return outArg
|
||||
}
|
||||
//--flag
|
||||
|
||||
// --flag
|
||||
if equalIndex := strings.Index(inArg, "="); equalIndex != -1 {
|
||||
//--flag=value
|
||||
// --flag=value
|
||||
outArg = strings.ToLower(inArg[dashIndex:equalIndex]) + inArg[equalIndex:]
|
||||
} else {
|
||||
//--boolflag
|
||||
// --boolflag
|
||||
outArg = strings.ToLower(inArg[dashIndex:])
|
||||
}
|
||||
|
||||
|
@ -745,7 +719,7 @@ func argToLower(inArg string) string {
|
|||
}
|
||||
|
||||
func argsToLower(inArgs []string) []string {
|
||||
outArgs := make([]string, len(inArgs), len(inArgs))
|
||||
outArgs := make([]string, len(inArgs))
|
||||
for i, inArg := range inArgs {
|
||||
outArgs[i] = argToLower(inArg)
|
||||
}
|
||||
|
|
7
vendor/github.com/containous/flaeg/flaeg_types.go
generated
vendored
Normal file
7
vendor/github.com/containous/flaeg/flaeg_types.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
package flaeg
|
||||
|
||||
import "github.com/containous/flaeg/parse"
|
||||
|
||||
// Duration is deprecated use parse.Duration instead
|
||||
// Deprecated
|
||||
type Duration = parse.Duration
|
301
vendor/github.com/containous/flaeg/parse/parse.go
generated
vendored
Normal file
301
vendor/github.com/containous/flaeg/parse/parse.go
generated
vendored
Normal file
|
@ -0,0 +1,301 @@
|
|||
package parse
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Parser is an interface that allows the contents of a flag.Getter to be set.
|
||||
type Parser interface {
|
||||
flag.Getter
|
||||
SetValue(interface{})
|
||||
}
|
||||
|
||||
// BoolValue bool Value type
|
||||
type BoolValue bool
|
||||
|
||||
// Set sets bool value from the given string value.
|
||||
func (b *BoolValue) Set(s string) error {
|
||||
v, err := strconv.ParseBool(s)
|
||||
*b = BoolValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the bool value.
|
||||
func (b *BoolValue) Get() interface{} { return bool(*b) }
|
||||
|
||||
func (b *BoolValue) String() string { return fmt.Sprintf("%v", *b) }
|
||||
|
||||
// IsBoolFlag return true
|
||||
func (b *BoolValue) IsBoolFlag() bool { return true }
|
||||
|
||||
// SetValue sets the duration from the given bool-asserted value.
|
||||
func (b *BoolValue) SetValue(val interface{}) {
|
||||
*b = BoolValue(val.(bool))
|
||||
}
|
||||
|
||||
// BoolFlag optional interface to indicate boolean flags that can be
|
||||
// supplied without "=value" text
|
||||
type BoolFlag interface {
|
||||
flag.Value
|
||||
IsBoolFlag() bool
|
||||
}
|
||||
|
||||
// IntValue int Value
|
||||
type IntValue int
|
||||
|
||||
// Set sets int value from the given string value.
|
||||
func (i *IntValue) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = IntValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the int value.
|
||||
func (i *IntValue) Get() interface{} { return int(*i) }
|
||||
|
||||
func (i *IntValue) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// SetValue sets the IntValue from the given int-asserted value.
|
||||
func (i *IntValue) SetValue(val interface{}) {
|
||||
*i = IntValue(val.(int))
|
||||
}
|
||||
|
||||
// Int64Value int64 Value
|
||||
type Int64Value int64
|
||||
|
||||
// Set sets int64 value from the given string value.
|
||||
func (i *Int64Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = Int64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the int64 value.
|
||||
func (i *Int64Value) Get() interface{} { return int64(*i) }
|
||||
|
||||
func (i *Int64Value) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// SetValue sets the Int64Value from the given int64-asserted value.
|
||||
func (i *Int64Value) SetValue(val interface{}) {
|
||||
*i = Int64Value(val.(int64))
|
||||
}
|
||||
|
||||
// UintValue uint Value
|
||||
type UintValue uint
|
||||
|
||||
// Set sets uint value from the given string value.
|
||||
func (i *UintValue) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = UintValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the uint value.
|
||||
func (i *UintValue) Get() interface{} { return uint(*i) }
|
||||
|
||||
func (i *UintValue) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// SetValue sets the UintValue from the given uint-asserted value.
|
||||
func (i *UintValue) SetValue(val interface{}) {
|
||||
*i = UintValue(val.(uint))
|
||||
}
|
||||
|
||||
// Uint64Value uint64 Value
|
||||
type Uint64Value uint64
|
||||
|
||||
// Set sets uint64 value from the given string value.
|
||||
func (i *Uint64Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = Uint64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the uint64 value.
|
||||
func (i *Uint64Value) Get() interface{} { return uint64(*i) }
|
||||
|
||||
func (i *Uint64Value) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// SetValue sets the Uint64Value from the given uint64-asserted value.
|
||||
func (i *Uint64Value) SetValue(val interface{}) {
|
||||
*i = Uint64Value(val.(uint64))
|
||||
}
|
||||
|
||||
// StringValue string Value
|
||||
type StringValue string
|
||||
|
||||
// Set sets string value from the given string value.
|
||||
func (s *StringValue) Set(val string) error {
|
||||
*s = StringValue(val)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the string value.
|
||||
func (s *StringValue) Get() interface{} { return string(*s) }
|
||||
|
||||
func (s *StringValue) String() string { return string(*s) }
|
||||
|
||||
// SetValue sets the StringValue from the given string-asserted value.
|
||||
func (s *StringValue) SetValue(val interface{}) {
|
||||
*s = StringValue(val.(string))
|
||||
}
|
||||
|
||||
// Float64Value float64 Value
|
||||
type Float64Value float64
|
||||
|
||||
// Set sets float64 value from the given string value.
|
||||
func (f *Float64Value) Set(s string) error {
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
*f = Float64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the float64 value.
|
||||
func (f *Float64Value) Get() interface{} { return float64(*f) }
|
||||
|
||||
func (f *Float64Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
|
||||
// SetValue sets the Float64Value from the given float64-asserted value.
|
||||
func (f *Float64Value) SetValue(val interface{}) {
|
||||
*f = Float64Value(val.(float64))
|
||||
}
|
||||
|
||||
// Duration is a custom type suitable for parsing duration values.
|
||||
// It supports `time.ParseDuration`-compatible values and suffix-less digits; in
|
||||
// the latter case, seconds are assumed.
|
||||
type Duration time.Duration
|
||||
|
||||
// Set sets the duration from the given string value.
|
||||
func (d *Duration) Set(s string) error {
|
||||
if v, err := strconv.Atoi(s); err == nil {
|
||||
*d = Duration(time.Duration(v) * time.Second)
|
||||
return nil
|
||||
}
|
||||
|
||||
v, err := time.ParseDuration(s)
|
||||
*d = Duration(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the duration value.
|
||||
func (d *Duration) Get() interface{} { return time.Duration(*d) }
|
||||
|
||||
// String returns a string representation of the duration value.
|
||||
func (d *Duration) String() string { return (*time.Duration)(d).String() }
|
||||
|
||||
// SetValue sets the duration from the given Duration-asserted value.
|
||||
func (d *Duration) SetValue(val interface{}) {
|
||||
*d = val.(Duration)
|
||||
}
|
||||
|
||||
// MarshalText serialize the given duration value into a text.
|
||||
func (d *Duration) MarshalText() ([]byte, error) {
|
||||
return []byte(d.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText deserializes the given text into a duration value.
|
||||
// It is meant to support TOML decoding of durations.
|
||||
func (d *Duration) UnmarshalText(text []byte) error {
|
||||
return d.Set(string(text))
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes the given text into a duration value.
|
||||
func (d *Duration) UnmarshalJSON(text []byte) error {
|
||||
if v, err := strconv.Atoi(string(text)); err == nil {
|
||||
*d = Duration(time.Duration(v))
|
||||
return nil
|
||||
}
|
||||
|
||||
v, err := time.ParseDuration(string(text))
|
||||
*d = Duration(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// TimeValue time.Time Value
|
||||
type TimeValue time.Time
|
||||
|
||||
// Set sets time.Time value from the given string value.
|
||||
func (t *TimeValue) Set(s string) error {
|
||||
v, err := time.Parse(time.RFC3339, s)
|
||||
*t = TimeValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the time.Time value.
|
||||
func (t *TimeValue) Get() interface{} { return time.Time(*t) }
|
||||
|
||||
func (t *TimeValue) String() string { return (*time.Time)(t).String() }
|
||||
|
||||
// SetValue sets the TimeValue from the given time.Time-asserted value.
|
||||
func (t *TimeValue) SetValue(val interface{}) {
|
||||
*t = TimeValue(val.(time.Time))
|
||||
}
|
||||
|
||||
// SliceStrings parse slice of strings
|
||||
type SliceStrings []string
|
||||
|
||||
// Set adds strings elem into the the parser.
|
||||
// It splits str on , and ;
|
||||
func (s *SliceStrings) Set(str string) error {
|
||||
fargs := func(c rune) bool {
|
||||
return c == ',' || c == ';'
|
||||
}
|
||||
// get function
|
||||
slice := strings.FieldsFunc(str, fargs)
|
||||
*s = append(*s, slice...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get []string
|
||||
func (s *SliceStrings) Get() interface{} { return []string(*s) }
|
||||
|
||||
// String return slice in a string
|
||||
func (s *SliceStrings) String() string { return fmt.Sprintf("%v", *s) }
|
||||
|
||||
// SetValue sets []string into the parser
|
||||
func (s *SliceStrings) SetValue(val interface{}) {
|
||||
*s = SliceStrings(val.([]string))
|
||||
}
|
||||
|
||||
// LoadParsers loads default parsers and custom parsers given as parameter.
|
||||
// Return a map [reflect.Type]parsers
|
||||
// bool, int, int64, uint, uint64, float64,
|
||||
func LoadParsers(customParsers map[reflect.Type]Parser) (map[reflect.Type]Parser, error) {
|
||||
parsers := map[reflect.Type]Parser{}
|
||||
|
||||
var boolParser BoolValue
|
||||
parsers[reflect.TypeOf(true)] = &boolParser
|
||||
|
||||
var intParser IntValue
|
||||
parsers[reflect.TypeOf(1)] = &intParser
|
||||
|
||||
var int64Parser Int64Value
|
||||
parsers[reflect.TypeOf(int64(1))] = &int64Parser
|
||||
|
||||
var uintParser UintValue
|
||||
parsers[reflect.TypeOf(uint(1))] = &uintParser
|
||||
|
||||
var uint64Parser Uint64Value
|
||||
parsers[reflect.TypeOf(uint64(1))] = &uint64Parser
|
||||
|
||||
var stringParser StringValue
|
||||
parsers[reflect.TypeOf("")] = &stringParser
|
||||
|
||||
var float64Parser Float64Value
|
||||
parsers[reflect.TypeOf(float64(1.5))] = &float64Parser
|
||||
|
||||
var durationParser Duration
|
||||
parsers[reflect.TypeOf(Duration(time.Second))] = &durationParser
|
||||
|
||||
var timeParser TimeValue
|
||||
parsers[reflect.TypeOf(time.Now())] = &timeParser
|
||||
|
||||
for rType, parser := range customParsers {
|
||||
parsers[rType] = parser
|
||||
}
|
||||
return parsers, nil
|
||||
}
|
221
vendor/github.com/containous/flaeg/parsers.go
generated
vendored
221
vendor/github.com/containous/flaeg/parsers.go
generated
vendored
|
@ -1,221 +0,0 @@
|
|||
package flaeg
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//TODO : add parsers on all types in https://golang.org/pkg/builtin/
|
||||
|
||||
// Parser is an interface that allows the contents of a flag.Getter to be set.
|
||||
type Parser interface {
|
||||
flag.Getter
|
||||
SetValue(interface{})
|
||||
}
|
||||
|
||||
// -- bool Value
|
||||
type boolValue bool
|
||||
|
||||
func (b *boolValue) Set(s string) error {
|
||||
v, err := strconv.ParseBool(s)
|
||||
*b = boolValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *boolValue) Get() interface{} { return bool(*b) }
|
||||
|
||||
func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
|
||||
|
||||
func (b *boolValue) IsBoolFlag() bool { return true }
|
||||
|
||||
func (b *boolValue) SetValue(val interface{}) {
|
||||
*b = boolValue(val.(bool))
|
||||
}
|
||||
|
||||
// optional interface to indicate boolean flags that can be
|
||||
// supplied without "=value" text
|
||||
type boolFlag interface {
|
||||
flag.Value
|
||||
IsBoolFlag() bool
|
||||
}
|
||||
|
||||
// -- int Value
|
||||
type intValue int
|
||||
|
||||
func (i *intValue) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = intValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *intValue) Get() interface{} { return int(*i) }
|
||||
|
||||
func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
func (i *intValue) SetValue(val interface{}) {
|
||||
*i = intValue(val.(int))
|
||||
}
|
||||
|
||||
// -- int64 Value
|
||||
type int64Value int64
|
||||
|
||||
func (i *int64Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = int64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *int64Value) Get() interface{} { return int64(*i) }
|
||||
|
||||
func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
func (i *int64Value) SetValue(val interface{}) {
|
||||
*i = int64Value(val.(int64))
|
||||
}
|
||||
|
||||
// -- uint Value
|
||||
type uintValue uint
|
||||
|
||||
func (i *uintValue) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = uintValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uintValue) Get() interface{} { return uint(*i) }
|
||||
|
||||
func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
func (i *uintValue) SetValue(val interface{}) {
|
||||
*i = uintValue(val.(uint))
|
||||
}
|
||||
|
||||
// -- uint64 Value
|
||||
type uint64Value uint64
|
||||
|
||||
func (i *uint64Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = uint64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uint64Value) Get() interface{} { return uint64(*i) }
|
||||
|
||||
func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
func (i *uint64Value) SetValue(val interface{}) {
|
||||
*i = uint64Value(val.(uint64))
|
||||
}
|
||||
|
||||
// -- string Value
|
||||
type stringValue string
|
||||
|
||||
func (s *stringValue) Set(val string) error {
|
||||
*s = stringValue(val)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stringValue) Get() interface{} { return string(*s) }
|
||||
|
||||
func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
|
||||
|
||||
func (s *stringValue) SetValue(val interface{}) {
|
||||
*s = stringValue(val.(string))
|
||||
}
|
||||
|
||||
// -- float64 Value
|
||||
type float64Value float64
|
||||
|
||||
func (f *float64Value) Set(s string) error {
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
*f = float64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *float64Value) Get() interface{} { return float64(*f) }
|
||||
|
||||
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
|
||||
func (f *float64Value) SetValue(val interface{}) {
|
||||
*f = float64Value(val.(float64))
|
||||
}
|
||||
|
||||
// Duration is a custom type suitable for parsing duration values.
|
||||
// It supports `time.ParseDuration`-compatible values and suffix-less digits; in
|
||||
// the latter case, seconds are assumed.
|
||||
type Duration time.Duration
|
||||
|
||||
// Set sets the duration from the given string value.
|
||||
func (d *Duration) Set(s string) error {
|
||||
if v, err := strconv.Atoi(s); err == nil {
|
||||
*d = Duration(time.Duration(v) * time.Second)
|
||||
return nil
|
||||
}
|
||||
|
||||
v, err := time.ParseDuration(s)
|
||||
*d = Duration(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the duration value.
|
||||
func (d *Duration) Get() interface{} { return time.Duration(*d) }
|
||||
|
||||
// String returns a string representation of the duration value.
|
||||
func (d *Duration) String() string { return (*time.Duration)(d).String() }
|
||||
|
||||
// SetValue sets the duration from the given Duration-asserted value.
|
||||
func (d *Duration) SetValue(val interface{}) {
|
||||
*d = Duration(val.(Duration))
|
||||
}
|
||||
|
||||
// UnmarshalText deserializes the given text into a duration value.
|
||||
// It is meant to support TOML decoding of durations.
|
||||
func (d *Duration) UnmarshalText(text []byte) error {
|
||||
return d.Set(string(text))
|
||||
}
|
||||
|
||||
// -- time.Time Value
|
||||
type timeValue time.Time
|
||||
|
||||
func (t *timeValue) Set(s string) error {
|
||||
v, err := time.Parse(time.RFC3339, s)
|
||||
*t = timeValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *timeValue) Get() interface{} { return time.Time(*t) }
|
||||
|
||||
func (t *timeValue) String() string { return (*time.Time)(t).String() }
|
||||
|
||||
func (t *timeValue) SetValue(val interface{}) {
|
||||
*t = timeValue(val.(time.Time))
|
||||
}
|
||||
|
||||
//SliceStrings parse slice of strings
|
||||
type SliceStrings []string
|
||||
|
||||
//Set adds strings elem into the the parser
|
||||
//it splits str on , and ;
|
||||
func (s *SliceStrings) Set(str string) error {
|
||||
fargs := func(c rune) bool {
|
||||
return c == ',' || c == ';'
|
||||
}
|
||||
// get function
|
||||
slice := strings.FieldsFunc(str, fargs)
|
||||
*s = append(*s, slice...)
|
||||
return nil
|
||||
}
|
||||
|
||||
//Get []string
|
||||
func (s *SliceStrings) Get() interface{} { return []string(*s) }
|
||||
|
||||
//String return slice in a string
|
||||
func (s *SliceStrings) String() string { return fmt.Sprintf("%v", *s) }
|
||||
|
||||
//SetValue sets []string into the parser
|
||||
func (s *SliceStrings) SetValue(val interface{}) {
|
||||
*s = SliceStrings(val.([]string))
|
||||
}
|
Loading…
Reference in a new issue