Пример #1
0
func (e *RequiredValidator) processField(fieldName string, field *structs.Field) error {
	fieldName += field.Name()
	switch field.Kind() {
	case reflect.Struct:
		// this is used for error messages below, when we have an error at the
		// child properties add parent properties into the error message as well
		fieldName += "."

		for _, f := range field.Fields() {
			if err := e.processField(fieldName, f); err != nil {
				return err
			}
		}
	default:
		val := field.Tag(e.RequiredTagName)
		if val != "true" && val != "1" {
			return nil
		}
		if field.IsZero() {
			return fmt.Errorf("Field '%s' is required", fieldName)
		}
	}

	return nil
}
Пример #2
0
// fieldSet sets field value from the given string value. It converts the
// string value in a sane way and is usefulf or environment variables or flags
// which are by nature in string types.
func fieldSet(field *structs.Field, s string) error {
	if err := field.Settable(); err != nil {
		return err
	}

	return setValue(field.ReflectValue(), s, field.Name())
}
Пример #3
0
func (e *RangeValidator) processField(fieldName string, field *structs.Field) error {
	fieldName += field.Name()
	switch field.Kind() {
	case reflect.Struct:
		// this is used for error messages below, when we have an error at the
		// child properties add parent properties into the error message as well
		fieldName += "."

		for _, f := range field.Fields() {
			if err := e.processField(fieldName, f); err != nil {
				return err
			}
		}
	default:
		if field.IsZero() { //if not initialized, we won't validate it
			return nil
		}
		minStr := field.Tag(e.MinTagName)
		maxStr := field.Tag(e.MaxTagName)
		if minStr == "" && maxStr == "" {
			return nil
		}

		err := validateRange(field, minStr, maxStr)
		if err != nil {
			return err
		}
	}

	return nil
}
Пример #4
0
func (e *SelectionValidator) processField(fieldName string, field *structs.Field) error {
	fieldName += field.Name()
	switch field.Kind() {
	case reflect.Struct:
		// this is used for error messages below, when we have an error at the
		// child properties add parent properties into the error message as well
		fieldName += "."

		for _, f := range field.Fields() {
			if err := e.processField(fieldName, f); err != nil {
				return err
			}
		}
	default:
		if field.IsZero() {
			return nil
		}
		selectionStr := field.Tag(e.SelectTagName)
		if selectionStr == "" {
			return nil
		}

		err := validateSelection(field, selectionStr)
		if err != nil {
			return err
		}
	}

	return nil
}
Пример #5
0
func validateSelection(field *structs.Field, selection string) error {
	selectionSet := strings.Split(selection, "|")
	switch field.Kind() {
	case reflect.Int:
		i := field.Value().(int)
		s := strconv.Itoa(i)
		for _, selection := range selectionSet {
			if s == selection {
				return nil
			}
		}
		return fmt.Errorf("validate: Field %s value %s, not in selection %s.", field.Name(), s, selection)
	case reflect.String:
		s := field.Value().(string)
		for _, selection := range selectionSet {
			if s == selection {
				return nil
			}
		}
		return fmt.Errorf("validate: Field %s value %s, not in selection %s.", field.Name(), s, selection)
	default:
		return nil
	}
	return nil
}
Пример #6
0
// generateFieldName generates the fiels name combined with the prefix and the
// struct's field name
func (e *EnvironmentLoader) generateFieldName(prefix string, field *structs.Field) string {
	fieldName := strings.ToUpper(field.Name())
	if e.CamelCase {
		fieldName = strings.ToUpper(strings.Join(camelcase.Split(field.Name()), "_"))
	}

	return strings.ToUpper(prefix) + "_" + fieldName
}
Пример #7
0
func validateString(field *structs.Field, regex string) error {
	switch field.Kind() {
	case reflect.String:
		i := field.Value().(string)
		matched, err := regexp.MatchString(regex, i)
		if err == nil && !matched {
			return fmt.Errorf("validate: Field %s value %s, regex %s not matched.", field.Name(), i, regex)
		}
	}

	return nil
}
Пример #8
0
func (b *Builder) keyFromField(f *structs.Field) string {
	tag := f.Tag(b.Tag)

	if i := strings.IndexRune(tag, ','); i != -1 {
		tag = tag[:i]
	}

	switch tag {
	case "-":
		return ""
	case "":
		return b.fieldFunc(f.Name())
	}

	return tag
}
Пример #9
0
// processField generates a flag based on the given field and fieldName. If a
// nested struct is detected, a flag for each field of that nested struct is
// generated too.
func (f *FlagLoader) processField(fieldName string, field *structs.Field) error {
	if f.CamelCase {
		fieldName = strings.Join(camelcase.Split(fieldName), "-")
	}

	switch field.Kind() {
	case reflect.Struct:
		for _, ff := range field.Fields() {
			flagName := field.Name() + "-" + ff.Name()

			if f.Flatten {
				// first check if it's set or not, because if we have duplicate
				// we don't want to break the flag. Panic by giving a readable
				// output
				f.flagSet.VisitAll(func(fl *flag.Flag) {
					if strings.ToLower(ff.Name()) == fl.Name {
						// already defined
						panic(fmt.Sprintf("flag '%s' is already defined in outer struct", fl.Name))
					}
				})

				flagName = ff.Name()
			}

			if err := f.processField(flagName, ff); err != nil {
				return err
			}
		}
	default:
		// Add custom prefix to the flag if it's set
		if f.Prefix != "" {
			fieldName = f.Prefix + "-" + fieldName
		}

		// we only can get the value from expored fields, unexported fields panics
		if field.IsExported() {
			// use built-in or custom flag usage message
			flagUsageFunc := flagUsageDefault
			if f.FlagUsageFunc != nil {
				flagUsageFunc = f.FlagUsageFunc
			}
			f.flagSet.Var(newFieldValue(field), flagName(fieldName), flagUsageFunc(fieldName))
		}
	}

	return nil
}
Пример #10
0
func validateLength(field *structs.Field, minlenStr string, maxlenStr string) error {
	switch field.Kind() {
	case reflect.String:
		i := field.Value().(string)
		l := len(i)

		min, minErr := strconv.Atoi(minlenStr)
		max, maxErr := strconv.Atoi(maxlenStr)
		if (minErr == nil && l < min) || (maxErr == nil && l > max) {
			return fmt.Errorf("validate: Field %s value %s, length limit: [%s, %s]", field.Name(), i, minlenStr, maxlenStr)
		}
	default:
		return nil
	}

	return nil
}
Пример #11
0
func (i *INILoader) setField(field *structs.Field, c *goconfig.ConfigFile, section string) error {
	//first process each subfield of a struct field
	switch field.Kind() {
	case reflect.Struct:
		for _, f := range field.Fields() {
			var subsection string
			if section == "" {
				subsection = field.Name()
			} else {
				subsection = section + "." + field.Name()
			}
			if err := i.setField(f, c, subsection); err != nil {
				return err
			}
		}
	default:
		v, err := c.GetValue(section, field.Name())
		if err == nil && v != "" {
			err := fieldSet(field, v)
			if err != nil {
				return err
			}
		}
	}

	return nil
}
Пример #12
0
func validateRange(field *structs.Field, minStr string, maxStr string) error {
	switch field.Kind() {
	case reflect.Int:
		i := field.Value().(int)

		min, minErr := strconv.Atoi(minStr)
		max, maxErr := strconv.Atoi(maxStr)
		if (minErr == nil && i < min) || (maxErr == nil && i > max) {
			return fmt.Errorf("validate: Field %s value %d, want: [%s, %s]", field.Name(), i, minStr, maxStr)
		}
	case reflect.Float64:
		i := field.Value().(float64)

		min, minErr := strconv.ParseFloat(minStr, 64)
		max, maxErr := strconv.ParseFloat(maxStr, 64)
		if (minErr == nil && i < min) || (maxErr == nil && i > max) {
			return fmt.Errorf("validate: Field %s value %f, want: [%s, %s]", field.Name(), i, minStr, maxStr)
		}
	case reflect.Int64:
		switch field.Value().(type) {
		case int64:
			i := field.Value().(int64)

			min, minErr := strconv.ParseInt(minStr, 10, 64)
			max, maxErr := strconv.ParseInt(maxStr, 10, 64)
			if (minErr == nil && i < min) || (maxErr == nil && i > max) {
				return fmt.Errorf("validate: Field %s value %d, want: [%s, %s]", field.Name(), i, minStr, maxStr)
			}
		default:
			return nil
		}
	default:
		return nil
	}

	return nil
}
Пример #13
0
// fieldSet sets field value from the given string value. It converts the
// string value in a sane way and is usefulf or environment variables or flags
// which are by nature in string types.
func fieldSet(field *structs.Field, v string) error {
	// TODO: add support for other types
	switch field.Kind() {
	case reflect.Bool:
		val, err := strconv.ParseBool(v)
		if err != nil {
			return err
		}

		if err := field.Set(val); err != nil {
			return err
		}
	case reflect.Int:
		i, err := strconv.Atoi(v)
		if err != nil {
			return err
		}

		if field.RawValue.Type().Name() != "int" {
			// We're probably dealing with an enum type
			field.RawValue.SetInt(int64(i))
			return nil
		}

		if err := field.Set(i); err != nil {
			return err
		}
	case reflect.String:
		if field.RawValue.Type().Name() != "string" {
			// We're probably dealing with an enum type
			field.RawValue.SetString(v)
			return nil
		}

		if err := field.Set(v); err != nil {
			return err
		}
	case reflect.Slice:
		switch t := field.Value().(type) {
		case []string:
			if err := field.Set(strings.Split(v, ",")); err != nil {
				return err
			}
		case []int:
			var list []int
			for _, in := range strings.Split(v, ",") {
				i, err := strconv.Atoi(in)
				if err != nil {
					return err
				}

				list = append(list, i)
			}

			if err := field.Set(list); err != nil {
				return err
			}
		default:
			return fmt.Errorf("multiconfig: field '%s' of type slice is unsupported: %s (%T)",
				field.Name(), field.Kind(), t)
		}
	case reflect.Float64:
		f, err := strconv.ParseFloat(v, 64)
		if err != nil {
			return err
		}

		if err := field.Set(f); err != nil {
			return err
		}
	case reflect.Int64:
		switch t := field.Value().(type) {
		case time.Duration:
			d, err := time.ParseDuration(v)
			if err != nil {
				return err
			}

			if err := field.Set(d); err != nil {
				return err
			}
		case int64:
			p, err := strconv.ParseInt(v, 10, 0)
			if err != nil {
				return err
			}

			if err := field.Set(p); err != nil {
				return err
			}
		default:
			return fmt.Errorf("multiconfig: field '%s' of type int64 is unsupported: %s (%T)",
				field.Name(), field.Kind(), t)
		}

	default:
		return fmt.Errorf("multiconfig: field '%s' has unsupported type: %s", field.Name(), field.Kind())
	}

	return nil
}
Пример #14
0
// fieldSet sets field value from the given string value. It converts the
// string value in a sane way and is usefulf or environment variables or flags
// which are by nature in string types.
func fieldSet(field *structs.Field, v string) error {
	switch field.Kind() {
	case reflect.Bool:
		val, err := strconv.ParseBool(v)
		if err != nil {
			return err
		}

		if err := field.Set(val); err != nil {
			return err
		}
	case reflect.Int:
		i, err := strconv.Atoi(v)
		if err != nil {
			return err
		}

		if err := field.Set(i); err != nil {
			return err
		}
	case reflect.String:
		if err := field.Set(v); err != nil {
			return err
		}
	case reflect.Map:
		switch t := field.Value().(type) {
		case map[string]int:
			si := make(map[string]int)
			if err := json.Unmarshal([]byte(v), &si); err != nil {
				return err
			}
			if err := field.Set(si); err != nil {
				return err
			}
		case map[string]string:
			ss := make(map[string]string)
			if err := json.Unmarshal([]byte(v), &ss); err != nil {
				return err
			}
			if err := field.Set(ss); err != nil {
				return err
			}
		default:
			return fmt.Errorf("config: field '%s' of type map is unsupported: %s (%T)",
				field.Name(), field.Kind(), t)
		}
	case reflect.Slice:
		switch t := field.Value().(type) {
		case []string:
			if err := field.Set(strings.Split(v, ",")); err != nil {
				return err
			}
		case []int:
			var list []int
			for _, in := range strings.Split(v, ",") {
				i, err := strconv.Atoi(in)
				if err != nil {
					return err
				}

				list = append(list, i)
			}

			if err := field.Set(list); err != nil {
				return err
			}
		case []int64:
			var list []int64
			for _, in := range strings.Split(v, ",") {
				i, err := strconv.ParseInt(in, 10, 64)
				if err != nil {
					return err
				}

				list = append(list, i)
			}

			if err := field.Set(list); err != nil {
				return err
			}
		case []float64:
			var list []float64
			for _, in := range strings.Split(v, ",") {
				i, err := strconv.ParseFloat(in, 64)
				if err != nil {
					return err
				}

				list = append(list, i)
			}

			if err := field.Set(list); err != nil {
				return err
			}
		default:
			return fmt.Errorf("config: field '%s' of type slice is unsupported: %s (%T)",
				field.Name(), field.Kind(), t)
		}
	case reflect.Float64:
		f, err := strconv.ParseFloat(v, 64)
		if err != nil {
			return err
		}

		if err := field.Set(f); err != nil {
			return err
		}
	case reflect.Int64:
		switch t := field.Value().(type) {
		case time.Duration:
			d, err := time.ParseDuration(v)
			if err != nil {
				return err
			}

			if err := field.Set(d); err != nil {
				return err
			}
		case int64:
			p, err := strconv.ParseInt(v, 10, 64)
			if err != nil {
				return err
			}

			if err := field.Set(p); err != nil {
				return err
			}
		default:
			return fmt.Errorf("config: field '%s' of type int64 is unsupported: %s (%T)",
				field.Name(), field.Kind(), t)
		}
	default:
		return fmt.Errorf("config: field '%s' has unsupported type: %s", field.Name(), field.Kind())
	}

	return nil
}
Пример #15
0
// fieldSet sets field value from the given string value. It converts the
// string value in a sane way and is usefulf or environment variables or flags
// which are by nature in string types.
func fieldSet(field *structs.Field, v string) error {
	switch f := field.Value().(type) {
	case flag.Value:
		if v := reflect.ValueOf(field.Value()); v.IsNil() {
			typ := v.Type()
			if typ.Kind() == reflect.Ptr {
				typ = typ.Elem()
			}

			if err := field.Set(reflect.New(typ).Interface()); err != nil {
				return err
			}

			f = field.Value().(flag.Value)
		}

		return f.Set(v)
	}

	// TODO: add support for other types
	switch field.Kind() {
	case reflect.Bool:
		val, err := strconv.ParseBool(v)
		if err != nil {
			return err
		}

		if err := field.Set(val); err != nil {
			return err
		}
	case reflect.Int:
		i, err := strconv.Atoi(v)
		if err != nil {
			return err
		}

		if err := field.Set(i); err != nil {
			return err
		}
	case reflect.String:
		if err := field.Set(v); err != nil {
			return err
		}
	case reflect.Slice:
		switch t := field.Value().(type) {
		case []string:
			if err := field.Set(strings.Split(v, ",")); err != nil {
				return err
			}
		case []int:
			var list []int
			for _, in := range strings.Split(v, ",") {
				i, err := strconv.Atoi(in)
				if err != nil {
					return err
				}

				list = append(list, i)
			}

			if err := field.Set(list); err != nil {
				return err
			}
		default:
			return fmt.Errorf("multiconfig: field '%s' of type slice is unsupported: %s (%T)",
				field.Name(), field.Kind(), t)
		}
	case reflect.Float64:
		f, err := strconv.ParseFloat(v, 64)
		if err != nil {
			return err
		}

		if err := field.Set(f); err != nil {
			return err
		}
	case reflect.Int64:
		switch t := field.Value().(type) {
		case time.Duration:
			d, err := time.ParseDuration(v)
			if err != nil {
				return err
			}

			if err := field.Set(d); err != nil {
				return err
			}
		case int64:
			p, err := strconv.ParseInt(v, 10, 0)
			if err != nil {
				return err
			}

			if err := field.Set(p); err != nil {
				return err
			}
		default:
			return fmt.Errorf("multiconfig: field '%s' of type int64 is unsupported: %s (%T)",
				field.Name(), field.Kind(), t)
		}

	default:
		return fmt.Errorf("multiconfig: field '%s' has unsupported type: %s", field.Name(), field.Kind())
	}

	return nil
}