Example #1
0
// ProcessObject checks if the object is valid from this schema's standpoint
// and returns an object with defaults set up according to schema's spec
func (j *JSONSchema) ProcessObject(in interface{}) (interface{}, error) {
	result, err := j.schema.Validate(gojsonschema.NewGoLoader(in))
	if err != nil {
		return nil, trace.Wrap(err)
	}
	if !result.Valid() {
		return nil, trace.Wrap(trace.Errorf("errors: %v", schemaErrors(result.Errors())))
	}
	return setDefaults(j.rawSchema, in), nil
}
Example #2
0
// ParseCommandLine takes a pointer to a function and attempts
// to initialize it from environment variables.
func ParseCommandLine(v interface{}, args []string) error {
	app, err := NewCommandLineApp(v)
	if err != nil {
		return trace.Wrap(err)
	}
	if _, err := app.Parse(args); err != nil {
		return trace.Wrap(err)
	}
	return nil
}
Example #3
0
// New returns JSON schema created from JSON byte string
// returns a valid schema or error if schema is invalid
func New(data []byte) (*JSONSchema, error) {
	j := JSONSchema{}
	err := json.Unmarshal(data, &j.rawSchema)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	loader := gojsonschema.NewGoLoader(j.rawSchema)
	j.schema, err = gojsonschema.NewSchema(loader)
	if err != nil {
		return nil, trace.Wrap(err)
	}
	return &j, nil
}
Example #4
0
func (p *cparser) parseEnum(s paramSpec) (Param, error) {
	var e *enumSpec
	if err := json.Unmarshal(s.S, &e); err != nil {
		return nil, trace.Wrap(
			err, fmt.Sprintf("failed to parse: '%v'", string(s.S)))
	}
	if len(e.Values) == 0 {
		return nil, trace.Errorf("provide at least one value for '%v'", s.Name)
	}

	values := make([]string, len(e.Values))
	seen := make(map[string]bool, len(e.Values))

	for i, v := range e.Values {
		if v == "" {
			return nil, trace.Errorf("value can not be an empty string")
		}
		if seen[v] {
			return nil, trace.Errorf("duplicate value: '%v'", v)
		}
		values[i] = v
	}

	ep := &EnumParam{values: values}
	ep.paramCommon = s.common()
	return ep, nil
}
Example #5
0
// TransformXML parses the XML tree, traverses it and calls TransformFunc
// on each XML token, writing the output to the writer, resulting in a
// transformed XML tree
func TransformXML(decoder *xml.Decoder, encoder *xml.Encoder, fn TransformFunc) error {
	parentNodes := &NodeList{}
	for {
		token, err := decoder.Token()
		if err != nil {
			if err != io.EOF {
				return trace.Wrap(err)
			}
			break
		}
		for _, t := range fn(parentNodes, token) {
			if err := encoder.EncodeToken(t); err != nil {
				return err
			}
		}
		switch e := token.(type) {
		case xml.StartElement:
			parentNodes.Push(e)
		case xml.EndElement:
			parentNodes.Pop()
		}
	}
	encoder.Flush()
	return nil
}
Example #6
0
func (p *cparser) parseKeyVal(s paramSpec) (Param, error) {
	var k *kvSpec
	if err := json.Unmarshal(s.S, &k); err != nil {
		return nil, trace.Wrap(
			err, fmt.Sprintf("failed to parse: '%v'", string(s.S)))
	}
	if len(k.Keys) == 0 {
		return nil, trace.Errorf("provide at least one key for '%v'", s.Name)
	}

	keys := make([]Param, len(k.Keys))

	for i, ks := range k.Keys {
		k, err := p.parseParam(ks, true)
		if err != nil {
			return nil, err
		}
		keys[i] = k
	}

	if err := checkSameNames(keys); err != nil {
		return nil, err
	}

	kv := &KVParam{keys: keys, separator: k.Separator}
	kv.paramCommon = s.common()
	return kv, nil
}
Example #7
0
// SetEnv sets the value from environment variable using json encoding
func (kv *KeyValSlice) SetEnv(v string) error {
	if err := json.Unmarshal([]byte(v), &kv); err != nil {
		return trace.Wrap(
			err, "failed to parse environment variable, expected JSON map")
	}
	return nil
}
Example #8
0
func (c *ctx) File(path string) (string, error) {
	o, err := ioutil.ReadFile(path)
	if err != nil {
		return "", trace.Wrap(err, fmt.Sprintf("reading file: %v", path))
	}
	return string(o), nil
}
Example #9
0
func (c *cliBoolValue) Set(v string) error {
	boolVal, err := strconv.ParseBool(v)
	if err != nil {
		return trace.Wrap(err)
	}
	*c.v = boolVal
	return nil
}
Example #10
0
// ParseYAML parses yaml-encoded byte string into the struct
// passed to the function.
// EnableTemplating() argument allows to treat configuration file as a template
// for example, it will support {{env "VAR"}} - that will substitute
// environment variable "VAR" and pass it to YAML file parser
func ParseYAML(data []byte, cfg interface{}, funcArgs ...ParseOption) error {
	var opts parseOptions
	for _, fn := range funcArgs {
		fn(&opts)
	}
	var err error
	if opts.templating {
		if data, err = renderTemplate(data); err != nil {
			return trace.Wrap(err)
		}
	}

	if err := yaml.Unmarshal(data, cfg); err != nil {
		return trace.Wrap(err)
	}
	return nil
}
Example #11
0
func (c *CIDR) Set(v string) error {
	out, err := ParseCIDR(v)
	if err != nil {
		return trace.Wrap(err)
	}
	*c = *out
	return nil
}
Example #12
0
func ParseVariablesJSON(r io.Reader) (*Config, error) {
	var variables []paramSpec

	if err := json.NewDecoder(r).Decode(&variables); err != nil {
		return nil, trace.Wrap(err)
	}
	return newParser().parse(configV1{Params: variables})
}
Example #13
0
func ParseJSON(r io.Reader) (*Config, error) {
	var c *configV1

	if err := json.NewDecoder(r).Decode(&c); err != nil {
		return nil, trace.Wrap(err)
	}
	return newParser().parse(*c)
}
Example #14
0
func (p *cparser) checkName(n string) error {
	for _, pr := range p.params {
		if pr.Name() == n {
			return trace.Errorf("parameter '%v' is already defined", n)
		}
	}
	e, err := parser.ParseExpr(n)
	if err != nil {
		return trace.Wrap(
			err, fmt.Sprintf("failed to parse name: '%v'", n))
	}
	if _, ok := e.(*ast.Ident); !ok {
		return trace.Wrap(
			err, fmt.Sprintf("name should be a valid identifier: '%v'", n))
	}
	return nil
}
Example #15
0
// NewCommandLineApp generates a command line parsing tool based on the struct
// that was passed in as a parameter
func NewCommandLineApp(v interface{}) (*kingpin.Application, error) {
	s := reflect.ValueOf(v).Elem()
	app := kingpin.New("app", "Auto generated command line application")
	if err := setupApp(app, s); err != nil {
		return nil, trace.Wrap(err)
	}
	return app, nil
}
Example #16
0
func (c *cliInt32Value) Set(v string) error {
	intValue, err := strconv.ParseInt(v, 0, 32)
	if err != nil {
		return trace.Wrap(err)
	}
	*c.v = int32(intValue)
	return nil
}
Example #17
0
// Set accepts string with arguments in the form "key:val,key2:val2"
func (kv *KeyValSlice) Set(v string) error {
	if len(*kv) == 0 {
		*kv = make([]map[string]string, 0)
	}
	var i KeyVal
	if err := i.Set(v); err != nil {
		return trace.Wrap(err)
	}
	*kv = append(*kv, i)
	return nil
}
Example #18
0
func renderTemplate(data []byte) ([]byte, error) {
	t := template.New("tpl")
	c, err := newCtx()
	if err != nil {
		return nil, trace.Wrap(err)
	}
	t.Funcs(map[string]interface{}{
		"env":  c.Env,
		"file": c.File,
	})
	t, err = t.Parse(string(data))
	if err != nil {
		return nil, trace.Wrap(err)
	}
	buf := &bytes.Buffer{}
	if err := t.Execute(buf, nil); err != nil {
		return nil, trace.Wrap(err)
	}
	return buf.Bytes(), nil
}
Example #19
0
func (c *cliSliceMapValue) Set(v string) error {
	if len(*c.v) == 0 {
		(*c.v) = make([]map[string]string, 0)
	}
	var kv map[string]string
	if err := setMap(&kv, v); err != nil {
		return trace.Wrap(err)
	}
	*c.v = append(*c.v, kv)
	return nil
}
Example #20
0
func (p *cparser) parseList(s paramSpec) (Param, error) {
	var ps *paramSpec
	if err := json.Unmarshal(s.S, &ps); err != nil {
		return nil, trace.Wrap(err, "failed to parse: '%v'", string(s.S))
	}
	el, err := p.parseParam(*ps, false)
	if err != nil {
		return nil, err
	}
	l := &ListParam{el: el}
	l.paramCommon = s.common()
	return l, nil
}
Example #21
0
func (c *Config) ParseVars(vars map[string]string) error {
	for _, p := range c.Params {
		val, ok := vars[p.Name()]
		if !ok {
			if p.Required() {
				return trace.Errorf("missing value for required variable: %v", p.Name())
			} else {
				val = p.Default()
			}
		}
		if err := p.Set(val); err != nil {
			return trace.Wrap(err)
		}
	}
	return nil
}
Example #22
0
// ProcessObject checks if the object is valid from this schema's standpoint
// and returns an object with defaults set up according to schema's spec
func (j *JSONSchema) ProcessObject(in interface{}) (interface{}, error) {
	defaults := setDefaults(j.rawSchema, in)

	result, err := j.schema.Validate(gojsonschema.NewGoLoader(defaults))
	if err != nil {
		return nil, trace.Wrap(err)
	}
	if !result.Valid() {
		errors := result.Errors()
		output := make([]string, len(errors))
		for i, err := range errors {
			output[i] = fmt.Sprintf("%v", err)
		}

		return nil, trace.Errorf("failed to validate: %v", strings.Join(output, ","))
	}
	return defaults, nil
}
Example #23
0
func setEnv(v reflect.Value, env map[string]string) error {
	// for structs, walk every element and parse
	vType := v.Type()
	if v.Kind() != reflect.Struct {
		return nil
	}
	for i := 0; i < v.NumField(); i++ {
		structField := vType.Field(i)
		field := v.Field(i)
		if !field.CanSet() {
			continue
		}
		kind := field.Kind()
		if kind == reflect.Struct {
			if err := setEnv(field, env); err != nil {
				return trace.Wrap(err,
					fmt.Sprintf("failed parsing struct field %v",
						structField.Name))
			}
		}
		envKey := structField.Tag.Get("env")

		if envKey == "" {
			continue
		}
		val, ok := env[envKey]
		if !ok || val == "" { // assume defaults
			continue
		}
		if field.CanAddr() {
			if s, ok := field.Addr().Interface().(EnvSetter); ok {
				if err := s.SetEnv(val); err != nil {
					return trace.Wrap(err)
				}
				continue
			}
			if s, ok := field.Addr().Interface().(StringSetter); ok {
				if err := s.Set(val); err != nil {
					return trace.Wrap(err)
				}
				continue
			}
		}
		switch kind {
		case reflect.Slice:
			if _, ok := field.Interface().([]map[string]string); ok {
				var kv KeyValSlice
				if err := kv.SetEnv(val); err != nil {
					return trace.Wrap(err, "error parsing key value list")
				}
				field.Set(reflect.ValueOf([]map[string]string(kv)))
			}
		case reflect.Map:
			if _, ok := field.Interface().(map[string]string); ok {
				var kv KeyVal
				if err := kv.SetEnv(val); err != nil {
					return trace.Wrap(err, "error parsing key value list")
				}
				field.Set(reflect.ValueOf(map[string]string(kv)))
			}
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			intValue, err := strconv.ParseInt(val, 0, field.Type().Bits())
			if err != nil {
				return trace.Wrap(err)
			}
			field.SetInt(intValue)
		case reflect.String:
			field.SetString(val)
		case reflect.Bool:
			boolVal, err := strconv.ParseBool(val)
			if err != nil {
				return trace.Wrap(
					err,
					fmt.Sprintf("failed parsing struct field %v, expected bool, got '%v'",
						structField.Name, val))
			}
			field.SetBool(boolVal)
		}
	}
	return nil
}
Example #24
0
func setupApp(app *kingpin.Application, v reflect.Value) error {
	// for structs, walk every element and parse
	vType := v.Type()
	if v.Kind() != reflect.Struct {
		return nil
	}
	for i := 0; i < v.NumField(); i++ {
		structField := vType.Field(i)
		field := v.Field(i)
		if !field.CanSet() {
			continue
		}
		kind := field.Kind()
		if kind == reflect.Struct {
			if err := setupApp(app, field); err != nil {
				return trace.Wrap(err,
					fmt.Sprintf("failed parsing struct field %v",
						structField.Name))
			}
		}
		cliFlag := structField.Tag.Get("cli")
		if cliFlag == "" {
			continue
		}
		if !field.CanAddr() {
			continue
		}
		f := app.Flag(cliFlag, cliFlag)
		fieldPtr := field.Addr().Interface()
		if setter, ok := fieldPtr.(CLISetter); ok {
			f.SetValue(&cliValue{setter: setter})
			continue
		}
		if setter, ok := fieldPtr.(StringSetter); ok {
			f.SetValue(&cliValue{setter: &cliStringSetter{setter: setter}})
			continue
		}
		switch ptr := fieldPtr.(type) {
		case *map[string]string:
			f.SetValue(&cliMapValue{v: ptr})
			continue
		case *[]map[string]string:
			f.SetValue(&cliSliceMapValue{v: ptr})
			continue
		case *int:
			f.SetValue(&cliIntValue{v: ptr})
			continue
		case *int32:
			f.SetValue(&cliInt32Value{v: ptr})
			continue
		case *int64:
			f.SetValue(&cliInt64Value{v: ptr})
			continue
		case *string:
			f.SetValue(&cliStringValue{v: ptr})
		case *bool:
			f.SetValue(&cliBoolValue{v: ptr})
		default:
			return trace.Errorf("unsupported type: %T", ptr)
		}
	}
	return nil
}