Beispiel #1
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
}
Beispiel #2
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
}
Beispiel #3
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
}
Beispiel #4
0
func checkSameNames(ps []Param) error {
	n := map[string]bool{}
	for _, p := range ps {
		if n[p.Name()] {
			return trace.Errorf("parameter '%v' is already defined", n)
		}
		n[p.Name()] = true
	}
	return nil
}
Beispiel #5
0
func (c *ctx) Env(key string) (string, error) {
	v, ok := c.env[key]
	if !ok {
		return "", trace.Errorf("environment variable '%v' is not set", key)
	}
	values := cstrings.SplitComma(v)
	out := make([]string, len(values))
	for i, p := range values {
		out[i] = quoteYAML(p)
	}
	return strings.Join(out, ","), nil
}
Beispiel #6
0
func parseEnvironment() (map[string]string, error) {
	values := os.Environ()
	env := make(map[string]string, len(values))
	for _, v := range values {
		vals := strings.SplitN(v, "=", 2)
		if len(vals) != 2 {
			return nil, trace.Errorf("failed to parse variable: '%v'", v)
		}
		env[vals[0]] = vals[1]
	}
	return env, nil
}
Beispiel #7
0
func (p *cparser) parseParam(s paramSpec, scalar bool) (Param, error) {
	if s.Name == "" {
		return nil, trace.Errorf("set a type name")
	}
	if err := p.checkName(s.Name); err != nil {
		return nil, err
	}
	if s.Type == "" {
		return nil, trace.Errorf("set a type for '%v'", s.Name)
	}
	switch s.Type {
	case "String":
		pr := &StringParam{}
		pr.paramCommon = s.common()
		return pr, nil
	case "Path":
		pr := &PathParam{}
		pr.paramCommon = s.common()
		return pr, nil
	case "Int":
		pr := &IntParam{}
		pr.paramCommon = s.common()
		return pr, nil
	case "Bool":
		pr := &BoolParam{}
		pr.paramCommon = s.common()
		return pr, nil
	case "KeyVal":
		return p.parseKeyVal(s)
	case "Enum":
		return p.parseEnum(s)
	case "List":
		if scalar {
			return nil, trace.Errorf(
				"scalar values are not allowed here: '%v'", s.Type)
		}
		return p.parseList(s)
	}
	return nil, trace.Errorf("unrecognized type: '%v'", s.Type)
}
Beispiel #8
0
// Set accepts string with arguments in the form "key:val,key2:val2"
func (kv *KeyVal) Set(v string) error {
	if len(*kv) == 0 {
		*kv = make(map[string]string)
	}
	for _, i := range cstrings.SplitComma(v) {
		vals := strings.SplitN(i, ":", 2)
		if len(vals) != 2 {
			return trace.Errorf("extra options should be defined like KEY:VAL")
		}
		(*kv)[vals[0]] = vals[1]
	}
	return nil
}
Beispiel #9
0
func newCtx() (*ctx, error) {
	values := os.Environ()
	c := &ctx{
		env: make(map[string]string, len(values)),
	}
	for _, v := range values {
		vals := strings.SplitN(v, "=", 2)
		if len(vals) != 2 {
			return nil, trace.Errorf("failed to parse variable: '%v'", v)
		}
		c.env[vals[0]] = vals[1]
	}
	return c, nil
}
Beispiel #10
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
}
Beispiel #11
0
func (p *EnumParam) Set(s string) error {
	found := false
	for _, v := range p.values {
		if s == v {
			found = true
		}
	}
	if !found {
		return trace.Errorf(
			"value '%v' is not one of the allowed '%v'",
			s, strings.Join(p.values, ","),
		)
	}
	p.value = &s
	return nil
}
Beispiel #12
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
}
Beispiel #13
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
}
Beispiel #14
0
func (p *KVParam) Set(s string) error {
	sep := p.sep()

	parts := strings.Split(s, sep)
	if len(parts) != len(p.keys) {
		return trace.Errorf(
			"expected elements separated by '%v', got '%v'", sep, s)
	}
	values := make([]Param, len(p.keys))
	for i, pt := range parts {
		el := p.keys[i].New()
		if err := el.Set(pt); err != nil {
			return err
		}
		values[i] = el
	}

	p.values = values
	return nil
}
Beispiel #15
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
}