structured flags as alternative to config #76
This commit is contained in:
Generated
+3
-3
@@ -115,10 +115,10 @@
|
||||
revision = "0dc08b1671f34c4250ce212759ebd880f743d883"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/jessevdk/go-flags"
|
||||
packages = ["."]
|
||||
revision = "96dc06278ce32a0e9d957d590bb987c81ee66407"
|
||||
version = "v1.3.0"
|
||||
revision = "1c38ed7ad0cc3d9e66649ac398c30e45f395c4eb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -223,6 +223,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "e849348430ea10a86642c328c52b516e237207389cf765ff1849c8bded391d4a"
|
||||
inputs-digest = "2c90909156f93c975489ffa0340d12a2f9ce4369166c93bbfc531fdbbf40efb6"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
+4
-1
@@ -30,4 +30,7 @@ required = ["github.com/patrickmn/go-cache"]
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/patrickmn/go-cache"
|
||||
version = "2.1.0"
|
||||
version = "2.1.0"
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/jessevdk/go-flags"
|
||||
|
||||
@@ -30,34 +30,34 @@ Remark42 is a self-hosted, lightweight, and simple (yet functional) comment engi
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Command line | Environment | Default | Multi | Description |
|
||||
| ----------------- | -------------------- | ---------------------- | ----- | ---------------------------------------------- |
|
||||
| --url | REMARK_URL | | no | url to remark42 server |
|
||||
| --bolt | BOLTDB_PATH | `./var` | no | path to data directory |
|
||||
| --site | SITE | `remark` | yes | site name(s) |
|
||||
| --admin | ADMIN | | yes | admin names (list of user ids) |
|
||||
| --admin-email | ADMIN_EMAIL | `admin@${REMARK_URL}` | no | admin email |
|
||||
| --backup | BACKUP_PATH | `./var/backup` | no | backups location |
|
||||
| --max-back | MAX_BACKUP_FILES | `10` | no | max backup files to keep |
|
||||
| --max-cache-items | MAX_CACHE_ITEMS | `1000` | no | max number of cached items, `0` - unlimited |
|
||||
| --max-cache-value | MAX_CACHE_VALUE | `65536` | no | max size of cached value, `0` - unlimited |
|
||||
| --max-cache-size | MAX_CACHE_SIZE | `50000000` | no | max size of all cached values, `0` - unlimited |
|
||||
| --avatars | AVATAR_STORE | `./var/avatars` | no | avatars location |
|
||||
| --secret | SECRET | | no | secret key, required |
|
||||
| --max-comment | MAX_COMMENT_SIZE | 2048 | no | comment's size limit |
|
||||
| --google-cid | REMARK_GOOGLE_CID | | no | Google OAuth client ID |
|
||||
| --google-csec | REMARK_GOOGLE_CSEC | | no | Google OAuth client secret |
|
||||
| --facebook-cid | REMARK_FACEBOOK_CID | | no | Facebook OAuth client ID |
|
||||
| --facebook-csec | REMARK_FACEBOOK_CSEC | | no | Facebook OAuth client secret |
|
||||
| --github-cid | REMARK_GITHUB_CID | | no | Github OAuth client ID |
|
||||
| --github-csec | REMARK_GITHUB_CSEC | | no | Github OAuth client secret |
|
||||
| --yandex-cid | REMARK_YANDEX_CID | | no | Yandex OAuth client ID |
|
||||
| --yandex-csec | REMARK_YANDEX_CSEC | | no | Yandex OAuth client secret |
|
||||
| --low-score | LOW_SCORE | `-5` | no | Low score threshold |
|
||||
| --critical-score | CRITICAL_SCORE | `-10` | no | Critical score threshold |
|
||||
| --img-proxy | IMG_PROXY | `false` | no | Enable http->https proxy for images |
|
||||
| --dbg | DEBUG | `false` | no | debug mode |
|
||||
| --dev-passwd | DEV_PASSWD | | no | password for `dev` user |
|
||||
| Command line | Environment | Default | Multi | Description |
|
||||
| -------------------- | ------------------ | --------------------- | ----- | ---------------------------------------------- |
|
||||
| --url | REMARK_URL | | no | url to remark42 server, required |
|
||||
| --secret | SECRET | | no | secret key, required |
|
||||
| --bolt | BOLTDB_PATH | `./var` | no | path to data directory |
|
||||
| --site | SITE | `remark` | yes | site name(s) |
|
||||
| --admin | ADMIN | | yes | admin names (list of user ids) |
|
||||
| --admin-email | ADMIN_EMAIL | `admin@${REMARK_URL}` | no | admin email | |
|
||||
| --backup | BACKUP_PATH | `./var/backup` | no | backups location |
|
||||
| --max-back | MAX_BACKUP_FILES | `10` | no | max backup files to keep |
|
||||
| --max-cache-items | MAX_CACHE_ITEMS | `1000` | no | max number of cached items, `0` - unlimited |
|
||||
| --max-cache-value | MAX_CACHE_VALUE | `65536` | no | max size of cached value, `0` - unlimited |
|
||||
| --max-cache-size | MAX_CACHE_SIZE | `50000000` | no | max size of all cached values, `0` - unlimited |
|
||||
| --avatars | AVATAR_STORE | `./var/avatars` | no | avatars location |
|
||||
| --max-comment | MAX_COMMENT_SIZE | 2048 | no | comment's size limit |
|
||||
| --auth.google.cid | AUTH_GOOGLE_CID | | no | Google OAuth client ID |
|
||||
| --auth.google.csec | AUTH_GOOGLE_CSEC | | no | Google OAuth client secret |
|
||||
| --auth.facebook.cid | AUTH_FACEBOOK_CID | | no | Facebook OAuth client ID |
|
||||
| --auth.facebook.csec | AUTH_FACEBOOK_CSEC | | no | Facebook OAuth client secret |
|
||||
| --auth.github.cid | AUTH_GITHUB_CID | | no | Github OAuth client ID |
|
||||
| --auth.github.csec | AUTH_GITHUB_CSEC | | no | Github OAuth client secret |
|
||||
| --auth.yandex.cid | AUTH_YANDEX_CID | | no | Yandex OAuth client ID |
|
||||
| --auth.yandex.csec | AUTH_YANDEX_CSEC | | no | Yandex OAuth client secret |
|
||||
| --low-score | LOW_SCORE | `-5` | no | Low score threshold |
|
||||
| --critical-score | CRITICAL_SCORE | `-10` | no | Critical score threshold |
|
||||
| --img-proxy | IMG_PROXY | `false` | no | Enable http->https proxy for images |
|
||||
| --dbg | DEBUG | `false` | no | debug mode |
|
||||
| --dev-passwd | DEV_PASSWD | | no | password for `dev` user |
|
||||
|
||||
##### Required parameters
|
||||
|
||||
@@ -81,8 +81,8 @@ services:
|
||||
- REMARK_URL=https://demo.remark42.com # url pointing to your remark42 server
|
||||
- USER=1001 # UID on the host machine
|
||||
- SECRET=abcd-123456-xyz-$%^& # secret key
|
||||
- REMARK_GITHUB_CID=12345667890 # oauth2 client ID
|
||||
- REMARK_GITHUB_CSEC=abcdefg12345678 # oauth2 client secret
|
||||
- AUTH_GITHUB_CID=12345667890 # oauth2 client ID
|
||||
- AUTH_GITHUB_CSEC=abcdefg12345678 # oauth2 client secret
|
||||
volumes:
|
||||
- ./var:/srv/var # persistent volume to store all remark42 data
|
||||
```
|
||||
|
||||
+28
-18
@@ -52,17 +52,21 @@ type Opts struct {
|
||||
CriticalScore int `long:"critical-score" env:"CRITICAL_SCORE" default:"-10" description:"critical score threshold"`
|
||||
ReadOnlyAge int `long:"read-age" env:"READONLY_AGE" default:"0" description:"read-only age of comments"`
|
||||
|
||||
GoogleCID string `long:"google-cid" env:"REMARK_GOOGLE_CID" description:"Google OAuth client ID"`
|
||||
GoogleCSEC string `long:"google-csec" env:"REMARK_GOOGLE_CSEC" description:"Google OAuth client secret"`
|
||||
GithubCID string `long:"github-cid" env:"REMARK_GITHUB_CID" description:"Github OAuth client ID"`
|
||||
GithubCSEC string `long:"github-csec" env:"REMARK_GITHUB_CSEC" description:"Github OAuth client secret"`
|
||||
FacebookCID string `long:"facebook-cid" env:"REMARK_FACEBOOK_CID" description:"Facebook OAuth client ID"`
|
||||
FacebookCSEC string `long:"facebook-csec" env:"REMARK_FACEBOOK_CSEC" description:"Facebook OAuth client secret"`
|
||||
YandexCID string `long:"yandex-cid" env:"REMARK_YANDEX_CID" description:"Yandex OAuth client ID"`
|
||||
YandexCSEC string `long:"yandex-csec" env:"REMARK_YANDEX_CSEC" description:"Yandex OAuth client secret"`
|
||||
|
||||
Port int `long:"port" env:"REMARK_PORT" default:"8080" description:"port"`
|
||||
WebRoot string `long:"web-root" env:"REMARK_WEB_ROOT" default:"./web" description:"web root directory"`
|
||||
|
||||
Auth struct {
|
||||
Google AuthGroup `group:"google" namespace:"google" env-namespace:"GOOGLE" description:"Google OAuth"`
|
||||
Github AuthGroup `group:"github" namespace:"github" env-namespace:"GITHUB" description:"Github OAuth"`
|
||||
Facebook AuthGroup `group:"facebook" namespace:"facebook" env-namespace:"FACEBOOK" description:"Facebook OAuth"`
|
||||
Yandex AuthGroup `group:"yandex" namespace:"yandex" env-namespace:"YANDEX" description:"Yandex OAuth"`
|
||||
} `group:"auth" namespace:"auth" env-namespace:"AUTH"`
|
||||
}
|
||||
|
||||
// AuthGroup defines options group for auth params
|
||||
type AuthGroup struct {
|
||||
CID string `long:"cid" env:"CID" description:"OAuth client ID"`
|
||||
CSEC string `long:"csec" env:"CSEC" description:"OAuth client secret"`
|
||||
}
|
||||
|
||||
var revision = "unknown"
|
||||
@@ -85,7 +89,7 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Print("[INFO] started remark")
|
||||
|
||||
resetEnv("SECRET", "AUTH_GOOGLE_CSEC", "AUTH_GITHUB_CSEC", "AUTH_FACEBOOK_CSEC", "AUTH_YANDEX_CSEC")
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() { // catch signal and invoke graceful termination
|
||||
stop := make(chan os.Signal, 1)
|
||||
@@ -279,17 +283,17 @@ func makeAuthProviders(jwtService *auth.JWT, avatarProxy *proxy.Avatar, ds *serv
|
||||
}
|
||||
|
||||
providers := []auth.Provider{}
|
||||
if opts.GoogleCID != "" && opts.GoogleCSEC != "" {
|
||||
providers = append(providers, auth.NewGoogle(makeParams(opts.GoogleCID, opts.GoogleCSEC)))
|
||||
if opts.Auth.Google.CID != "" && opts.Auth.Google.CSEC != "" {
|
||||
providers = append(providers, auth.NewGoogle(makeParams(opts.Auth.Google.CID, opts.Auth.Google.CSEC)))
|
||||
}
|
||||
if opts.GithubCID != "" && opts.GithubCSEC != "" {
|
||||
providers = append(providers, auth.NewGithub(makeParams(opts.GithubCID, opts.GithubCSEC)))
|
||||
if opts.Auth.Github.CID != "" && opts.Auth.Github.CSEC != "" {
|
||||
providers = append(providers, auth.NewGithub(makeParams(opts.Auth.Github.CID, opts.Auth.Github.CSEC)))
|
||||
}
|
||||
if opts.FacebookCID != "" && opts.FacebookCSEC != "" {
|
||||
providers = append(providers, auth.NewFacebook(makeParams(opts.FacebookCID, opts.FacebookCSEC)))
|
||||
if opts.Auth.Facebook.CID != "" && opts.Auth.Facebook.CSEC != "" {
|
||||
providers = append(providers, auth.NewFacebook(makeParams(opts.Auth.Facebook.CID, opts.Auth.Facebook.CSEC)))
|
||||
}
|
||||
if opts.YandexCID != "" && opts.YandexCSEC != "" {
|
||||
providers = append(providers, auth.NewYandex(makeParams(opts.YandexCID, opts.YandexCSEC)))
|
||||
if opts.Auth.Yandex.CID != "" && opts.Auth.Yandex.CSEC != "" {
|
||||
providers = append(providers, auth.NewYandex(makeParams(opts.Auth.Yandex.CID, opts.Auth.Yandex.CSEC)))
|
||||
}
|
||||
if len(providers) == 0 {
|
||||
log.Printf("[WARN] no auth providers defined")
|
||||
@@ -322,6 +326,12 @@ func postFlushFn(sites []string, port int) func() {
|
||||
}
|
||||
}
|
||||
|
||||
func resetEnv(envs ...string) {
|
||||
for _, env := range envs {
|
||||
os.Unsetenv(env)
|
||||
}
|
||||
}
|
||||
|
||||
func setupLog(dbg bool) {
|
||||
filter := &logutils.LevelFilter{
|
||||
Levels: []logutils.LogLevel{"DEBUG", "INFO", "WARN", "ERROR"},
|
||||
|
||||
+4
-4
@@ -98,10 +98,10 @@ func prepApp(t *testing.T, port int, duration time.Duration) (*Application, cont
|
||||
p.ParseArgs([]string{"--secret=123456", "--dev-passwd=password", "--url=https://demo.remark42.com"})
|
||||
opts.AvatarStore, opts.BackupLocation = "/tmp", "/tmp"
|
||||
opts.BoltPath = fmt.Sprintf("/tmp/%d", port)
|
||||
opts.GithubCSEC, opts.GithubCID = "csec", "cid"
|
||||
opts.GoogleCSEC, opts.GoogleCID = "csec", "cid"
|
||||
opts.FacebookCSEC, opts.FacebookCID = "csec", "cid"
|
||||
opts.YandexCSEC, opts.YandexCID = "csec", "cid"
|
||||
opts.Auth.Github.CSEC, opts.Auth.Github.CID = "csec", "cid"
|
||||
opts.Auth.Google.CSEC, opts.Auth.Google.CID = "csec", "cid"
|
||||
opts.Auth.Facebook.CSEC, opts.Auth.Facebook.CID = "csec", "cid"
|
||||
opts.Auth.Yandex.CSEC, opts.Auth.Yandex.CID = "csec", "cid"
|
||||
opts.Port = port
|
||||
|
||||
os.Remove(opts.BoltPath + "/remark.db")
|
||||
|
||||
+9
-3
@@ -1,8 +1,15 @@
|
||||
language: go
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
go:
|
||||
- 1.6.x
|
||||
- 1.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
|
||||
install:
|
||||
# go-flags
|
||||
@@ -10,8 +17,7 @@ install:
|
||||
- go build -v ./...
|
||||
|
||||
# linting
|
||||
- go get github.com/golang/lint
|
||||
- go install github.com/golang/lint/golint
|
||||
- go get github.com/golang/lint/golint
|
||||
|
||||
# code coverage
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
|
||||
-1
@@ -110,7 +110,6 @@ args, err := flags.ParseArgs(&opts, args)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("Verbosity: %v\n", opts.Verbose)
|
||||
|
||||
+12
-2
@@ -5,7 +5,6 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Command represents an application command. Commands can be added to the
|
||||
@@ -229,7 +228,17 @@ func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler {
|
||||
subcommand := mtag.Get("command")
|
||||
|
||||
if len(subcommand) != 0 {
|
||||
ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr()))
|
||||
var ptrval reflect.Value
|
||||
|
||||
if realval.Kind() == reflect.Ptr {
|
||||
ptrval = realval
|
||||
|
||||
if ptrval.IsNil() {
|
||||
ptrval.Set(reflect.New(ptrval.Type().Elem()))
|
||||
}
|
||||
} else {
|
||||
ptrval = realval.Addr()
|
||||
}
|
||||
|
||||
shortDescription := mtag.Get("description")
|
||||
longDescription := mtag.Get("long-description")
|
||||
@@ -237,6 +246,7 @@ func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler {
|
||||
aliases := mtag.GetMany("alias")
|
||||
|
||||
subc, err := c.AddCommand(subcommand, shortDescription, longDescription, ptrval.Interface())
|
||||
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
+4
@@ -125,6 +125,10 @@ The following is a list of tags for struct fields supported by go-flags:
|
||||
gets prepended to every option's long name and
|
||||
subgroup's namespace of this group, separated by
|
||||
the parser's namespace delimiter (optional)
|
||||
env-namespace: when specified on a group struct field, the env-namespace
|
||||
gets prepended to every option's env key and
|
||||
subgroup's env-namespace of this group, separated by
|
||||
the parser's env-namespace delimiter (optional)
|
||||
command: when specified on a struct field, makes the struct
|
||||
field a (sub)command with the given name (optional)
|
||||
subcommands-optional: when specified on a command struct field, makes
|
||||
|
||||
+17
-2
@@ -9,7 +9,6 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// ErrNotPointerToStruct indicates that a provided data container is not
|
||||
@@ -35,6 +34,9 @@ type Group struct {
|
||||
// The namespace of the group
|
||||
Namespace string
|
||||
|
||||
// The environment namespace of the group
|
||||
EnvNamespace string
|
||||
|
||||
// If true, the group is not displayed in the help or man page
|
||||
Hidden bool
|
||||
|
||||
@@ -338,15 +340,28 @@ func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.Struc
|
||||
subgroup := mtag.Get("group")
|
||||
|
||||
if len(subgroup) != 0 {
|
||||
ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr()))
|
||||
var ptrval reflect.Value
|
||||
|
||||
if realval.Kind() == reflect.Ptr {
|
||||
ptrval = realval
|
||||
|
||||
if ptrval.IsNil() {
|
||||
ptrval.Set(reflect.New(ptrval.Type()))
|
||||
}
|
||||
} else {
|
||||
ptrval = realval.Addr()
|
||||
}
|
||||
|
||||
description := mtag.Get("description")
|
||||
|
||||
group, err := g.AddGroup(subgroup, description, ptrval.Interface())
|
||||
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
group.Namespace = mtag.Get("namespace")
|
||||
group.EnvNamespace = mtag.Get("env-namespace")
|
||||
group.Hidden = mtag.Get("hidden") != ""
|
||||
|
||||
return true, nil
|
||||
|
||||
+3
-3
@@ -225,12 +225,12 @@ func (p *Parser) writeHelpOption(writer *bufio.Writer, option *Option, info alig
|
||||
}
|
||||
|
||||
var envDef string
|
||||
if option.EnvDefaultKey != "" {
|
||||
if option.EnvKeyWithNamespace() != "" {
|
||||
var envPrintable string
|
||||
if runtime.GOOS == "windows" {
|
||||
envPrintable = "%" + option.EnvDefaultKey + "%"
|
||||
envPrintable = "%" + option.EnvKeyWithNamespace() + "%"
|
||||
} else {
|
||||
envPrintable = "$" + option.EnvDefaultKey
|
||||
envPrintable = "$" + option.EnvKeyWithNamespace()
|
||||
}
|
||||
envDef = fmt.Sprintf(" [%s]", envPrintable)
|
||||
}
|
||||
|
||||
+3
-3
@@ -83,11 +83,11 @@ func writeManPageOptions(wr io.Writer, grp *Group) {
|
||||
|
||||
if len(opt.Default) != 0 {
|
||||
fmt.Fprintf(wr, " <default: \\fI%s\\fR>", manQuote(strings.Join(quoteV(opt.Default), ", ")))
|
||||
} else if len(opt.EnvDefaultKey) != 0 {
|
||||
} else if len(opt.EnvKeyWithNamespace()) != 0 {
|
||||
if runtime.GOOS == "windows" {
|
||||
fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvDefaultKey))
|
||||
fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvKeyWithNamespace()))
|
||||
} else {
|
||||
fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvDefaultKey))
|
||||
fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvKeyWithNamespace()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+55
-7
@@ -3,9 +3,9 @@ package flags
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
@@ -139,6 +139,57 @@ func (option *Option) LongNameWithNamespace() string {
|
||||
return longName
|
||||
}
|
||||
|
||||
// EnvKeyWithNamespace returns the option's env key with the group namespaces
|
||||
// prepended by walking up the option's group tree. Namespaces and the env key
|
||||
// itself are separated by the parser's namespace delimiter. If the env key is
|
||||
// empty an empty string is returned.
|
||||
func (option *Option) EnvKeyWithNamespace() string {
|
||||
if len(option.EnvDefaultKey) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// fetch the namespace delimiter from the parser which is always at the
|
||||
// end of the group hierarchy
|
||||
namespaceDelimiter := ""
|
||||
g := option.group
|
||||
|
||||
for {
|
||||
if p, ok := g.parent.(*Parser); ok {
|
||||
namespaceDelimiter = p.EnvNamespaceDelimiter
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
switch i := g.parent.(type) {
|
||||
case *Command:
|
||||
g = i.Group
|
||||
case *Group:
|
||||
g = i
|
||||
}
|
||||
}
|
||||
|
||||
// concatenate long name with namespace
|
||||
key := option.EnvDefaultKey
|
||||
g = option.group
|
||||
|
||||
for g != nil {
|
||||
if g.EnvNamespace != "" {
|
||||
key = g.EnvNamespace + namespaceDelimiter + key
|
||||
}
|
||||
|
||||
switch i := g.parent.(type) {
|
||||
case *Command:
|
||||
g = i.Group
|
||||
case *Group:
|
||||
g = i
|
||||
case *Parser:
|
||||
g = nil
|
||||
}
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
// String converts an option to a human friendly readable string describing the
|
||||
// option.
|
||||
func (option *Option) String() string {
|
||||
@@ -260,13 +311,10 @@ func (option *Option) empty() {
|
||||
func (option *Option) clearDefault() {
|
||||
usedDefault := option.Default
|
||||
|
||||
if envKey := option.EnvDefaultKey; envKey != "" {
|
||||
// os.Getenv() makes no distinction between undefined and
|
||||
// empty values, so we use syscall.Getenv()
|
||||
if value, ok := syscall.Getenv(envKey); ok {
|
||||
if envKey := option.EnvKeyWithNamespace(); envKey != "" {
|
||||
if value, ok := os.LookupEnv(envKey); ok {
|
||||
if option.EnvDefaultDelim != "" {
|
||||
usedDefault = strings.Split(value,
|
||||
option.EnvDefaultDelim)
|
||||
usedDefault = strings.Split(value, option.EnvDefaultDelim)
|
||||
} else {
|
||||
usedDefault = []string{value}
|
||||
}
|
||||
|
||||
+7
-3
@@ -29,6 +29,9 @@ type Parser struct {
|
||||
// NamespaceDelimiter separates group namespaces and option long names
|
||||
NamespaceDelimiter string
|
||||
|
||||
// EnvNamespaceDelimiter separates group env namespaces and env keys
|
||||
EnvNamespaceDelimiter string
|
||||
|
||||
// UnknownOptionsHandler is a function which gets called when the parser
|
||||
// encounters an unknown option. The function receives the unknown option
|
||||
// name, a SplitArgument which specifies its value if set with an argument
|
||||
@@ -170,9 +173,10 @@ func NewParser(data interface{}, options Options) *Parser {
|
||||
// be added to this parser by using AddGroup and AddCommand.
|
||||
func NewNamedParser(appname string, options Options) *Parser {
|
||||
p := &Parser{
|
||||
Command: newCommand(appname, "", "", nil),
|
||||
Options: options,
|
||||
NamespaceDelimiter: ".",
|
||||
Command: newCommand(appname, "", "", nil),
|
||||
Options: options,
|
||||
NamespaceDelimiter: ".",
|
||||
EnvNamespaceDelimiter: "_",
|
||||
}
|
||||
|
||||
p.Command.parent = p
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// +build !windows,!plan9,!solaris
|
||||
// +build !windows,!plan9,!solaris,!appengine
|
||||
|
||||
package flags
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// +build windows plan9 solaris
|
||||
// +build windows plan9 solaris appengine
|
||||
|
||||
package flags
|
||||
|
||||
|
||||
Generated
Vendored
Generated
Vendored
Reference in New Issue
Block a user