add comments
This commit is contained in:
parent
e7703f94bf
commit
4bf6f65377
45
cli/cli.go
45
cli/cli.go
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 eschao <esc.chao@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -11,10 +26,13 @@ import (
|
|||||||
"github.com/eschao/config/utils"
|
"github.com/eschao/config/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// anyValue wraps a reflect.Value object and implements flag.Value interface
|
||||||
|
// the reflect.Value could be Bool, String, Int, Uint and Float
|
||||||
type anyValue struct {
|
type anyValue struct {
|
||||||
any reflect.Value
|
any reflect.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newAnyValue creates an anyValue object
|
||||||
func newAnyValue(v reflect.Value) *anyValue {
|
func newAnyValue(v reflect.Value) *anyValue {
|
||||||
return &anyValue{any: v}
|
return &anyValue{any: v}
|
||||||
}
|
}
|
||||||
@ -78,6 +96,8 @@ func (this *anyValue) Set(v string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sliceValue wraps a reflect.Value object and implements flag.Value interface
|
||||||
|
// the reflect.Value could only be a sliceable type
|
||||||
type sliceValue struct {
|
type sliceValue struct {
|
||||||
value reflect.Value
|
value reflect.Value
|
||||||
separator string
|
separator string
|
||||||
@ -99,19 +119,26 @@ func (this *sliceValue) Set(v string) error {
|
|||||||
return utils.SetValueWithSlice(this.value, v, sp)
|
return utils.SetValueWithSlice(this.value, v, sp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// errorHanling is a global flag.ErrorHandling
|
||||||
var errorHandling = flag.ExitOnError
|
var errorHandling = flag.ExitOnError
|
||||||
|
|
||||||
|
// UsageFunc defines a callback function for printing command usage
|
||||||
type UsageFunc func(*Command) func()
|
type UsageFunc func(*Command) func()
|
||||||
|
|
||||||
|
// usageHandler is a global UsageFunc callback, default is nil which means it
|
||||||
|
// will use default flag.Usage function
|
||||||
var usageHandler UsageFunc = nil
|
var usageHandler UsageFunc = nil
|
||||||
|
|
||||||
|
// Command defines a command line structure
|
||||||
type Command struct {
|
type Command struct {
|
||||||
Name string
|
Name string // command name
|
||||||
FlagSet *flag.FlagSet
|
FlagSet *flag.FlagSet // command arguments
|
||||||
Usage string
|
Usage string // command usage description
|
||||||
SubCommands map[string]*Command
|
SubCommands map[string]*Command // sub-commands
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New creates a command with given name, the command will use default
|
||||||
|
// ErrorHandling: flag.ExitOnError and default usage function: flag.Usage
|
||||||
func New(name string) *Command {
|
func New(name string) *Command {
|
||||||
cmd := Command{
|
cmd := Command{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -122,6 +149,8 @@ func New(name string) *Command {
|
|||||||
return &cmd
|
return &cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewWith creates a command with given name, error handling and customized
|
||||||
|
// usage function
|
||||||
func NewWith(name string, errHandling flag.ErrorHandling,
|
func NewWith(name string, errHandling flag.ErrorHandling,
|
||||||
usageHandling UsageFunc) *Command {
|
usageHandling UsageFunc) *Command {
|
||||||
errorHandling = errHandling
|
errorHandling = errHandling
|
||||||
@ -139,6 +168,9 @@ func NewWith(name string, errHandling flag.ErrorHandling,
|
|||||||
return &cmd
|
return &cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init analyzes the given structure interface, extracts cli definitions from
|
||||||
|
// its tag and installs command flagset by flag APIs. The interface must be a
|
||||||
|
// structure pointer, otherwise will return an error
|
||||||
func (this *Command) Init(i interface{}) error {
|
func (this *Command) Init(i interface{}) error {
|
||||||
ptrRef := reflect.ValueOf(i)
|
ptrRef := reflect.ValueOf(i)
|
||||||
|
|
||||||
@ -156,6 +188,7 @@ func (this *Command) Init(i interface{}) error {
|
|||||||
return this.parseValue(valueOfStruct)
|
return this.parseValue(valueOfStruct)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseValue parses a reflect.Value object and extracts cli definitions
|
||||||
func (this *Command) parseValue(v reflect.Value) error {
|
func (this *Command) parseValue(v reflect.Value) error {
|
||||||
typeOfStruct := v.Type()
|
typeOfStruct := v.Type()
|
||||||
var err error
|
var err error
|
||||||
@ -181,6 +214,7 @@ func (this *Command) parseValue(v reflect.Value) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addFlag installs a command flag variable by flag API
|
||||||
func (this *Command) addFlag(v reflect.Value, f reflect.StructField) error {
|
func (this *Command) addFlag(v reflect.Value, f reflect.StructField) error {
|
||||||
cmdTag, ok := f.Tag.Lookup("cli")
|
cmdTag, ok := f.Tag.Lookup("cli")
|
||||||
if !ok || cmdTag == "" {
|
if !ok || cmdTag == "" {
|
||||||
@ -226,6 +260,7 @@ func (this *Command) addFlag(v reflect.Value, f reflect.StructField) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createSubCommand creates sub-commands
|
||||||
func (this *Command) createSubCommand(tag reflect.StructTag) *Command {
|
func (this *Command) createSubCommand(tag reflect.StructTag) *Command {
|
||||||
cmdTag, ok := tag.Lookup("cli")
|
cmdTag, ok := tag.Lookup("cli")
|
||||||
if !ok || cmdTag == "" {
|
if !ok || cmdTag == "" {
|
||||||
@ -253,6 +288,8 @@ func (this *Command) createSubCommand(tag reflect.StructTag) *Command {
|
|||||||
return &cmd
|
return &cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse parses values from command line and save values into given structure.
|
||||||
|
// The Init(interface{}) function must be called before parsing
|
||||||
func (this *Command) Parse(args []string) error {
|
func (this *Command) Parse(args []string) error {
|
||||||
if err := this.FlagSet.Parse(args); err != nil {
|
if err := this.FlagSet.Parse(args); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 eschao <esc.chao@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
39
config.go
39
config.go
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 eschao <esc.chao@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -15,6 +30,7 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Default configuration file
|
||||||
const (
|
const (
|
||||||
DefaultJSONConfig = "config.json"
|
DefaultJSONConfig = "config.json"
|
||||||
DefaultYamlConfig = "config.yaml"
|
DefaultYamlConfig = "config.yaml"
|
||||||
@ -27,6 +43,10 @@ const (
|
|||||||
PropConfigType = "properties"
|
PropConfigType = "properties"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ParseDefault parses the given structure, extract default value from its tag
|
||||||
|
// and set structure with these values.
|
||||||
|
// Normally, ParseDefault should be called before any other parsing functions
|
||||||
|
// to set default values for structure.
|
||||||
func ParseDefault(i interface{}) error {
|
func ParseDefault(i interface{}) error {
|
||||||
ptrRef := reflect.ValueOf(i)
|
ptrRef := reflect.ValueOf(i)
|
||||||
|
|
||||||
@ -108,10 +128,13 @@ func parseValue(v reflect.Value) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseEnv parses given structure interface and set it with corresponding
|
||||||
|
// environment values
|
||||||
func ParseEnv(i interface{}) error {
|
func ParseEnv(i interface{}) error {
|
||||||
return env.ParseWith(i, "")
|
return env.ParseWith(i, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseCli parses given structure interface and set it with command line input
|
||||||
func ParseCli(i interface{}) error {
|
func ParseCli(i interface{}) error {
|
||||||
cli := cli.New(os.Args[0])
|
cli := cli.New(os.Args[0])
|
||||||
if err := cli.Init(i); err != nil {
|
if err := cli.Init(i); err != nil {
|
||||||
@ -123,11 +146,19 @@ func ParseCli(i interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseConfig parses given structure interface and set it with default
|
||||||
|
// configuration file.
|
||||||
|
// configFlag is a command line flag to tell where to locate configure file.
|
||||||
|
// If the config file doesn't exist, the default config fill will be searched
|
||||||
|
// under the same folder with the fixed order: config.json, config.yaml and
|
||||||
|
// config.properties
|
||||||
func ParseConfig(i interface{}, configFlag string) error {
|
func ParseConfig(i interface{}, configFlag string) error {
|
||||||
configFile := flag.String(configFlag, "", "Specifiy configuration file")
|
configFile := flag.String(configFlag, "", "Specifiy configuration file")
|
||||||
return ParseConfigFile(i, *configFile)
|
return ParseConfigFile(i, *configFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseConfigFile parses given structure interface and set its value with
|
||||||
|
// the specified configuration file
|
||||||
func ParseConfigFile(i interface{}, configFile string) error {
|
func ParseConfigFile(i interface{}, configFile string) error {
|
||||||
var err error
|
var err error
|
||||||
if configFile == "" {
|
if configFile == "" {
|
||||||
@ -156,6 +187,7 @@ func ParseConfigFile(i interface{}, configFile string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseJSON parses JSON file and set structure with its value
|
||||||
func parseJSON(i interface{}, jsonFile string) error {
|
func parseJSON(i interface{}, jsonFile string) error {
|
||||||
raw, err := ioutil.ReadFile(jsonFile)
|
raw, err := ioutil.ReadFile(jsonFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -165,6 +197,7 @@ func parseJSON(i interface{}, jsonFile string) error {
|
|||||||
return json.Unmarshal(raw, i)
|
return json.Unmarshal(raw, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseYaml parses Yaml file and set structure with its value
|
||||||
func parseYaml(i interface{}, yamlFile string) error {
|
func parseYaml(i interface{}, yamlFile string) error {
|
||||||
raw, err := ioutil.ReadFile(yamlFile)
|
raw, err := ioutil.ReadFile(yamlFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -174,10 +207,14 @@ func parseYaml(i interface{}, yamlFile string) error {
|
|||||||
return yaml.Unmarshal(raw, i)
|
return yaml.Unmarshal(raw, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseProp parses Properties file and set structure with its value
|
||||||
func parseProp(i interface{}, propFile string) error {
|
func parseProp(i interface{}, propFile string) error {
|
||||||
return fmt.Errorf("Properties config has not implemented!")
|
return fmt.Errorf("Properties config has not implemented!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getDefaultConfigFile returns a existing default config file. The checking
|
||||||
|
// order is fixed with beginning from: config.json to config.yaml and
|
||||||
|
// config.properties
|
||||||
func getDefaultConfigFile() (string, error) {
|
func getDefaultConfigFile() (string, error) {
|
||||||
exe, err := os.Executable()
|
exe, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -207,6 +244,8 @@ func getDefaultConfigFile() (string, error) {
|
|||||||
return "", fmt.Errorf("No default config file found in path: %s", path)
|
return "", fmt.Errorf("No default config file found in path: %s", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getConfigFileType analyzes config file extension name and return
|
||||||
|
// corresponding type: json, yaml or properties
|
||||||
func getConfigFileType(configFile string) (string, error) {
|
func getConfigFileType(configFile string) (string, error) {
|
||||||
ext := filepath.Ext(configFile)
|
ext := filepath.Ext(configFile)
|
||||||
if ext == ".json" {
|
if ext == ".json" {
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 eschao <esc.chao@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
33
env/env.go
vendored
33
env/env.go
vendored
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 eschao <esc.chao@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 env
|
package env
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -8,10 +23,25 @@ import (
|
|||||||
"github.com/eschao/config/utils"
|
"github.com/eschao/config/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Parse parses given structure interface, extracts environment definitions
|
||||||
|
// from its tag and sets structure with defined environement variables
|
||||||
func Parse(i interface{}) error {
|
func Parse(i interface{}) error {
|
||||||
return ParseWith(i, "")
|
return ParseWith(i, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseWith parses with given structure interface and environment name prefix
|
||||||
|
// It is normally used in nested structure.
|
||||||
|
// For example: we have such structure
|
||||||
|
// type Database struct {
|
||||||
|
// Host string `env:"HOST"`
|
||||||
|
// }
|
||||||
|
|
||||||
|
// type Server struct {
|
||||||
|
// Server string `env:"SERVER"`
|
||||||
|
// DB Database `env:"DB_"`
|
||||||
|
// }
|
||||||
|
// The Server.DB.Host will be mapped to environment variable: DB_HOST which is
|
||||||
|
// concatenated from DB tag in Server struct and Host tag in Database struct
|
||||||
func ParseWith(i interface{}, prefix string) error {
|
func ParseWith(i interface{}, prefix string) error {
|
||||||
ptrRef := reflect.ValueOf(i)
|
ptrRef := reflect.ValueOf(i)
|
||||||
|
|
||||||
@ -29,6 +59,7 @@ func ParseWith(i interface{}, prefix string) error {
|
|||||||
return parseValue(valueOfStruct, prefix)
|
return parseValue(valueOfStruct, prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseValue parses a reflect.Value object
|
||||||
func parseValue(v reflect.Value, prefix string) error {
|
func parseValue(v reflect.Value, prefix string) error {
|
||||||
typeOfStruct := v.Type()
|
typeOfStruct := v.Type()
|
||||||
var err error
|
var err error
|
||||||
@ -55,6 +86,7 @@ func parseValue(v reflect.Value, prefix string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getEnvValue get environment value
|
||||||
func getEnvValue(envName string, f reflect.StructField) (string, bool) {
|
func getEnvValue(envName string, f reflect.StructField) (string, bool) {
|
||||||
//fmt.Printf("Lookup ENV: %s\n", envName)
|
//fmt.Printf("Lookup ENV: %s\n", envName)
|
||||||
envValue, ok := os.LookupEnv(envName)
|
envValue, ok := os.LookupEnv(envName)
|
||||||
@ -65,6 +97,7 @@ func getEnvValue(envName string, f reflect.StructField) (string, bool) {
|
|||||||
return envValue, ok
|
return envValue, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setFieldValue sets a reflect.Value with environment value
|
||||||
func setFieldValue(v reflect.Value, f reflect.StructField, prefix string) error {
|
func setFieldValue(v reflect.Value, f reflect.StructField, prefix string) error {
|
||||||
envName := f.Tag.Get("env")
|
envName := f.Tag.Get("env")
|
||||||
if envName == "" {
|
if envName == "" {
|
||||||
|
15
env/env_test.go
vendored
15
env/env_test.go
vendored
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 eschao <esc.chao@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 env
|
package env
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
15
test/data.go
15
test/data.go
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 eschao <esc.chao@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 test
|
package test
|
||||||
|
|
||||||
type DBConfig struct {
|
type DBConfig struct {
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 eschao <esc.chao@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 eschao <esc.chao@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
Loading…
Reference in New Issue
Block a user