mirror of
https://github.com/notherealmarco/WASAPhoto.git
synced 2025-05-05 20:32:35 +02:00
Integrated Fantastic coffie (decaffeinated) base version
This commit is contained in:
parent
2fc5535f0f
commit
94036c4831
482 changed files with 476112 additions and 0 deletions
31
vendor/github.com/ardanlabs/conf/CONTRIBUTORS
generated
vendored
Normal file
31
vendor/github.com/ardanlabs/conf/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
# This is the official list of people who can contribute
|
||||
# (and typically have contributed) code to the gotraining repository.
|
||||
#
|
||||
# Names should be added to this file only after verifying that
|
||||
# the individual or the individual's organization has agreed to
|
||||
# the appropriate Contributor License Agreement, found here:
|
||||
#
|
||||
# http://code.google.com/legal/individual-cla-v1.0.html
|
||||
# http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
#
|
||||
# The agreement for individuals can be filled out on the web.
|
||||
|
||||
# Names should be added to this file like so:
|
||||
# Name <email address>
|
||||
#
|
||||
# An entry with two email addresses specifies that the
|
||||
# first address should be used in the submit logs and
|
||||
# that the second address should be recognized as the
|
||||
# same person when interacting with Rietveld.
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Arash Bina <arash@arash.io>
|
||||
Andy Walker
|
||||
Bruno Pereira <brunopereir4@gmail.com>
|
||||
Enrico204 <enrico204@gmail.com>
|
||||
Fábio Correia <fabiodcorreia@gmail.com>
|
||||
Kelsey Hightower
|
||||
Peter Bourgon
|
||||
Steven Edwards <steven@stephenwithav.com>
|
||||
William Kennedy <bill@ardanlabs.com>
|
201
vendor/github.com/ardanlabs/conf/LICENSE
generated
vendored
Normal file
201
vendor/github.com/ardanlabs/conf/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
29
vendor/github.com/ardanlabs/conf/README.md
generated
vendored
Normal file
29
vendor/github.com/ardanlabs/conf/README.md
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Conf
|
||||
|
||||
[](https://circleci.com/gh/ardanlabs/conf)
|
||||
|
||||
Copyright 2018, 2019, 2020, 2021, Ardan Labs
|
||||
info@ardanlabs.com
|
||||
|
||||
## Licensing
|
||||
|
||||
```
|
||||
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.
|
||||
```
|
||||
|
||||
## About The Project
|
||||
|
||||
Package conf provides support for using environmental variables and command
|
||||
line arguments for configuration.
|
||||
|
||||
All of the documentation can be found on the [go.dev](https://pkg.go.dev/github.com/ardanlabs/conf?tab=doc) website.
|
240
vendor/github.com/ardanlabs/conf/conf.go
generated
vendored
Normal file
240
vendor/github.com/ardanlabs/conf/conf.go
generated
vendored
Normal file
|
@ -0,0 +1,240 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrInvalidStruct indicates that a configuration struct is not the correct type.
|
||||
var ErrInvalidStruct = errors.New("configuration must be a struct pointer")
|
||||
|
||||
// A FieldError occurs when an error occurs updating an individual field
|
||||
// in the provided struct value.
|
||||
type FieldError struct {
|
||||
fieldName string
|
||||
typeName string
|
||||
value string
|
||||
err error
|
||||
}
|
||||
|
||||
func (err *FieldError) Error() string {
|
||||
return fmt.Sprintf("conf: error assigning to field %s: converting '%s' to type %s. details: %s", err.fieldName, err.value, err.typeName, err.err)
|
||||
}
|
||||
|
||||
// Sourcer provides the ability to source data from a configuration source.
|
||||
// Consider the use of lazy-loading for sourcing large datasets or systems.
|
||||
type Sourcer interface {
|
||||
|
||||
// Source takes the field key and attempts to locate that key in its
|
||||
// configuration data. Returns true if found with the value.
|
||||
Source(fld Field) (string, bool)
|
||||
}
|
||||
|
||||
// Version provides the abitily to add version and description to the application.
|
||||
type Version struct {
|
||||
SVN string
|
||||
Desc string
|
||||
}
|
||||
|
||||
// ParseOSArgs parses the configuration allowing command line
|
||||
// arguments to override settings. Function returns ErrHelpWanted
|
||||
// for any information to be provided to the user.
|
||||
func ParseOSArgs(prefix string, cfg interface{}) (string, error) {
|
||||
err := Parse(os.Args[1:], prefix, cfg)
|
||||
if err == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
switch err {
|
||||
case ErrHelpWanted:
|
||||
usage, err := Usage(prefix, cfg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("generating config usage: %w", err)
|
||||
}
|
||||
return usage, ErrHelpWanted
|
||||
|
||||
case ErrVersionWanted:
|
||||
version, err := VersionString(prefix, cfg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("generating config version: %w", err)
|
||||
}
|
||||
return version, ErrHelpWanted
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("parsing config: %w", err)
|
||||
}
|
||||
|
||||
// Parse parses configuration into the provided struct.
|
||||
func Parse(args []string, namespace string, cfgStruct interface{}, sources ...Sourcer) error {
|
||||
|
||||
// Create the flag source.
|
||||
flag, err := newSourceFlag(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Append default sources to any provided list.
|
||||
sources = append(sources, newSourceEnv(namespace))
|
||||
sources = append(sources, flag)
|
||||
|
||||
// Get the list of fields from the configuration struct to process.
|
||||
fields, err := extractFields(nil, cfgStruct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
return errors.New("no fields identified in config struct")
|
||||
}
|
||||
|
||||
// Process all fields found in the config struct provided.
|
||||
for _, field := range fields {
|
||||
|
||||
// If the field is supposed to hold the leftover args then copy them in
|
||||
// from the flags source.
|
||||
if field.Field.Type() == argsT {
|
||||
args := reflect.ValueOf(Args(flag.args))
|
||||
field.Field.Set(args)
|
||||
continue
|
||||
}
|
||||
|
||||
// Set any default value into the struct for this field.
|
||||
if field.Options.DefaultVal != "" {
|
||||
if err := processField(field.Options.DefaultVal, field.Field); err != nil {
|
||||
return &FieldError{
|
||||
fieldName: field.Name,
|
||||
typeName: field.Field.Type().String(),
|
||||
value: field.Options.DefaultVal,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process each field against all sources.
|
||||
var everProvided bool
|
||||
for _, sourcer := range sources {
|
||||
if sourcer == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
value, provided := sourcer.Source(field)
|
||||
if !provided {
|
||||
continue
|
||||
}
|
||||
everProvided = true
|
||||
|
||||
// A value was found so update the struct value with it.
|
||||
if err := processField(value, field.Field); err != nil {
|
||||
return &FieldError{
|
||||
fieldName: field.Name,
|
||||
typeName: field.Field.Type().String(),
|
||||
value: value,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this key is not provided by any source, check if it was
|
||||
// required to be provided.
|
||||
if !everProvided && field.Options.Required {
|
||||
return fmt.Errorf("required field %s is missing value", field.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Usage provides output to display the config usage on the command line.
|
||||
func Usage(namespace string, v interface{}) (string, error) {
|
||||
fields, err := extractFields(nil, v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmtUsage(namespace, fields), nil
|
||||
}
|
||||
|
||||
// VersionString provides output to display the application version and description on the command line.
|
||||
func VersionString(namespace string, v interface{}) (string, error) {
|
||||
fields, err := extractFields(nil, v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var str strings.Builder
|
||||
for i := range fields {
|
||||
if fields[i].Name == versionKey && fields[i].Field.Len() > 0 {
|
||||
str.WriteString("Version: ")
|
||||
str.WriteString(fields[i].Field.String())
|
||||
continue
|
||||
}
|
||||
if fields[i].Name == descKey && fields[i].Field.Len() > 0 {
|
||||
if str.Len() > 0 {
|
||||
str.WriteString("\n")
|
||||
}
|
||||
str.WriteString(fields[i].Field.String())
|
||||
break
|
||||
}
|
||||
}
|
||||
return str.String(), nil
|
||||
}
|
||||
|
||||
// String returns a stringified version of the provided conf-tagged
|
||||
// struct, minus any fields tagged with `noprint`.
|
||||
func String(v interface{}) (string, error) {
|
||||
fields, err := extractFields(nil, v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var s strings.Builder
|
||||
for i, fld := range fields {
|
||||
if fld.Options.Noprint {
|
||||
continue
|
||||
}
|
||||
|
||||
s.WriteString(flagUsage(fld))
|
||||
s.WriteString("=")
|
||||
v := fmt.Sprintf("%v", fld.Field.Interface())
|
||||
|
||||
switch {
|
||||
case fld.Options.Mask:
|
||||
if u, err := url.Parse(v); err == nil {
|
||||
userPass := u.User.String()
|
||||
if userPass != "" {
|
||||
v = strings.Replace(v, userPass, "xxxxxx:xxxxxx", 1)
|
||||
s.WriteString(v)
|
||||
break
|
||||
}
|
||||
}
|
||||
s.WriteString("xxxxxx")
|
||||
|
||||
default:
|
||||
s.WriteString(v)
|
||||
}
|
||||
|
||||
if i < len(fields)-1 {
|
||||
s.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
return s.String(), nil
|
||||
}
|
||||
|
||||
// Args holds command line arguments after flags have been parsed.
|
||||
type Args []string
|
||||
|
||||
// argsT is used by Parse and Usage to detect struct fields of the Args type.
|
||||
var argsT = reflect.TypeOf(Args{})
|
||||
|
||||
// Num returns the i'th argument in the Args slice. It returns an empty string
|
||||
// the request element is not present.
|
||||
func (a Args) Num(i int) string {
|
||||
if i < 0 || i >= len(a) {
|
||||
return ""
|
||||
}
|
||||
return a[i]
|
||||
}
|
128
vendor/github.com/ardanlabs/conf/doc.go
generated
vendored
Normal file
128
vendor/github.com/ardanlabs/conf/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
Package conf provides support for using environmental variables and command
|
||||
line arguments for configuration.
|
||||
|
||||
It is compatible with the GNU extensions to the POSIX recommendations
|
||||
for command-line options. See
|
||||
http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
|
||||
|
||||
There are no hard bindings for this package. This package takes a struct
|
||||
value and parses it for both the environment and flags. It supports several tags
|
||||
to customize the flag options.
|
||||
|
||||
default - Provides the default value for the help
|
||||
env - Allows for overriding the default variable name.
|
||||
flag - Allows for overriding the default flag name.
|
||||
short - Denotes a shorthand option for the flag.
|
||||
noprint - Denotes to not include the field in any display string.
|
||||
mask - Includes the field in any display string but masks out the value.
|
||||
required - Denotes a value must be provided.
|
||||
help - Provides a description for the help.
|
||||
|
||||
The field name and any parent struct name will be used for the long form of
|
||||
the command name unless the name is overridden.
|
||||
|
||||
As an example, this config struct:
|
||||
|
||||
type ip struct {
|
||||
Name string `conf:"default:localhost,env:IP_NAME_VAR"`
|
||||
IP string `conf:"default:127.0.0.0"`
|
||||
}
|
||||
type Embed struct {
|
||||
Name string `conf:"default:bill"`
|
||||
Duration time.Duration `conf:"default:1s,flag:e-dur,short:d"`
|
||||
}
|
||||
type config struct {
|
||||
AnInt int `conf:"default:9"`
|
||||
AString string `conf:"default:B,short:s"`
|
||||
Bool bool
|
||||
Skip string `conf:"-"`
|
||||
IP ip
|
||||
Embed
|
||||
}
|
||||
|
||||
Would produce the following usage output:
|
||||
|
||||
Usage: conf.test [options] [arguments]
|
||||
|
||||
OPTIONS
|
||||
--an-int/$CRUD_AN_INT <int> (default: 9)
|
||||
--a-string/-s/$CRUD_A_STRING <string> (default: B)
|
||||
--bool/$CRUD_BOOL <bool>
|
||||
--ip-name/$CRUD_IP_NAME_VAR <string> (default: localhost)
|
||||
--ip-ip/$CRUD_IP_IP <string> (default: 127.0.0.0)
|
||||
--name/$CRUD_NAME <string> (default: bill)
|
||||
--e-dur/-d/$CRUD_DURATION <duration> (default: 1s)
|
||||
--help/-h
|
||||
display this help message
|
||||
--version/-v
|
||||
display version information
|
||||
|
||||
The API is a single call to Parse
|
||||
|
||||
// Parse(args []string, namespace string, cfgStruct interface{}, sources ...Sourcer) error
|
||||
|
||||
if err := conf.Parse(os.Args, "CRUD", &cfg); err != nil {
|
||||
log.Fatalf("main : Parsing Config : %v", err)
|
||||
}
|
||||
|
||||
Additionally, if the config struct has a field of the slice type conf.Args
|
||||
then it will be populated with any remaining arguments from the command line
|
||||
after flags have been processed.
|
||||
|
||||
For example a program with a config struct like this:
|
||||
|
||||
var cfg struct {
|
||||
Port int
|
||||
Args conf.Args
|
||||
}
|
||||
|
||||
If that program is executed from the command line like this:
|
||||
|
||||
$ my-program --port=9000 serve http
|
||||
|
||||
Then the cfg.Args field will contain the string values ["serve", "http"].
|
||||
The Args type has a method Num for convenient access to these arguments
|
||||
such as this:
|
||||
|
||||
arg0 := cfg.Args.Num(0) // "serve"
|
||||
arg1 := cfg.Args.Num(1) // "http"
|
||||
arg2 := cfg.Args.Num(2) // "" empty string: not enough arguments
|
||||
|
||||
You can add a version with a description by adding the Version type to
|
||||
your config type
|
||||
|
||||
type ConfExplicit struct {
|
||||
Version conf.Version
|
||||
Address string
|
||||
}
|
||||
|
||||
type ConfImplicit struct {
|
||||
conf.Version
|
||||
Address string
|
||||
}
|
||||
|
||||
Then you can set these values at run time for display.
|
||||
|
||||
cfg := struct {
|
||||
Version conf.Version
|
||||
}{
|
||||
Version: conf.Version{
|
||||
SVN: "v1.0.0",
|
||||
Desc: "Service Description",
|
||||
},
|
||||
}
|
||||
|
||||
if err := conf.Parse(os.Args[1:], "APP", &cfg); err != nil {
|
||||
if err == conf.ErrVersionWanted {
|
||||
version, err := conf.VersionString("APP", &cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(version)
|
||||
return nil
|
||||
}
|
||||
fmt.Println("parsing config", err)
|
||||
}
|
||||
*/
|
||||
package conf
|
395
vendor/github.com/ardanlabs/conf/fields.go
generated
vendored
Normal file
395
vendor/github.com/ardanlabs/conf/fields.go
generated
vendored
Normal file
|
@ -0,0 +1,395 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Field maintains information about a field in the configuration struct.
|
||||
type Field struct {
|
||||
Name string
|
||||
FlagKey []string
|
||||
EnvKey []string
|
||||
Field reflect.Value
|
||||
Options FieldOptions
|
||||
|
||||
// Important for flag parsing or any other source where
|
||||
// booleans might be treated specially.
|
||||
BoolField bool
|
||||
}
|
||||
|
||||
// FieldOptions maintain flag options for a given field.
|
||||
type FieldOptions struct {
|
||||
Help string
|
||||
DefaultVal string
|
||||
EnvName string
|
||||
FlagName string
|
||||
ShortFlagChar rune
|
||||
Noprint bool
|
||||
Required bool
|
||||
Mask bool
|
||||
}
|
||||
|
||||
// extractFields uses reflection to examine the struct and generate the keys.
|
||||
func extractFields(prefix []string, target interface{}) ([]Field, error) {
|
||||
if prefix == nil {
|
||||
prefix = []string{}
|
||||
}
|
||||
s := reflect.ValueOf(target)
|
||||
|
||||
if s.Kind() != reflect.Ptr {
|
||||
return nil, ErrInvalidStruct
|
||||
}
|
||||
s = s.Elem()
|
||||
if s.Kind() != reflect.Struct {
|
||||
return nil, ErrInvalidStruct
|
||||
}
|
||||
targetType := s.Type()
|
||||
|
||||
var fields []Field
|
||||
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
f := s.Field(i)
|
||||
structField := targetType.Field(i)
|
||||
|
||||
// Get the conf tags associated with this item (if any).
|
||||
fieldTags := structField.Tag.Get("conf")
|
||||
|
||||
// If it's ignored or can't be set, move on.
|
||||
if !f.CanSet() || fieldTags == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldName := structField.Name
|
||||
|
||||
// Get and options. TODO: Need more.
|
||||
fieldOpts, err := parseTag(fieldTags)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("conf: error parsing tags for field %s: %s", fieldName, err)
|
||||
}
|
||||
|
||||
// Generate the field key. This could be ignored.
|
||||
fieldKey := append(prefix, camelSplit(fieldName)...)
|
||||
|
||||
// Drill down through pointers until we bottom out at type or nil.
|
||||
for f.Kind() == reflect.Ptr {
|
||||
if f.IsNil() {
|
||||
|
||||
// It's not a struct so leave it alone.
|
||||
if f.Type().Elem().Kind() != reflect.Struct {
|
||||
break
|
||||
}
|
||||
|
||||
// It is a struct so zero it out.
|
||||
f.Set(reflect.New(f.Type().Elem()))
|
||||
}
|
||||
f = f.Elem()
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
// If we've found a struct, drill down, appending fields as we go.
|
||||
case f.Kind() == reflect.Struct:
|
||||
|
||||
// Skip if it can deserialize itself.
|
||||
if setterFrom(f) == nil && textUnmarshaler(f) == nil && binaryUnmarshaler(f) == nil {
|
||||
|
||||
// Prefix for any subkeys is the fieldKey, unless it's
|
||||
// anonymous, then it's just the prefix so far.
|
||||
innerPrefix := fieldKey
|
||||
if structField.Anonymous {
|
||||
innerPrefix = prefix
|
||||
}
|
||||
|
||||
embeddedPtr := f.Addr().Interface()
|
||||
innerFields, err := extractFields(innerPrefix, embeddedPtr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fields = append(fields, innerFields...)
|
||||
}
|
||||
default:
|
||||
envKey := fieldKey
|
||||
if fieldOpts.EnvName != "" {
|
||||
envKey = strings.Split(fieldOpts.EnvName, "_")
|
||||
}
|
||||
|
||||
flagKey := fieldKey
|
||||
if fieldOpts.FlagName != "" {
|
||||
flagKey = strings.Split(fieldOpts.FlagName, "-")
|
||||
}
|
||||
|
||||
fld := Field{
|
||||
Name: fieldName,
|
||||
EnvKey: envKey,
|
||||
FlagKey: flagKey,
|
||||
Field: f,
|
||||
Options: fieldOpts,
|
||||
BoolField: f.Kind() == reflect.Bool,
|
||||
}
|
||||
fields = append(fields, fld)
|
||||
}
|
||||
}
|
||||
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
func parseTag(tagStr string) (FieldOptions, error) {
|
||||
var f FieldOptions
|
||||
if tagStr == "" {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
tagParts := strings.Split(tagStr, ",")
|
||||
for _, tagPart := range tagParts {
|
||||
vals := strings.SplitN(tagPart, ":", 2)
|
||||
tagProp := vals[0]
|
||||
|
||||
switch len(vals) {
|
||||
case 1:
|
||||
switch tagProp {
|
||||
case "noprint":
|
||||
f.Noprint = true
|
||||
case "required":
|
||||
f.Required = true
|
||||
case "mask":
|
||||
f.Mask = true
|
||||
}
|
||||
case 2:
|
||||
tagPropVal := strings.TrimSpace(vals[1])
|
||||
if tagPropVal == "" {
|
||||
return f, fmt.Errorf("tag %q missing a value", tagProp)
|
||||
}
|
||||
switch tagProp {
|
||||
case "short":
|
||||
if len([]rune(tagPropVal)) != 1 {
|
||||
return f, fmt.Errorf("short value must be a single rune, got %q", tagPropVal)
|
||||
}
|
||||
f.ShortFlagChar = []rune(tagPropVal)[0]
|
||||
case "default":
|
||||
f.DefaultVal = tagPropVal
|
||||
case "env":
|
||||
f.EnvName = tagPropVal
|
||||
case "flag":
|
||||
f.FlagName = tagPropVal
|
||||
case "help":
|
||||
f.Help = tagPropVal
|
||||
}
|
||||
default:
|
||||
// TODO: Do we check for integrity issues here?
|
||||
}
|
||||
}
|
||||
|
||||
// Perform a sanity check.
|
||||
switch {
|
||||
case f.Required && f.DefaultVal != "":
|
||||
return f, fmt.Errorf("cannot set both `required` and `default`")
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// camelSplit takes a string based on camel case and splits it.
|
||||
func camelSplit(src string) []string {
|
||||
if src == "" {
|
||||
return []string{}
|
||||
}
|
||||
if len(src) < 2 {
|
||||
return []string{src}
|
||||
}
|
||||
|
||||
runes := []rune(src)
|
||||
|
||||
lastClass := charClass(runes[0])
|
||||
lastIdx := 0
|
||||
out := []string{}
|
||||
|
||||
// Split into fields based on class of unicode character.
|
||||
for i, r := range runes {
|
||||
class := charClass(r)
|
||||
|
||||
// If the class has transitioned.
|
||||
if class != lastClass {
|
||||
|
||||
// If going from uppercase to lowercase, we want to retain the last
|
||||
// uppercase letter for names like FOOBar, which should split to
|
||||
// FOO Bar.
|
||||
switch {
|
||||
case lastClass == classUpper && class != classNumber:
|
||||
if i-lastIdx > 1 {
|
||||
out = append(out, string(runes[lastIdx:i-1]))
|
||||
lastIdx = i - 1
|
||||
}
|
||||
default:
|
||||
out = append(out, string(runes[lastIdx:i]))
|
||||
lastIdx = i
|
||||
}
|
||||
}
|
||||
|
||||
if i == len(runes)-1 {
|
||||
out = append(out, string(runes[lastIdx:]))
|
||||
}
|
||||
lastClass = class
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func processField(value string, field reflect.Value) error {
|
||||
typ := field.Type()
|
||||
|
||||
// Look for a Set method.
|
||||
setter := setterFrom(field)
|
||||
if setter != nil {
|
||||
return setter.Set(value)
|
||||
}
|
||||
|
||||
if t := textUnmarshaler(field); t != nil {
|
||||
return t.UnmarshalText([]byte(value))
|
||||
}
|
||||
|
||||
if b := binaryUnmarshaler(field); b != nil {
|
||||
return b.UnmarshalBinary([]byte(value))
|
||||
}
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
if field.IsNil() {
|
||||
field.Set(reflect.New(typ))
|
||||
}
|
||||
field = field.Elem()
|
||||
}
|
||||
|
||||
switch typ.Kind() {
|
||||
case reflect.String:
|
||||
field.SetString(value)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
var (
|
||||
val int64
|
||||
err error
|
||||
)
|
||||
if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" {
|
||||
var d time.Duration
|
||||
d, err = time.ParseDuration(value)
|
||||
val = int64(d)
|
||||
} else {
|
||||
val, err = strconv.ParseInt(value, 0, typ.Bits())
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
field.SetInt(val)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
val, err := strconv.ParseUint(value, 0, typ.Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetUint(val)
|
||||
case reflect.Bool:
|
||||
val, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetBool(val)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
val, err := strconv.ParseFloat(value, typ.Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetFloat(val)
|
||||
case reflect.Slice:
|
||||
vals := strings.Split(value, ";")
|
||||
sl := reflect.MakeSlice(typ, len(vals), len(vals))
|
||||
for i, val := range vals {
|
||||
err := processField(val, sl.Index(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
field.Set(sl)
|
||||
case reflect.Map:
|
||||
mp := reflect.MakeMap(typ)
|
||||
if len(strings.TrimSpace(value)) != 0 {
|
||||
pairs := strings.Split(value, ";")
|
||||
for _, pair := range pairs {
|
||||
kvpair := strings.Split(pair, ":")
|
||||
if len(kvpair) != 2 {
|
||||
return fmt.Errorf("invalid map item: %q", pair)
|
||||
}
|
||||
k := reflect.New(typ.Key()).Elem()
|
||||
err := processField(kvpair[0], k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := reflect.New(typ.Elem()).Elem()
|
||||
err = processField(kvpair[1], v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mp.SetMapIndex(k, v)
|
||||
}
|
||||
}
|
||||
field.Set(mp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func interfaceFrom(field reflect.Value, fn func(interface{}, *bool)) {
|
||||
|
||||
// It may be impossible for a struct field to fail this check.
|
||||
if !field.CanInterface() {
|
||||
return
|
||||
}
|
||||
|
||||
var ok bool
|
||||
fn(field.Interface(), &ok)
|
||||
if !ok && field.CanAddr() {
|
||||
fn(field.Addr().Interface(), &ok)
|
||||
}
|
||||
}
|
||||
|
||||
// Setter is implemented by types can self-deserialize values.
|
||||
// Any type that implements flag.Value also implements Setter.
|
||||
type Setter interface {
|
||||
Set(value string) error
|
||||
}
|
||||
|
||||
func setterFrom(field reflect.Value) (s Setter) {
|
||||
interfaceFrom(field, func(v interface{}, ok *bool) { s, *ok = v.(Setter) })
|
||||
return s
|
||||
}
|
||||
|
||||
func textUnmarshaler(field reflect.Value) (t encoding.TextUnmarshaler) {
|
||||
interfaceFrom(field, func(v interface{}, ok *bool) { t, *ok = v.(encoding.TextUnmarshaler) })
|
||||
return t
|
||||
}
|
||||
|
||||
func binaryUnmarshaler(field reflect.Value) (b encoding.BinaryUnmarshaler) {
|
||||
interfaceFrom(field, func(v interface{}, ok *bool) { b, *ok = v.(encoding.BinaryUnmarshaler) })
|
||||
return b
|
||||
}
|
||||
|
||||
const (
|
||||
classLower int = iota
|
||||
classUpper
|
||||
classNumber
|
||||
classOther
|
||||
)
|
||||
|
||||
func charClass(r rune) int {
|
||||
switch {
|
||||
case unicode.IsLower(r):
|
||||
return classLower
|
||||
case unicode.IsUpper(r):
|
||||
return classUpper
|
||||
case unicode.IsDigit(r):
|
||||
return classNumber
|
||||
}
|
||||
return classOther
|
||||
}
|
205
vendor/github.com/ardanlabs/conf/sources.go
generated
vendored
Normal file
205
vendor/github.com/ardanlabs/conf/sources.go
generated
vendored
Normal file
|
@ -0,0 +1,205 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// env is a source for environmental variables.
|
||||
type env struct {
|
||||
m map[string]string
|
||||
}
|
||||
|
||||
// newSourceEnv accepts a namespace and parses the environment into a Env for
|
||||
// use by the configuration package.
|
||||
func newSourceEnv(namespace string) *env {
|
||||
m := make(map[string]string)
|
||||
|
||||
// Create the uppercase version to meet the standard {NAMESPACE_} format.
|
||||
// If the namespace is empty, remove the _ from the beginning of the string.
|
||||
uspace := fmt.Sprintf("%s_", strings.ToUpper(namespace))
|
||||
if namespace == "" {
|
||||
uspace = uspace[1:]
|
||||
}
|
||||
|
||||
// Loop and match each variable using the uppercase namespace.
|
||||
for _, val := range os.Environ() {
|
||||
if !strings.HasPrefix(val, uspace) {
|
||||
continue
|
||||
}
|
||||
|
||||
idx := strings.Index(val, "=")
|
||||
m[strings.ToUpper(strings.TrimPrefix(val[0:idx], uspace))] = val[idx+1:]
|
||||
}
|
||||
|
||||
return &env{m: m}
|
||||
}
|
||||
|
||||
// Source implements the confg.Sourcer interface. It returns the stringfied value
|
||||
// stored at the specified key from the environment.
|
||||
func (e *env) Source(fld Field) (string, bool) {
|
||||
k := strings.ToUpper(strings.Join(fld.EnvKey, `_`))
|
||||
v, ok := e.m[k]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// envUsage constructs a usage string for the environment variable.
|
||||
func envUsage(namespace string, fld Field) string {
|
||||
uspace := strings.ToUpper(namespace) + "_" + strings.ToUpper(strings.Join(fld.EnvKey, `_`))
|
||||
if namespace == "" {
|
||||
uspace = uspace[1:]
|
||||
}
|
||||
return "$" + uspace
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
// ErrHelpWanted provides an indication help was requested.
|
||||
var ErrHelpWanted = errors.New("help wanted")
|
||||
|
||||
// ErrVersionWanted provides an indication version was requested.
|
||||
var ErrVersionWanted = errors.New("version wanted")
|
||||
|
||||
// flag is a source for command line arguments.
|
||||
type flag struct {
|
||||
m map[string]string
|
||||
args []string
|
||||
}
|
||||
|
||||
// newSourceFlag parsing a string of command line arguments. NewFlag will return
|
||||
// errHelpWanted, if the help flag is identifyed. This code is adapted
|
||||
// from the Go standard library flag package.
|
||||
func newSourceFlag(args []string) (*flag, error) {
|
||||
m := make(map[string]string)
|
||||
|
||||
if len(args) != 0 {
|
||||
for {
|
||||
if len(args) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Look at the next arg.
|
||||
s := args[0]
|
||||
|
||||
// If it's too short or doesn't begin with a `-`, assume we're at
|
||||
// the end of the flags.
|
||||
if len(s) < 2 || s[0] != '-' {
|
||||
break
|
||||
}
|
||||
|
||||
numMinuses := 1
|
||||
if s[1] == '-' {
|
||||
numMinuses++
|
||||
if len(s) == 2 { // "--" terminates the flags
|
||||
args = args[1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
name := s[numMinuses:]
|
||||
if len(name) == 0 || name[0] == '-' || name[0] == '=' {
|
||||
return nil, fmt.Errorf("bad flag syntax: %s", s)
|
||||
}
|
||||
|
||||
// It's a flag. Does it have an argument?
|
||||
args = args[1:]
|
||||
hasValue := false
|
||||
value := ""
|
||||
for i := 1; i < len(name); i++ { // equals cannot be first
|
||||
if name[i] == '=' {
|
||||
value = name[i+1:]
|
||||
hasValue = true
|
||||
name = name[0:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if name == "help" || name == "h" || name == "?" {
|
||||
return nil, ErrHelpWanted
|
||||
}
|
||||
|
||||
if name == "version" || name == "v" {
|
||||
return nil, ErrVersionWanted
|
||||
}
|
||||
|
||||
// If we don't have a value yet, it's possible the flag was not in the
|
||||
// -flag=value format which means it might still have a value which would be
|
||||
// the next argument, provided the next argument isn't a flag.
|
||||
if !hasValue {
|
||||
if len(args) > 0 && len(args[0]) > 0 && args[0][0] != '-' {
|
||||
|
||||
// Doesn't look like a flag. Must be a value.
|
||||
value, args = args[0], args[1:]
|
||||
} else {
|
||||
|
||||
// We assume this is a boolean flag.
|
||||
value = "true"
|
||||
}
|
||||
}
|
||||
|
||||
// Store the flag/value pair.
|
||||
m[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
return &flag{m: m, args: args}, nil
|
||||
}
|
||||
|
||||
// Source implements the confg.Sourcer interface. Returns the stringfied value
|
||||
// stored at the specified key from the flag source.
|
||||
func (f *flag) Source(fld Field) (string, bool) {
|
||||
if fld.Options.ShortFlagChar != 0 {
|
||||
flagKey := fld.Options.ShortFlagChar
|
||||
k := strings.ToLower(string(flagKey))
|
||||
if val, found := f.m[k]; found {
|
||||
return val, found
|
||||
}
|
||||
}
|
||||
|
||||
k := strings.ToLower(strings.Join(fld.FlagKey, `-`))
|
||||
val, found := f.m[k]
|
||||
return val, found
|
||||
}
|
||||
|
||||
// flagUsage constructs a usage string for the flag argument.
|
||||
func flagUsage(fld Field) string {
|
||||
usage := "--" + strings.ToLower(strings.Join(fld.FlagKey, `-`))
|
||||
if fld.Options.ShortFlagChar != 0 {
|
||||
flagKey := []string{string(fld.Options.ShortFlagChar)}
|
||||
usage += "/-" + strings.ToLower(strings.Join(flagKey, `-`))
|
||||
}
|
||||
|
||||
return usage
|
||||
}
|
||||
|
||||
/*
|
||||
Portions Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
184
vendor/github.com/ardanlabs/conf/usage.go
generated
vendored
Normal file
184
vendor/github.com/ardanlabs/conf/usage.go
generated
vendored
Normal file
|
@ -0,0 +1,184 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
const versionKey = `SVN`
|
||||
const descKey = `Desc`
|
||||
|
||||
func containsField(fields []Field, name string) bool {
|
||||
for i := range fields {
|
||||
if name == fields[i].Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func fmtUsage(namespace string, fields []Field) string {
|
||||
var sb strings.Builder
|
||||
|
||||
fields = append(fields, Field{
|
||||
Name: "help",
|
||||
BoolField: true,
|
||||
Field: reflect.ValueOf(true),
|
||||
FlagKey: []string{"help"},
|
||||
Options: FieldOptions{
|
||||
ShortFlagChar: 'h',
|
||||
Help: "display this help message",
|
||||
}})
|
||||
|
||||
if containsField(fields, versionKey) {
|
||||
fields = append(fields, Field{
|
||||
Name: "version",
|
||||
BoolField: true,
|
||||
Field: reflect.ValueOf(true),
|
||||
FlagKey: []string{"version"},
|
||||
Options: FieldOptions{
|
||||
ShortFlagChar: 'v',
|
||||
Help: "display version information",
|
||||
}})
|
||||
}
|
||||
|
||||
_, file := path.Split(os.Args[0])
|
||||
fmt.Fprintf(&sb, "Usage: %s [options] [arguments]\n\n", file)
|
||||
|
||||
fmt.Fprintln(&sb, "OPTIONS")
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(&sb, 0, 4, 2, ' ', tabwriter.TabIndent)
|
||||
|
||||
for _, fld := range fields {
|
||||
|
||||
// Skip printing usage info for fields that just hold arguments.
|
||||
if fld.Field.Type() == argsT {
|
||||
continue
|
||||
}
|
||||
|
||||
// Do not display version fields SVN and Description
|
||||
if fld.Name == versionKey || fld.Name == descKey {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, " %s", flagUsage(fld))
|
||||
|
||||
// Do not display env vars for help since they aren't respected.
|
||||
if fld.Name != "help" && fld.Name != "version" {
|
||||
fmt.Fprintf(w, "/%s", envUsage(namespace, fld))
|
||||
}
|
||||
|
||||
typeName, help := getTypeAndHelp(&fld)
|
||||
|
||||
// Do not display type info for help because it would show <bool> but our
|
||||
// parsing does not really treat --help as a boolean field. Its presence
|
||||
// always indicates true even if they do --help=false.
|
||||
if fld.Name != "help" && fld.Name != "version" {
|
||||
fmt.Fprintf(w, "\t%s", typeName)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "\t%s\n", getOptString(fld))
|
||||
if help != "" {
|
||||
fmt.Fprintf(w, " %s\n", help)
|
||||
}
|
||||
}
|
||||
|
||||
w.Flush()
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// getTypeAndHelp extracts the type and help message for a single field for
|
||||
// printing in the usage message. If the help message contains text in
|
||||
// single quotes ('), this is assumed to be a more specific "type", and will
|
||||
// be returned as such. If there are no back quotes, it attempts to make a
|
||||
// guess as to the type of the field. Boolean flags are not printed with a
|
||||
// type, manually-specified or not, since their presence is equated with a
|
||||
// 'true' value and their absence with a 'false' value. If a type cannot be
|
||||
// determined, it will simply give the name "value". Slices will be annotated
|
||||
// as "<Type>,[Type...]", where "Type" is whatever type name was chosen.
|
||||
// (adapted from package flag).
|
||||
func getTypeAndHelp(fld *Field) (name string, usage string) {
|
||||
|
||||
// Look for a single-quoted name.
|
||||
usage = fld.Options.Help
|
||||
for i := 0; i < len(usage); i++ {
|
||||
if usage[i] == '\'' {
|
||||
for j := i + 1; j < len(usage); j++ {
|
||||
if usage[j] == '\'' {
|
||||
name = usage[i+1 : j]
|
||||
usage = usage[:i] + name + usage[j+1:]
|
||||
}
|
||||
}
|
||||
break // Only one single quote; use type name.
|
||||
}
|
||||
}
|
||||
|
||||
var isSlice bool
|
||||
if fld.Field.IsValid() {
|
||||
t := fld.Field.Type()
|
||||
|
||||
// If it's a pointer, we want to deref.
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
// If it's a slice, we want the type of the slice elements.
|
||||
if t.Kind() == reflect.Slice {
|
||||
t = t.Elem()
|
||||
isSlice = true
|
||||
}
|
||||
|
||||
// If no explicit name was provided, attempt to get the type
|
||||
if name == "" {
|
||||
switch t.Kind() {
|
||||
case reflect.Bool:
|
||||
name = "bool"
|
||||
case reflect.Float32, reflect.Float64:
|
||||
name = "float"
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
typ := fld.Field.Type()
|
||||
if typ.PkgPath() == "time" && typ.Name() == "Duration" {
|
||||
name = "duration"
|
||||
} else {
|
||||
name = "int"
|
||||
}
|
||||
case reflect.String:
|
||||
name = "string"
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
name = "uint"
|
||||
default:
|
||||
name = "value"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case isSlice:
|
||||
name = fmt.Sprintf("<%s>,[%s...]", name, name)
|
||||
case name != "":
|
||||
name = fmt.Sprintf("<%s>", name)
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getOptString(fld Field) string {
|
||||
opts := make([]string, 0, 3)
|
||||
if fld.Options.Required {
|
||||
opts = append(opts, "required")
|
||||
}
|
||||
if fld.Options.Noprint {
|
||||
opts = append(opts, "noprint")
|
||||
}
|
||||
if fld.Options.DefaultVal != "" {
|
||||
opts = append(opts, fmt.Sprintf("default: %s", fld.Options.DefaultVal))
|
||||
}
|
||||
if len(opts) > 0 {
|
||||
return fmt.Sprintf("(%s)", strings.Join(opts, `,`))
|
||||
}
|
||||
return ""
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue