diff --git a/Gopkg.lock b/Gopkg.lock index fb765df42..17f8591c3 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -61,6 +61,14 @@ pruneopts = "NUT" revision = "2fd0705ce648e602e6c9c57329a174270a4f6688" +[[projects]] + digest = "1:25870183293a3fb61cc9afd060a61d63a486f091db72af01a8ea3449f5ca530d" + name = "github.com/Masterminds/goutils" + packages = ["."] + pruneopts = "NUT" + revision = "41ac8693c5c10a92ea1ff5ac3a7f95646f6123b0" + version = "v1.1.0" + [[projects]] digest = "1:0ce2a409217f52078c6b8642993deb1025940cded6d5054047c1d5c7379f753c" name = "github.com/Masterminds/semver" @@ -70,11 +78,12 @@ version = "v1.2.2" [[projects]] - digest = "1:a49472e7d73071005f436b7da85567220f24bb26fbfccbec45d2cd1359d4c67d" + digest = "1:876a1121171c083c4e3a4789683d02a40c0f644c8190da521d15b59799f556d6" name = "github.com/Masterminds/sprig" packages = ["."] pruneopts = "NUT" - revision = "e039e20e500c2c025d9145be375e27cf42a94174" + revision = "9f8fceff796fb9f4e992cd2bece016be0121ab74" + version = "2.19.0" [[projects]] digest = "1:915c86626dfd65f8105c48b2972d29f34fd77ff16b31157147cb8ebbddeebbe3" @@ -175,14 +184,6 @@ revision = "cad214d7d71fba7883fcf3b7e550ba782c15b400" version = "1.27.7" -[[projects]] - digest = "1:975108e8d4f5dab096fc991326e96a5716ee8d02e5e7386bb4796171afc4ab9a" - name = "github.com/aokoli/goutils" - packages = ["."] - pruneopts = "NUT" - revision = "3391d3790d23d03408670993e957e8f408993c34" - version = "v1.0.1" - [[projects]] digest = "1:b39cf81d5f440b9c0757a25058432d33af867e5201109bf53621356d9dab4b73" name = "github.com/apache/thrift" @@ -913,11 +914,12 @@ revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" [[projects]] - digest = "1:45e66b20393507035c6a7d15bef5ffe8faf5b083621c1284d9824cc052776de5" + digest = "1:dc54242755f5b6721dd880843de6e45fe234838ea9149ec8249951880fd5802f" name = "github.com/huandu/xstrings" packages = ["."] pruneopts = "NUT" - revision = "3959339b333561bf62a38b424fd41517c2c90f40" + revision = "f02667b379e2fb5916c3cda2cf31e0eb885d79f8" + version = "v1.2.0" [[projects]] branch = "master" @@ -2239,7 +2241,6 @@ "github.com/prometheus/client_model/go", "github.com/rancher/go-rancher-metadata/metadata", "github.com/ryanuber/go-glob", - "github.com/satori/go.uuid", "github.com/sirupsen/logrus", "github.com/stretchr/testify/assert", "github.com/stretchr/testify/mock", diff --git a/Gopkg.toml b/Gopkg.toml index 4616be67d..b6a718318 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -159,8 +159,8 @@ required = [ name = "github.com/ryanuber/go-glob" [[constraint]] - name = "github.com/satori/go.uuid" - version = "1.1.0" + name = "github.com/Masterminds/sprig" + version = "2.19.0" [[constraint]] branch = "master" diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go index afb0757b3..853e1b0bd 100644 --- a/cmd/traefik/traefik.go +++ b/cmd/traefik/traefik.go @@ -94,7 +94,7 @@ func main() { // traefik Command init traefikCmd := &flaeg.Command{ Name: "traefik", - Description: `traefik is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease. + Description: `Traefik is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease. Complete documentation is available at https://traefik.io`, Config: traefikConfiguration, DefaultPointersConfig: traefikPointersConfiguration, diff --git a/pkg/server/uuid/uuid.go b/pkg/server/uuid/uuid.go deleted file mode 100644 index d8b7a6b57..000000000 --- a/pkg/server/uuid/uuid.go +++ /dev/null @@ -1,14 +0,0 @@ -package uuid - -import guuid "github.com/satori/go.uuid" - -var uuid string - -func init() { - uuid = guuid.NewV4().String() -} - -// Get the instance UUID -func Get() string { - return uuid -} diff --git a/vendor/github.com/aokoli/goutils/LICENSE.txt b/vendor/github.com/Masterminds/goutils/LICENSE.txt similarity index 100% rename from vendor/github.com/aokoli/goutils/LICENSE.txt rename to vendor/github.com/Masterminds/goutils/LICENSE.txt diff --git a/vendor/github.com/Masterminds/goutils/cryptorandomstringutils.go b/vendor/github.com/Masterminds/goutils/cryptorandomstringutils.go new file mode 100644 index 000000000..177dd8658 --- /dev/null +++ b/vendor/github.com/Masterminds/goutils/cryptorandomstringutils.go @@ -0,0 +1,251 @@ +/* +Copyright 2014 Alexander Okoli + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package goutils + +import ( + "crypto/rand" + "fmt" + "math" + "math/big" + "regexp" + "unicode" +) + +/* +CryptoRandomNonAlphaNumeric creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of all characters (ASCII/Unicode values between 0 to 2,147,483,647 (math.MaxInt32)). + +Parameter: + count - the length of random string to create + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...) +*/ +func CryptoRandomNonAlphaNumeric(count int) (string, error) { + return CryptoRandomAlphaNumericCustom(count, false, false) +} + +/* +CryptoRandomAscii creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of characters whose ASCII value is between 32 and 126 (inclusive). + +Parameter: + count - the length of random string to create + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...) +*/ +func CryptoRandomAscii(count int) (string, error) { + return CryptoRandom(count, 32, 127, false, false) +} + +/* +CryptoRandomNumeric creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of numeric characters. + +Parameter: + count - the length of random string to create + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...) +*/ +func CryptoRandomNumeric(count int) (string, error) { + return CryptoRandom(count, 0, 0, false, true) +} + +/* +CryptoRandomAlphabetic creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments. + +Parameters: + count - the length of random string to create + letters - if true, generated string may include alphabetic characters + numbers - if true, generated string may include numeric characters + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...) +*/ +func CryptoRandomAlphabetic(count int) (string, error) { + return CryptoRandom(count, 0, 0, true, false) +} + +/* +CryptoRandomAlphaNumeric creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of alpha-numeric characters. + +Parameter: + count - the length of random string to create + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...) +*/ +func CryptoRandomAlphaNumeric(count int) (string, error) { + if count == 0 { + return "", nil + } + RandomString, err := CryptoRandom(count, 0, 0, true, true) + if err != nil { + return "", fmt.Errorf("Error: %s", err) + } + match, err := regexp.MatchString("([0-9]+)", RandomString) + if err != nil { + panic(err) + } + + if !match { + //Get the position between 0 and the length of the string-1 to insert a random number + position := getCryptoRandomInt(count) + //Insert a random number between [0-9] in the position + RandomString = RandomString[:position] + string('0' + getCryptoRandomInt(10)) + RandomString[position + 1:] + return RandomString, err + } + return RandomString, err + +} + +/* +CryptoRandomAlphaNumericCustom creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments. + +Parameters: + count - the length of random string to create + letters - if true, generated string may include alphabetic characters + numbers - if true, generated string may include numeric characters + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...) +*/ +func CryptoRandomAlphaNumericCustom(count int, letters bool, numbers bool) (string, error) { + return CryptoRandom(count, 0, 0, letters, numbers) +} + +/* +CryptoRandom creates a random string based on a variety of options, using using golang's crypto/rand source of randomness. +If the parameters start and end are both 0, start and end are set to ' ' and 'z', the ASCII printable characters, will be used, +unless letters and numbers are both false, in which case, start and end are set to 0 and math.MaxInt32, respectively. +If chars is not nil, characters stored in chars that are between start and end are chosen. + +Parameters: + count - the length of random string to create + start - the position in set of chars (ASCII/Unicode int) to start at + end - the position in set of chars (ASCII/Unicode int) to end before + letters - if true, generated string may include alphabetic characters + numbers - if true, generated string may include numeric characters + chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars. + +Returns: + string - the random string + error - an error stemming from invalid parameters: if count < 0; or the provided chars array is empty; or end <= start; or end > len(chars) +*/ +func CryptoRandom(count int, start int, end int, letters bool, numbers bool, chars ...rune) (string, error) { + if count == 0 { + return "", nil + } else if count < 0 { + err := fmt.Errorf("randomstringutils illegal argument: Requested random string length %v is less than 0.", count) // equiv to err := errors.New("...") + return "", err + } + if chars != nil && len(chars) == 0 { + err := fmt.Errorf("randomstringutils illegal argument: The chars array must not be empty") + return "", err + } + + if start == 0 && end == 0 { + if chars != nil { + end = len(chars) + } else { + if !letters && !numbers { + end = math.MaxInt32 + } else { + end = 'z' + 1 + start = ' ' + } + } + } else { + if end <= start { + err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) must be greater than start (%v)", end, start) + return "", err + } + + if chars != nil && end > len(chars) { + err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) cannot be greater than len(chars) (%v)", end, len(chars)) + return "", err + } + } + + buffer := make([]rune, count) + gap := end - start + + // high-surrogates range, (\uD800-\uDBFF) = 55296 - 56319 + // low-surrogates range, (\uDC00-\uDFFF) = 56320 - 57343 + + for count != 0 { + count-- + var ch rune + if chars == nil { + ch = rune(getCryptoRandomInt(gap) + int64(start)) + } else { + ch = chars[getCryptoRandomInt(gap) + int64(start)] + } + + if letters && unicode.IsLetter(ch) || numbers && unicode.IsDigit(ch) || !letters && !numbers { + if ch >= 56320 && ch <= 57343 { // low surrogate range + if count == 0 { + count++ + } else { + // Insert low surrogate + buffer[count] = ch + count-- + // Insert high surrogate + buffer[count] = rune(55296 + getCryptoRandomInt(128)) + } + } else if ch >= 55296 && ch <= 56191 { // High surrogates range (Partial) + if count == 0 { + count++ + } else { + // Insert low surrogate + buffer[count] = rune(56320 + getCryptoRandomInt(128)) + count-- + // Insert high surrogate + buffer[count] = ch + } + } else if ch >= 56192 && ch <= 56319 { + // private high surrogate, skip it + count++ + } else { + // not one of the surrogates* + buffer[count] = ch + } + } else { + count++ + } + } + return string(buffer), nil +} + +func getCryptoRandomInt(count int) int64 { + nBig, err := rand.Int(rand.Reader, big.NewInt(int64(count))) + if err != nil { + panic(err) + } + return nBig.Int64() +} diff --git a/vendor/github.com/aokoli/goutils/randomstringutils.go b/vendor/github.com/Masterminds/goutils/randomstringutils.go similarity index 100% rename from vendor/github.com/aokoli/goutils/randomstringutils.go rename to vendor/github.com/Masterminds/goutils/randomstringutils.go diff --git a/vendor/github.com/aokoli/goutils/stringutils.go b/vendor/github.com/Masterminds/goutils/stringutils.go similarity index 100% rename from vendor/github.com/aokoli/goutils/stringutils.go rename to vendor/github.com/Masterminds/goutils/stringutils.go diff --git a/vendor/github.com/aokoli/goutils/wordutils.go b/vendor/github.com/Masterminds/goutils/wordutils.go similarity index 98% rename from vendor/github.com/aokoli/goutils/wordutils.go rename to vendor/github.com/Masterminds/goutils/wordutils.go index e92dd3990..034cad8e2 100644 --- a/vendor/github.com/aokoli/goutils/wordutils.go +++ b/vendor/github.com/Masterminds/goutils/wordutils.go @@ -129,14 +129,15 @@ func WrapCustom(str string, wrapLength int, newLineStr string, wrapLongWords boo } else { // long words aren't wrapped, just extended beyond limit end := wrapLength + offset - spaceToWrapAt = strings.IndexRune(str[end:len(str)], ' ') + end - if spaceToWrapAt >= 0 { + index := strings.IndexRune(str[end:len(str)], ' ') + if index == -1 { + wrappedLine.WriteString(str[offset:len(str)]) + offset = inputLineLength + } else { + spaceToWrapAt = index + end wrappedLine.WriteString(str[offset:spaceToWrapAt]) wrappedLine.WriteString(newLineStr) offset = spaceToWrapAt + 1 - } else { - wrappedLine.WriteString(str[offset:len(str)]) - offset = inputLineLength } } } diff --git a/vendor/github.com/Masterminds/sprig/crypto.go b/vendor/github.com/Masterminds/sprig/crypto.go index a935b6c1a..7427deb83 100644 --- a/vendor/github.com/Masterminds/sprig/crypto.go +++ b/vendor/github.com/Masterminds/sprig/crypto.go @@ -8,16 +8,23 @@ import ( "crypto/hmac" "crypto/rand" "crypto/rsa" + "crypto/sha1" "crypto/sha256" "crypto/x509" + "crypto/x509/pkix" "encoding/asn1" + "encoding/base64" "encoding/binary" "encoding/hex" "encoding/pem" + "errors" "fmt" + "hash/adler32" "math/big" + "net" + "time" - uuid "github.com/satori/go.uuid" + "github.com/google/uuid" "golang.org/x/crypto/scrypt" ) @@ -26,9 +33,19 @@ func sha256sum(input string) string { return hex.EncodeToString(hash[:]) } +func sha1sum(input string) string { + hash := sha1.Sum([]byte(input)) + return hex.EncodeToString(hash[:]) +} + +func adler32sum(input string) string { + hash := adler32.Checksum([]byte(input)) + return fmt.Sprintf("%d", hash) +} + // uuidv4 provides a safe and secure UUID v4 implementation func uuidv4() string { - return fmt.Sprintf("%s", uuid.NewV4()) + return fmt.Sprintf("%s", uuid.New()) } var master_password_seed = "com.lyndir.masterpassword" @@ -146,3 +163,279 @@ func pemBlockForKey(priv interface{}) *pem.Block { return nil } } + +type certificate struct { + Cert string + Key string +} + +func buildCustomCertificate(b64cert string, b64key string) (certificate, error) { + crt := certificate{} + + cert, err := base64.StdEncoding.DecodeString(b64cert) + if err != nil { + return crt, errors.New("unable to decode base64 certificate") + } + + key, err := base64.StdEncoding.DecodeString(b64key) + if err != nil { + return crt, errors.New("unable to decode base64 private key") + } + + decodedCert, _ := pem.Decode(cert) + if decodedCert == nil { + return crt, errors.New("unable to decode certificate") + } + _, err = x509.ParseCertificate(decodedCert.Bytes) + if err != nil { + return crt, fmt.Errorf( + "error parsing certificate: decodedCert.Bytes: %s", + err, + ) + } + + decodedKey, _ := pem.Decode(key) + if decodedKey == nil { + return crt, errors.New("unable to decode key") + } + _, err = x509.ParsePKCS1PrivateKey(decodedKey.Bytes) + if err != nil { + return crt, fmt.Errorf( + "error parsing prive key: decodedKey.Bytes: %s", + err, + ) + } + + crt.Cert = string(cert) + crt.Key = string(key) + + return crt, nil +} + +func generateCertificateAuthority( + cn string, + daysValid int, +) (certificate, error) { + ca := certificate{} + + template, err := getBaseCertTemplate(cn, nil, nil, daysValid) + if err != nil { + return ca, err + } + // Override KeyUsage and IsCA + template.KeyUsage = x509.KeyUsageKeyEncipherment | + x509.KeyUsageDigitalSignature | + x509.KeyUsageCertSign + template.IsCA = true + + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return ca, fmt.Errorf("error generating rsa key: %s", err) + } + + ca.Cert, ca.Key, err = getCertAndKey(template, priv, template, priv) + if err != nil { + return ca, err + } + + return ca, nil +} + +func generateSelfSignedCertificate( + cn string, + ips []interface{}, + alternateDNS []interface{}, + daysValid int, +) (certificate, error) { + cert := certificate{} + + template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid) + if err != nil { + return cert, err + } + + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return cert, fmt.Errorf("error generating rsa key: %s", err) + } + + cert.Cert, cert.Key, err = getCertAndKey(template, priv, template, priv) + if err != nil { + return cert, err + } + + return cert, nil +} + +func generateSignedCertificate( + cn string, + ips []interface{}, + alternateDNS []interface{}, + daysValid int, + ca certificate, +) (certificate, error) { + cert := certificate{} + + decodedSignerCert, _ := pem.Decode([]byte(ca.Cert)) + if decodedSignerCert == nil { + return cert, errors.New("unable to decode certificate") + } + signerCert, err := x509.ParseCertificate(decodedSignerCert.Bytes) + if err != nil { + return cert, fmt.Errorf( + "error parsing certificate: decodedSignerCert.Bytes: %s", + err, + ) + } + decodedSignerKey, _ := pem.Decode([]byte(ca.Key)) + if decodedSignerKey == nil { + return cert, errors.New("unable to decode key") + } + signerKey, err := x509.ParsePKCS1PrivateKey(decodedSignerKey.Bytes) + if err != nil { + return cert, fmt.Errorf( + "error parsing prive key: decodedSignerKey.Bytes: %s", + err, + ) + } + + template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid) + if err != nil { + return cert, err + } + + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return cert, fmt.Errorf("error generating rsa key: %s", err) + } + + cert.Cert, cert.Key, err = getCertAndKey( + template, + priv, + signerCert, + signerKey, + ) + if err != nil { + return cert, err + } + + return cert, nil +} + +func getCertAndKey( + template *x509.Certificate, + signeeKey *rsa.PrivateKey, + parent *x509.Certificate, + signingKey *rsa.PrivateKey, +) (string, string, error) { + derBytes, err := x509.CreateCertificate( + rand.Reader, + template, + parent, + &signeeKey.PublicKey, + signingKey, + ) + if err != nil { + return "", "", fmt.Errorf("error creating certificate: %s", err) + } + + certBuffer := bytes.Buffer{} + if err := pem.Encode( + &certBuffer, + &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}, + ); err != nil { + return "", "", fmt.Errorf("error pem-encoding certificate: %s", err) + } + + keyBuffer := bytes.Buffer{} + if err := pem.Encode( + &keyBuffer, + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(signeeKey), + }, + ); err != nil { + return "", "", fmt.Errorf("error pem-encoding key: %s", err) + } + + return string(certBuffer.Bytes()), string(keyBuffer.Bytes()), nil +} + +func getBaseCertTemplate( + cn string, + ips []interface{}, + alternateDNS []interface{}, + daysValid int, +) (*x509.Certificate, error) { + ipAddresses, err := getNetIPs(ips) + if err != nil { + return nil, err + } + dnsNames, err := getAlternateDNSStrs(alternateDNS) + if err != nil { + return nil, err + } + serialNumberUpperBound := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberUpperBound) + if err != nil { + return nil, err + } + return &x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: cn, + }, + IPAddresses: ipAddresses, + DNSNames: dnsNames, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(daysValid)), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, + }, + BasicConstraintsValid: true, + }, nil +} + +func getNetIPs(ips []interface{}) ([]net.IP, error) { + if ips == nil { + return []net.IP{}, nil + } + var ipStr string + var ok bool + var netIP net.IP + netIPs := make([]net.IP, len(ips)) + for i, ip := range ips { + ipStr, ok = ip.(string) + if !ok { + return nil, fmt.Errorf("error parsing ip: %v is not a string", ip) + } + netIP = net.ParseIP(ipStr) + if netIP == nil { + return nil, fmt.Errorf("error parsing ip: %s", ipStr) + } + netIPs[i] = netIP + } + return netIPs, nil +} + +func getAlternateDNSStrs(alternateDNS []interface{}) ([]string, error) { + if alternateDNS == nil { + return []string{}, nil + } + var dnsStr string + var ok bool + alternateDNSStrs := make([]string, len(alternateDNS)) + for i, dns := range alternateDNS { + dnsStr, ok = dns.(string) + if !ok { + return nil, fmt.Errorf( + "error processing alternate dns name: %v is not a string", + dns, + ) + } + alternateDNSStrs[i] = dnsStr + } + return alternateDNSStrs, nil +} diff --git a/vendor/github.com/Masterminds/sprig/date.go b/vendor/github.com/Masterminds/sprig/date.go index dc5263f24..1c2c3653c 100644 --- a/vendor/github.com/Masterminds/sprig/date.go +++ b/vendor/github.com/Masterminds/sprig/date.go @@ -51,3 +51,26 @@ func dateModify(fmt string, date time.Time) time.Time { } return date.Add(d) } + +func dateAgo(date interface{}) string { + var t time.Time + + switch date := date.(type) { + default: + t = time.Now() + case time.Time: + t = date + case int64: + t = time.Unix(date, 0) + case int: + t = time.Unix(int64(date), 0) + } + // Drop resolution to seconds + duration := time.Since(t).Round(time.Second) + return duration.String() +} + +func toDate(fmt, str string) time.Time { + t, _ := time.ParseInLocation(fmt, str, time.Local) + return t +} diff --git a/vendor/github.com/Masterminds/sprig/defaults.go b/vendor/github.com/Masterminds/sprig/defaults.go index a2381d66b..ed6a8ab29 100644 --- a/vendor/github.com/Masterminds/sprig/defaults.go +++ b/vendor/github.com/Masterminds/sprig/defaults.go @@ -49,7 +49,6 @@ func empty(given interface{}) bool { case reflect.Struct: return false } - return true } // coalesce returns the first non-empty value. @@ -73,3 +72,12 @@ func toPrettyJson(v interface{}) string { output, _ := json.MarshalIndent(v, "", " ") return string(output) } + +// ternary returns the first value if the last value is true, otherwise returns the second value. +func ternary(vt interface{}, vf interface{}, v bool) interface{} { + if v { + return vt + } + + return vf +} diff --git a/vendor/github.com/Masterminds/sprig/dict.go b/vendor/github.com/Masterminds/sprig/dict.go index 46692d15d..026eccb73 100644 --- a/vendor/github.com/Masterminds/sprig/dict.go +++ b/vendor/github.com/Masterminds/sprig/dict.go @@ -27,10 +27,12 @@ func pluck(key string, d ...map[string]interface{}) []interface{} { return res } -func keys(dict map[string]interface{}) []string { +func keys(dicts ...map[string]interface{}) []string { k := []string{} - for key := range dict { - k = append(k, key) + for _, dict := range dicts { + for key := range dict { + k = append(k, key) + } } return k } @@ -75,10 +77,31 @@ func dict(v ...interface{}) map[string]interface{} { return dict } -func merge(dst map[string]interface{}, src map[string]interface{}) interface{} { - if err := mergo.Merge(&dst, src); err != nil { - // Swallow errors inside of a template. - return "" +func merge(dst map[string]interface{}, srcs ...map[string]interface{}) interface{} { + for _, src := range srcs { + if err := mergo.Merge(&dst, src); err != nil { + // Swallow errors inside of a template. + return "" + } } return dst } + +func mergeOverwrite(dst map[string]interface{}, srcs ...map[string]interface{}) interface{} { + for _, src := range srcs { + if err := mergo.MergeWithOverwrite(&dst, src); err != nil { + // Swallow errors inside of a template. + return "" + } + } + return dst +} + +func values(dict map[string]interface{}) []interface{} { + values := []interface{}{} + for _, value := range dict { + values = append(values, value) + } + + return values +} diff --git a/vendor/github.com/Masterminds/sprig/doc.go b/vendor/github.com/Masterminds/sprig/doc.go index 0eac8e27a..8f8f1d737 100644 --- a/vendor/github.com/Masterminds/sprig/doc.go +++ b/vendor/github.com/Masterminds/sprig/doc.go @@ -14,212 +14,6 @@ Note that you should add the function map before you parse any template files. appear in the standard library. This is to make it easier to pipe arguments into functions. -Date Functions - - - date FORMAT TIME: Format a date, where a date is an integer type or a time.Time type, and - format is a time.Format formatting string. - - dateModify: Given a date, modify it with a duration: `date_modify "-1.5h" now`. If the duration doesn't - parse, it returns the time unaltered. See `time.ParseDuration` for info on duration strings. - - now: Current time.Time, for feeding into date-related functions. - - htmlDate TIME: Format a date for use in the value field of an HTML "date" form element. - - dateInZone FORMAT TIME TZ: Like date, but takes three arguments: format, timestamp, - timezone. - - htmlDateInZone TIME TZ: Like htmlDate, but takes two arguments: timestamp, - timezone. - -String Functions - - - abbrev: Truncate a string with ellipses. `abbrev 5 "hello world"` yields "he..." - - abbrevboth: Abbreviate from both sides, yielding "...lo wo..." - - trunc: Truncate a string (no suffix). `trunc 5 "Hello World"` yields "hello". - - trim: strings.TrimSpace - - trimAll: strings.Trim, but with the argument order reversed `trimAll "$" "$5.00"` or `"$5.00 | trimAll "$"` - - trimSuffix: strings.TrimSuffix, but with the argument order reversed: `trimSuffix "-" "ends-with-"` - - trimPrefix: strings.TrimPrefix, but with the argument order reversed `trimPrefix "$" "$5"` - - upper: strings.ToUpper - - lower: strings.ToLower - - nospace: Remove all space characters from a string. `nospace "h e l l o"` becomes "hello" - - title: strings.Title - - untitle: Remove title casing - - repeat: strings.Repeat, but with the arguments switched: `repeat count str`. (This simplifies common pipelines) - - substr: Given string, start, and length, return a substr. - - initials: Given a multi-word string, return the initials. `initials "Matt Butcher"` returns "MB" - - randAlphaNum: Given a length, generate a random alphanumeric sequence - - randAlpha: Given a length, generate an alphabetic string - - randAscii: Given a length, generate a random ASCII string (symbols included) - - randNumeric: Given a length, generate a string of digits. - - wrap: Force a line wrap at the given width. `wrap 80 "imagine a longer string"` - - wrapWith: Wrap a line at the given length, but using 'sep' instead of a newline. `wrapWith 50, "
", $html` - - contains: strings.Contains, but with the arguments switched: `contains substr str`. (This simplifies common pipelines) - - hasPrefix: strings.hasPrefix, but with the arguments switched - - hasSuffix: strings.hasSuffix, but with the arguments switched - - quote: Wrap string(s) in double quotation marks, escape the contents by adding '\' before '"'. - - squote: Wrap string(s) in double quotation marks, does not escape content. - - cat: Concatenate strings, separating them by spaces. `cat $a $b $c`. - - indent: Indent a string using space characters. `indent 4 "foo\nbar"` produces " foo\n bar" - - replace: Replace an old with a new in a string: `$name | replace " " "-"` - - plural: Choose singular or plural based on length: `len $fish | plural "one anchovy" "many anchovies"` - - sha256sum: Generate a hex encoded sha256 hash of the input - - toString: Convert something to a string - -String Slice Functions: - - - join: strings.Join, but as `join SEP SLICE` - - split: strings.Split, but as `split SEP STRING`. The results are returned - as a map with the indexes set to _N, where N is an integer starting from 0. - Use it like this: `{{$v := "foo/bar/baz" | split "/"}}{{$v._0}}` (Prints `foo`) - - splitList: strings.Split, but as `split SEP STRING`. The results are returned - as an array. - - toStrings: convert a list to a list of strings. 'list 1 2 3 | toStrings' produces '["1" "2" "3"]' - - sortAlpha: sort a list lexicographically. - -Integer Slice Functions: - - - until: Given an integer, returns a slice of counting integers from 0 to one - less than the given integer: `range $i, $e := until 5` - - untilStep: Given start, stop, and step, return an integer slice starting at - 'start', stopping at `stop`, and incrementing by 'step. This is the same - as Python's long-form of 'range'. - -Conversions: - - - atoi: Convert a string to an integer. 0 if the integer could not be parsed. - - in64: Convert a string or another numeric type to an int64. - - int: Convert a string or another numeric type to an int. - - float64: Convert a string or another numeric type to a float64. - -Defaults: - - - default: Give a default value. Used like this: trim " "| default "empty". - Since trim produces an empty string, the default value is returned. For - things with a length (strings, slices, maps), len(0) will trigger the default. - For numbers, the value 0 will trigger the default. For booleans, false will - trigger the default. For structs, the default is never returned (there is - no clear empty condition). For everything else, nil value triggers a default. - - empty: Return true if the given value is the zero value for its type. - Caveats: structs are always non-empty. This should match the behavior of - {{if pipeline}}, but can be used inside of a pipeline. - - coalesce: Given a list of items, return the first non-empty one. - This follows the same rules as 'empty'. '{{ coalesce .someVal 0 "hello" }}` - will return `.someVal` if set, or else return "hello". The 0 is skipped - because it is an empty value. - - compact: Return a copy of a list with all of the empty values removed. - 'list 0 1 2 "" | compact' will return '[1 2]' - -OS: - - env: Resolve an environment variable - - expandenv: Expand a string through the environment - -File Paths: - - base: Return the last element of a path. https://golang.org/pkg/path#Base - - dir: Remove the last element of a path. https://golang.org/pkg/path#Dir - - clean: Clean a path to the shortest equivalent name. (e.g. remove "foo/.." - from "foo/../bar.html") https://golang.org/pkg/path#Clean - - ext: https://golang.org/pkg/path#Ext - - isAbs: https://golang.org/pkg/path#IsAbs - -Encoding: - - b64enc: Base 64 encode a string. - - b64dec: Base 64 decode a string. - -Reflection: - - - typeOf: Takes an interface and returns a string representation of the type. - For pointers, this will return a type prefixed with an asterisk(`*`). So - a pointer to type `Foo` will be `*Foo`. - - typeIs: Compares an interface with a string name, and returns true if they match. - Note that a pointer will not match a reference. For example `*Foo` will not - match `Foo`. - - typeIsLike: Compares an interface with a string name and returns true if - the interface is that `name` or that `*name`. In other words, if the given - value matches the given type or is a pointer to the given type, this returns - true. - - kindOf: Takes an interface and returns a string representation of its kind. - - kindIs: Returns true if the given string matches the kind of the given interface. - - Note: None of these can test whether or not something implements a given - interface, since doing so would require compiling the interface in ahead of - time. - -Data Structures: - - - tuple: Takes an arbitrary list of items and returns a slice of items. Its - tuple-ish properties are mainly gained through the template idiom, and not - through an API provided here. WARNING: The implementation of tuple will - change in the future. - - list: An arbitrary ordered list of items. (This is prefered over tuple.) - - dict: Takes a list of name/values and returns a map[string]interface{}. - The first parameter is converted to a string and stored as a key, the - second parameter is treated as the value. And so on, with odds as keys and - evens as values. If the function call ends with an odd, the last key will - be assigned the empty string. Non-string keys are converted to strings as - follows: []byte are converted, fmt.Stringers will have String() called. - errors will have Error() called. All others will be passed through - fmt.Sprtinf("%v"). - -Lists Functions: - -These are used to manipulate lists: '{{ list 1 2 3 | reverse | first }}' - - - first: Get the first item in a 'list'. 'list 1 2 3 | first' prints '1' - - last: Get the last item in a 'list': 'list 1 2 3 | last ' prints '3' - - rest: Get all but the first item in a list: 'list 1 2 3 | rest' returns '[2 3]' - - initial: Get all but the last item in a list: 'list 1 2 3 | initial' returns '[1 2]' - - append: Add an item to the end of a list: 'append $list 4' adds '4' to the end of '$list' - - prepend: Add an item to the beginning of a list: 'prepend $list 4' puts 4 at the beginning of the list. - - reverse: Reverse the items in a list. - - uniq: Remove duplicates from a list. - - without: Return a list with the given values removed: 'without (list 1 2 3) 1' would return '[2 3]' - - has: Return 'true' if the item is found in the list: 'has "foo" $list' will return 'true' if the list contains "foo" - -Dict Functions: - -These are used to manipulate dicts. - - - set: Takes a dict, a key, and a value, and sets that key/value pair in - the dict. `set $dict $key $value`. For convenience, it returns the dict, - even though the dict was modified in place. - - unset: Takes a dict and a key, and deletes that key/value pair from the - dict. `unset $dict $key`. This returns the dict for convenience. - - hasKey: Takes a dict and a key, and returns boolean true if the key is in - the dict. - - pluck: Given a key and one or more maps, get all of the values for that key. - - keys: Get an array of all of the keys in a dict. - - pick: Select just the given keys out of the dict, and return a new dict. - - omit: Return a dict without the given keys. - -Math Functions: - -Integer functions will convert integers of any width to `int64`. If a -string is passed in, functions will attempt to convert with -`strconv.ParseInt(s, 1064)`. If this fails, the value will be treated as 0. - - - add1: Increment an integer by 1 - - add: Sum an arbitrary number of integers - - sub: Subtract the second integer from the first - - div: Divide the first integer by the second - - mod: Module of first integer divided by second - - mul: Multiply integers - - max: Return the biggest of a series of one or more integers - - min: Return the smallest of a series of one or more integers - - biggest: DEPRECATED. Return the biggest of a series of one or more integers - -Crypto Functions: - - - genPrivateKey: Generate a private key for the given cryptosystem. If no - argument is supplied, by default it will generate a private key using - the RSA algorithm. Accepted values are `rsa`, `dsa`, and `ecdsa`. - - derivePassword: Derive a password from the given parameters according to the ["Master Password" algorithm](http://masterpasswordapp.com/algorithm.html) - Given parameters (in order) are: - `counter` (starting with 1), `password_type` (maximum, long, medium, short, basic, or pin), `password`, - `user`, and `site` - -SemVer Functions: - -These functions provide version parsing and comparisons for SemVer 2 version -strings. - - - semver: Parse a semantic version and return a Version object. - - semverCompare: Compare a SemVer range to a particular version. +See http://masterminds.github.io/sprig/ for more detailed documentation on each of the available functions. */ package sprig diff --git a/vendor/github.com/Masterminds/sprig/functions.go b/vendor/github.com/Masterminds/sprig/functions.go index c20175b25..6397be696 100644 --- a/vendor/github.com/Masterminds/sprig/functions.go +++ b/vendor/github.com/Masterminds/sprig/functions.go @@ -10,7 +10,7 @@ import ( ttemplate "text/template" "time" - util "github.com/aokoli/goutils" + util "github.com/Masterminds/goutils" "github.com/huandu/xstrings" ) @@ -98,6 +98,8 @@ var genericMap = map[string]interface{}{ "htmlDateInZone": htmlDateInZone, "dateInZone": dateInZone, "dateModify": dateModify, + "ago": dateAgo, + "toDate": toDate, // Strings "abbrev": abbrev, @@ -127,6 +129,7 @@ var genericMap = map[string]interface{}{ "shuffle": xstrings.Shuffle, "snakecase": xstrings.ToSnakeCase, "camelcase": xstrings.ToCamelCase, + "kebabcase": xstrings.ToKebabCase, "wrap": func(l int, s string) string { return util.Wrap(s, l) }, "wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) }, // Switch order so that "foobar" | contains "foo" @@ -137,9 +140,12 @@ var genericMap = map[string]interface{}{ "squote": squote, "cat": cat, "indent": indent, + "nindent": nindent, "replace": replace, "plural": plural, + "sha1sum": sha1sum, "sha256sum": sha256sum, + "adler32sum": adler32sum, "toString": strval, // Wrap Atoi to stop errors. @@ -156,6 +162,8 @@ var genericMap = map[string]interface{}{ // split "/" foo/bar returns map[int]string{0: foo, 1: bar} "split": split, "splitList": func(sep, orig string) []string { return strings.Split(orig, sep) }, + // splitn "/" foo/bar/fuu returns map[int]string{0: foo, 1: bar/fuu} + "splitn": splitn, "toStrings": strslice, "until": until, @@ -199,6 +207,7 @@ var genericMap = map[string]interface{}{ "compact": compact, "toJson": toJson, "toPrettyJson": toPrettyJson, + "ternary": ternary, // Reflection "typeOf": typeOf, @@ -236,6 +245,8 @@ var genericMap = map[string]interface{}{ "pick": pick, "omit": omit, "merge": merge, + "mergeOverwrite": mergeOverwrite, + "values": values, "append": push, "push": push, "prepend": prepend, @@ -246,11 +257,16 @@ var genericMap = map[string]interface{}{ "reverse": reverse, "uniq": uniq, "without": without, - "has": func(needle interface{}, haystack []interface{}) bool { return inList(haystack, needle) }, + "has": has, + "slice": slice, // Crypto: - "genPrivateKey": generatePrivateKey, - "derivePassword": derivePassword, + "genPrivateKey": generatePrivateKey, + "derivePassword": derivePassword, + "buildCustomCert": buildCustomCertificate, + "genCA": generateCertificateAuthority, + "genSelfSignedCert": generateSelfSignedCertificate, + "genSignedCert": generateSignedCertificate, // UUIDs: "uuidv4": uuidv4, @@ -263,10 +279,10 @@ var genericMap = map[string]interface{}{ "fail": func(msg string) (string, error) { return "", errors.New(msg) }, // Regex - "regexMatch": regexMatch, - "regexFindAll": regexFindAll, - "regexFind": regexFind, - "regexReplaceAll": regexReplaceAll, + "regexMatch": regexMatch, + "regexFindAll": regexFindAll, + "regexFind": regexFind, + "regexReplaceAll": regexReplaceAll, "regexReplaceAllLiteral": regexReplaceAllLiteral, - "regexSplit": regexSplit, + "regexSplit": regexSplit, } diff --git a/vendor/github.com/Masterminds/sprig/list.go b/vendor/github.com/Masterminds/sprig/list.go index 0c47b8c8a..41e136625 100644 --- a/vendor/github.com/Masterminds/sprig/list.go +++ b/vendor/github.com/Masterminds/sprig/list.go @@ -1,50 +1,135 @@ package sprig import ( + "fmt" "reflect" "sort" ) +// Reflection is used in these functions so that slices and arrays of strings, +// ints, and other types not implementing []interface{} can be worked with. +// For example, this is useful if you need to work on the output of regexs. + func list(v ...interface{}) []interface{} { return v } -func push(list []interface{}, v interface{}) []interface{} { - return append(list, v) -} +func push(list interface{}, v interface{}) []interface{} { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) -func prepend(list []interface{}, v interface{}) []interface{} { - return append([]interface{}{v}, list...) -} + l := l2.Len() + nl := make([]interface{}, l) + for i := 0; i < l; i++ { + nl[i] = l2.Index(i).Interface() + } -func last(list []interface{}) interface{} { - l := len(list) - if l == 0 { - return nil + return append(nl, v) + + default: + panic(fmt.Sprintf("Cannot push on type %s", tp)) } - return list[l-1] } -func first(list []interface{}) interface{} { - if len(list) == 0 { - return nil +func prepend(list interface{}, v interface{}) []interface{} { + //return append([]interface{}{v}, list...) + + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + nl := make([]interface{}, l) + for i := 0; i < l; i++ { + nl[i] = l2.Index(i).Interface() + } + + return append([]interface{}{v}, nl...) + + default: + panic(fmt.Sprintf("Cannot prepend on type %s", tp)) } - return list[0] } -func rest(list []interface{}) []interface{} { - if len(list) == 0 { - return list +func last(list interface{}) interface{} { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil + } + + return l2.Index(l - 1).Interface() + default: + panic(fmt.Sprintf("Cannot find last on type %s", tp)) } - return list[1:] } -func initial(list []interface{}) []interface{} { - l := len(list) - if l == 0 { - return list +func first(list interface{}) interface{} { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil + } + + return l2.Index(0).Interface() + default: + panic(fmt.Sprintf("Cannot find first on type %s", tp)) + } +} + +func rest(list interface{}) []interface{} { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil + } + + nl := make([]interface{}, l-1) + for i := 1; i < l; i++ { + nl[i-1] = l2.Index(i).Interface() + } + + return nl + default: + panic(fmt.Sprintf("Cannot find rest on type %s", tp)) + } +} + +func initial(list interface{}) []interface{} { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil + } + + nl := make([]interface{}, l-1) + for i := 0; i < l-1; i++ { + nl[i] = l2.Index(i).Interface() + } + + return nl + default: + panic(fmt.Sprintf("Cannot find initial on type %s", tp)) } - return list[:l-1] } func sortAlpha(list interface{}) []string { @@ -59,34 +144,67 @@ func sortAlpha(list interface{}) []string { return []string{strval(list)} } -func reverse(v []interface{}) []interface{} { - // We do not sort in place because the incomming array should not be altered. - l := len(v) - c := make([]interface{}, l) - for i := 0; i < l; i++ { - c[l-i-1] = v[i] +func reverse(v interface{}) []interface{} { + tp := reflect.TypeOf(v).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(v) + + l := l2.Len() + // We do not sort in place because the incoming array should not be altered. + nl := make([]interface{}, l) + for i := 0; i < l; i++ { + nl[l-i-1] = l2.Index(i).Interface() + } + + return nl + default: + panic(fmt.Sprintf("Cannot find reverse on type %s", tp)) } - return c } -func compact(list []interface{}) []interface{} { - res := []interface{}{} - for _, item := range list { - if !empty(item) { - res = append(res, item) +func compact(list interface{}) []interface{} { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + nl := []interface{}{} + var item interface{} + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if !empty(item) { + nl = append(nl, item) + } } + + return nl + default: + panic(fmt.Sprintf("Cannot compact on type %s", tp)) } - return res } -func uniq(list []interface{}) []interface{} { - dest := []interface{}{} - for _, item := range list { - if !inList(dest, item) { - dest = append(dest, item) +func uniq(list interface{}) []interface{} { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + dest := []interface{}{} + var item interface{} + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if !inList(dest, item) { + dest = append(dest, item) + } } + + return dest + default: + panic(fmt.Sprintf("Cannot find uniq on type %s", tp)) } - return dest } func inList(haystack []interface{}, needle interface{}) bool { @@ -98,12 +216,79 @@ func inList(haystack []interface{}, needle interface{}) bool { return false } -func without(list []interface{}, omit ...interface{}) []interface{} { - res := []interface{}{} - for _, i := range list { - if !inList(omit, i) { - res = append(res, i) +func without(list interface{}, omit ...interface{}) []interface{} { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + res := []interface{}{} + var item interface{} + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if !inList(omit, item) { + res = append(res, item) + } } + + return res + default: + panic(fmt.Sprintf("Cannot find without on type %s", tp)) + } +} + +func has(needle interface{}, haystack interface{}) bool { + if haystack == nil { + return false + } + tp := reflect.TypeOf(haystack).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(haystack) + var item interface{} + l := l2.Len() + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if reflect.DeepEqual(needle, item) { + return true + } + } + + return false + default: + panic(fmt.Sprintf("Cannot find has on type %s", tp)) + } +} + +// $list := [1, 2, 3, 4, 5] +// slice $list -> list[0:5] = list[:] +// slice $list 0 3 -> list[0:3] = list[:3] +// slice $list 3 5 -> list[3:5] +// slice $list 3 -> list[3:5] = list[3:] +func slice(list interface{}, indices ...interface{}) interface{} { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil + } + + var start, end int + if len(indices) > 0 { + start = toInt(indices[0]) + } + if len(indices) < 2 { + end = l + } else { + end = toInt(indices[1]) + } + + return l2.Slice(start, end).Interface() + default: + panic(fmt.Sprintf("list should be type of slice or array but %s", tp)) } - return res } diff --git a/vendor/github.com/Masterminds/sprig/numeric.go b/vendor/github.com/Masterminds/sprig/numeric.go index 209c62e53..4bd89bf7f 100644 --- a/vendor/github.com/Masterminds/sprig/numeric.go +++ b/vendor/github.com/Masterminds/sprig/numeric.go @@ -156,4 +156,4 @@ func round(a interface{}, p int, r_opt ...float64) float64 { round = math.Floor(digit) } return round / pow -} \ No newline at end of file +} diff --git a/vendor/github.com/Masterminds/sprig/regex.go b/vendor/github.com/Masterminds/sprig/regex.go index 9fe033a6b..2016f6633 100644 --- a/vendor/github.com/Masterminds/sprig/regex.go +++ b/vendor/github.com/Masterminds/sprig/regex.go @@ -32,4 +32,4 @@ func regexReplaceAllLiteral(regex string, s string, repl string) string { func regexSplit(regex string, s string, n int) []string { r := regexp.MustCompile(regex) return r.Split(s, n) -} \ No newline at end of file +} diff --git a/vendor/github.com/Masterminds/sprig/strings.go b/vendor/github.com/Masterminds/sprig/strings.go index 69bcd9854..943fa3e8a 100644 --- a/vendor/github.com/Masterminds/sprig/strings.go +++ b/vendor/github.com/Masterminds/sprig/strings.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - util "github.com/aokoli/goutils" + util "github.com/Masterminds/goutils" ) func base64encode(v string) string { @@ -57,22 +57,22 @@ func initials(s string) string { func randAlphaNumeric(count int) string { // It is not possible, it appears, to actually generate an error here. - r, _ := util.RandomAlphaNumeric(count) + r, _ := util.CryptoRandomAlphaNumeric(count) return r } func randAlpha(count int) string { - r, _ := util.RandomAlphabetic(count) + r, _ := util.CryptoRandomAlphabetic(count) return r } func randAscii(count int) string { - r, _ := util.RandomAscii(count) + r, _ := util.CryptoRandomAscii(count) return r } func randNumeric(count int) string { - r, _ := util.RandomNumeric(count) + r, _ := util.CryptoRandomNumeric(count) return r } @@ -81,22 +81,27 @@ func untitle(str string) string { } func quote(str ...interface{}) string { - out := make([]string, len(str)) - for i, s := range str { - out[i] = fmt.Sprintf("%q", strval(s)) + out := make([]string, 0, len(str)) + for _, s := range str { + if s != nil { + out = append(out, fmt.Sprintf("%q", strval(s))) + } } return strings.Join(out, " ") } func squote(str ...interface{}) string { - out := make([]string, len(str)) - for i, s := range str { - out[i] = fmt.Sprintf("'%v'", s) + out := make([]string, 0, len(str)) + for _, s := range str { + if s != nil { + out = append(out, fmt.Sprintf("'%v'", s)) + } } return strings.Join(out, " ") } func cat(v ...interface{}) string { + v = removeNilElements(v) r := strings.TrimSpace(strings.Repeat("%v ", len(v))) return fmt.Sprintf(r, v...) } @@ -106,6 +111,10 @@ func indent(spaces int, v string) string { return pad + strings.Replace(v, "\n", "\n"+pad, -1) } +func nindent(spaces int, v string) string { + return "\n" + indent(spaces, v) +} + func replace(old, new, src string) string { return strings.Replace(src, old, new, -1) } @@ -122,10 +131,11 @@ func strslice(v interface{}) []string { case []string: return v case []interface{}: - l := len(v) - b := make([]string, l) - for i := 0; i < l; i++ { - b[i] = strval(v[i]) + b := make([]string, 0, len(v)) + for _, s := range v { + if s != nil { + b = append(b, strval(s)) + } } return b default: @@ -133,17 +143,34 @@ func strslice(v interface{}) []string { switch val.Kind() { case reflect.Array, reflect.Slice: l := val.Len() - b := make([]string, l) + b := make([]string, 0, l) for i := 0; i < l; i++ { - b[i] = strval(val.Index(i).Interface()) + value := val.Index(i).Interface() + if value != nil { + b = append(b, strval(value)) + } } return b default: - return []string{strval(v)} + if v == nil { + return []string{} + } else { + return []string{strval(v)} + } } } } +func removeNilElements(v []interface{}) []interface{} { + newSlice := make([]interface{}, 0, len(v)) + for _, i := range v { + if i != nil { + newSlice = append(newSlice, i) + } + } + return newSlice +} + func strval(v interface{}) string { switch v := v.(type) { case string: @@ -179,19 +206,28 @@ func split(sep, orig string) map[string]string { return res } +func splitn(sep string, n int, orig string) map[string]string { + parts := strings.SplitN(orig, sep, n) + res := make(map[string]string, len(parts)) + for i, v := range parts { + res["_"+strconv.Itoa(i)] = v + } + return res +} + // substring creates a substring of the given string. // -// If start is < 0, this calls string[:length]. +// If start is < 0, this calls string[:end]. // -// If start is >= 0 and length < 0, this calls string[start:] +// If start is >= 0 and end < 0 or end bigger than s length, this calls string[start:] // -// Otherwise, this calls string[start, length]. -func substring(start, length int, s string) string { +// Otherwise, this calls string[start, end]. +func substring(start, end int, s string) string { if start < 0 { - return s[:length] + return s[:end] } - if length < 0 { + if end < 0 || end > len(s) { return s[start:] } - return s[start:length] + return s[start:end] } diff --git a/vendor/github.com/huandu/xstrings/common.go b/vendor/github.com/huandu/xstrings/common.go index dbfaa2dd6..2aff57aab 100644 --- a/vendor/github.com/huandu/xstrings/common.go +++ b/vendor/github.com/huandu/xstrings/common.go @@ -7,7 +7,7 @@ import ( "bytes" ) -const _BUFFER_INIT_GROW_SIZE_MAX = 2048 +const bufferMaxInitGrowSize = 2048 // Lazy initialize a buffer. func allocBuffer(orig, cur string) *bytes.Buffer { @@ -15,8 +15,8 @@ func allocBuffer(orig, cur string) *bytes.Buffer { maxSize := len(orig) * 4 // Avoid to reserve too much memory at once. - if maxSize > _BUFFER_INIT_GROW_SIZE_MAX { - maxSize = _BUFFER_INIT_GROW_SIZE_MAX + if maxSize > bufferMaxInitGrowSize { + maxSize = bufferMaxInitGrowSize } output.Grow(maxSize) diff --git a/vendor/github.com/huandu/xstrings/convert.go b/vendor/github.com/huandu/xstrings/convert.go index 78ca34d49..8253fa9c6 100644 --- a/vendor/github.com/huandu/xstrings/convert.go +++ b/vendor/github.com/huandu/xstrings/convert.go @@ -44,18 +44,25 @@ func ToCamelCase(str string) string { return buf.String() } - buf.WriteRune(unicode.ToUpper(r0)) - r0, size = utf8.DecodeRuneInString(str) - str = str[size:] + r0 = unicode.ToUpper(r0) for len(str) > 0 { r1 = r0 r0, size = utf8.DecodeRuneInString(str) str = str[size:] - if r1 == '_' && r0 != '_' { + if r1 == '_' && r0 == '_' { + buf.WriteRune(r1) + continue + } + + if r1 == '_' { r0 = unicode.ToUpper(r0) } else { + r0 = unicode.ToLower(r0) + } + + if r1 != '_' { buf.WriteRune(r1) } } @@ -65,7 +72,7 @@ func ToCamelCase(str string) string { } // ToSnakeCase can convert all upper case characters in a string to -// underscore format. +// snake case format. // // Some samples. // "FirstName" => "first_name" @@ -74,7 +81,31 @@ func ToCamelCase(str string) string { // "GO_PATH" => "go_path" // "GO PATH" => "go_path" // space is converted to underscore. // "GO-PATH" => "go_path" // hyphen is converted to underscore. +// "HTTP2XX" => "http_2xx" // insert an underscore before a number and after an alphabet. +// "http2xx" => "http_2xx" +// "HTTP20xOK" => "http_20x_ok" func ToSnakeCase(str string) string { + return camelCaseToLowerCase(str, '_') +} + +// ToKebabCase can convert all upper case characters in a string to +// kebab case format. +// +// Some samples. +// "FirstName" => "first-name" +// "HTTPServer" => "http-server" +// "NoHTTPS" => "no-https" +// "GO_PATH" => "go-path" +// "GO PATH" => "go-path" // space is converted to '-'. +// "GO-PATH" => "go-path" // hyphen is converted to '-'. +// "HTTP2XX" => "http-2xx" // insert a '-' before a number and after an alphabet. +// "http2xx" => "http-2xx" +// "HTTP20xOK" => "http-20x-ok" +func ToKebabCase(str string) string { + return camelCaseToLowerCase(str, '-') +} + +func camelCaseToLowerCase(str string, connector rune) string { if len(str) == 0 { return "" } @@ -83,7 +114,7 @@ func ToSnakeCase(str string) string { var prev, r0, r1 rune var size int - r0 = '_' + r0 = connector for len(str) > 0 { prev = r0 @@ -92,11 +123,11 @@ func ToSnakeCase(str string) string { switch { case r0 == utf8.RuneError: - buf.WriteByte(byte(str[0])) + buf.WriteRune(r0) case unicode.IsUpper(r0): - if prev != '_' { - buf.WriteRune('_') + if prev != connector && !unicode.IsNumber(prev) { + buf.WriteRune(connector) } buf.WriteRune(unicode.ToLower(r0)) @@ -113,7 +144,7 @@ func ToSnakeCase(str string) string { break } - // find next non-upper-case character and insert `_` properly. + // find next non-upper-case character and insert connector properly. // it's designed to convert `HTTPServer` to `http_server`. // if there are more than 2 adjacent upper case characters in a word, // treat them as an abbreviation plus a normal word. @@ -124,17 +155,23 @@ func ToSnakeCase(str string) string { if r0 == utf8.RuneError { buf.WriteRune(unicode.ToLower(r1)) - buf.WriteByte(byte(str[0])) + buf.WriteRune(r0) break } if !unicode.IsUpper(r0) { if r0 == '_' || r0 == ' ' || r0 == '-' { - r0 = '_' + r0 = connector buf.WriteRune(unicode.ToLower(r1)) + } else if unicode.IsNumber(r0) { + // treat a number as an upper case rune + // so that both `http2xx` and `HTTP2XX` can be converted to `http_2xx`. + buf.WriteRune(unicode.ToLower(r1)) + buf.WriteRune(connector) + buf.WriteRune(r0) } else { - buf.WriteRune('_') + buf.WriteRune(connector) buf.WriteRune(unicode.ToLower(r1)) buf.WriteRune(r0) } @@ -145,14 +182,20 @@ func ToSnakeCase(str string) string { buf.WriteRune(unicode.ToLower(r1)) } - if len(str) == 0 || r0 == '_' { + if len(str) == 0 || r0 == connector { buf.WriteRune(unicode.ToLower(r0)) - break } + case unicode.IsNumber(r0): + if prev != connector && !unicode.IsNumber(prev) { + buf.WriteRune(connector) + } + + buf.WriteRune(r0) + default: - if r0 == ' ' || r0 == '-' { - r0 = '_' + if r0 == ' ' || r0 == '-' || r0 == '_' { + r0 = connector } buf.WriteRune(r0) diff --git a/vendor/github.com/huandu/xstrings/count.go b/vendor/github.com/huandu/xstrings/count.go index abf3214bd..f96e38703 100644 --- a/vendor/github.com/huandu/xstrings/count.go +++ b/vendor/github.com/huandu/xstrings/count.go @@ -8,12 +8,12 @@ import ( "unicode/utf8" ) -// Get str's utf8 rune length. +// Len returns str's utf8 rune length. func Len(str string) int { return utf8.RuneCountInString(str) } -// Count number of words in a string. +// WordCount returns number of words in a string. // // Word is defined as a locale dependent string containing alphabetic characters, // which may also contain but not start with `'` and `-` characters. diff --git a/vendor/github.com/huandu/xstrings/doc.go b/vendor/github.com/huandu/xstrings/doc.go index fab0ba322..1a6ef069f 100644 --- a/vendor/github.com/huandu/xstrings/doc.go +++ b/vendor/github.com/huandu/xstrings/doc.go @@ -1,8 +1,8 @@ // Copyright 2015 Huan Du. All rights reserved. // Licensed under the MIT license that can be found in the LICENSE file. -// Package `xstrings` is to provide string algorithms which are useful but not included in `strings` package. +// Package xstrings is to provide string algorithms which are useful but not included in `strings` package. // See project home page for details. https://github.com/huandu/xstrings // -// Package `xstrings` assumes all strings are encoded in utf8. +// Package xstrings assumes all strings are encoded in utf8. package xstrings diff --git a/vendor/github.com/huandu/xstrings/manipulate.go b/vendor/github.com/huandu/xstrings/manipulate.go index 4114f96ce..0eefb43ed 100644 --- a/vendor/github.com/huandu/xstrings/manipulate.go +++ b/vendor/github.com/huandu/xstrings/manipulate.go @@ -128,7 +128,7 @@ func Insert(dst, src string, index int) string { return Slice(dst, 0, index) + src + Slice(dst, index, -1) } -// Scrubs invalid utf8 bytes with repl string. +// Scrub scrubs invalid utf8 bytes with repl string. // Adjacent invalid bytes are replaced only once. func Scrub(str, repl string) string { var buf *bytes.Buffer @@ -171,7 +171,7 @@ func Scrub(str, repl string) string { return origin } -// Splits a string into words. Returns a slice of words. +// WordSplit splits a string into words. Returns a slice of words. // If there is no word in a string, return nil. // // Word is defined as a locale dependent string containing alphabetic characters, diff --git a/vendor/github.com/huandu/xstrings/translate.go b/vendor/github.com/huandu/xstrings/translate.go index bf6df38c0..d86a4cbbd 100644 --- a/vendor/github.com/huandu/xstrings/translate.go +++ b/vendor/github.com/huandu/xstrings/translate.go @@ -492,8 +492,9 @@ func Count(str, pattern string) int { // If pattern is not empty, only runes matching the pattern will be squeezed. // // Samples: -// Squeeze("hello", "") => "helo" -// Squeeze("hello", "m-z") => "hello" +// Squeeze("hello", "") => "helo" +// Squeeze("hello", "m-z") => "hello" +// Squeeze("hello world", " ") => "hello world" func Squeeze(str, pattern string) string { var last, r rune var size int @@ -532,6 +533,7 @@ func Squeeze(str, pattern string) string { } last = r + skipSqueeze = false } str = str[size:]