func ExampleGetFieldTag() {
	s := MyStruct{}

	tag, err := reflections.GetFieldTag(s, "FirstField", "matched")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(tag)

	tag, err = reflections.GetFieldTag(s, "ThirdField", "unmatched")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(tag)
}
Exemple #2
0
// ProcessCopy processes copy.
func (dc *DeepCopier) ProcessCopy() error {
	fields, _ := reflections.Fields(dc.Tagged)
	for _, field := range fields {
		fieldOptions := &FieldOptions{
			SourceField:      field,
			DestinationField: field,
			WithContext:      false,
			Skip:             false,
		}
		tagOptions, _ := reflections.GetFieldTag(dc.Tagged, field, TagName)
		if tagOptions != "" {
			opts := dc.GetTagOptions(tagOptions)
			if _, ok := opts[FieldOptionName]; ok {
				fieldName := opts[FieldOptionName]
				if !dc.Reversed {
					fieldOptions.SourceField = fieldName
				} else {
					fieldOptions.DestinationField = fieldName
				}
			}
			if _, ok := opts[ContextOptionName]; ok {
				fieldOptions.WithContext = true
			}
			if _, ok := opts[SkipOptionName]; ok {
				fieldOptions.Skip = true
			}
		}
		if err := dc.SetField(fieldOptions); err != nil {
			return err
		}
	}
	return nil
}
func (t *MyTools) GetValueByNamespace(object interface{}, ns []string) interface{} {
	// current level of namespace
	current := ns[0]
	fields, err := reflections.Fields(object)
	if err != nil {
		fmt.Printf("Could not return fields for object{%v}\n", object)
		return nil
	}

	for _, field := range fields {
		tag, err := reflections.GetFieldTag(object, field, "json")
		if err != nil {
			fmt.Printf("Could not find tag for field{%s}\n", field)
			return nil
		}
		// remove omitempty from tag
		tag = strings.Replace(tag, ",omitempty", "", -1)
		if tag == current {
			val, _ := reflections.GetField(object, field)

			// handling of special cases for slice and map
			switch reflect.TypeOf(val).Kind() {
			case reflect.Slice:
				idx, _ := strconv.Atoi(ns[1])
				val := reflect.ValueOf(val)
				if val.Index(idx).Kind() == reflect.Struct {
					return t.GetValueByNamespace(val.Index(idx).Interface(), ns[2:])
				} else {
					return val.Index(idx).Interface()
				}
			case reflect.Map:
				key := ns[1]
				// try uint64 map (memory_stats case)
				if vi, ok := val.(map[string]uint64); ok {
					return vi[key]
				}
				// try with hugetlb map (hugetlb_stats case)
				val := reflect.ValueOf(val)
				kval := reflect.ValueOf(key)
				if reflect.TypeOf(val.MapIndex(kval).Interface()).Kind() == reflect.Struct {
					return t.GetValueByNamespace(val.MapIndex(kval).Interface(), ns[2:])
				}
			default:
				// last ns, return value found
				if len(ns) == 1 {
					return val
				} else {
					// or go deeper
					return t.GetValueByNamespace(val, ns[1:])
				}
			}
		}
	}
	return nil
}
Exemple #4
0
// ProcessCopy processes copy.
func (dc *DeepCopier) ProcessCopy() error {
	fields := []string{}

	val := reflect.ValueOf(dc.Tagged).Elem()

	for i := 0; i < val.NumField(); i++ {
		typ := val.Type().Field(i)

		// Embedded struct
		if typ.Anonymous {
			f, _ := reflections.Fields(val.Field(i).Interface())
			fields = append(fields, f...)
		} else {
			fields = append(fields, typ.Name)
		}
	}

	for _, field := range fields {
		fieldOptions := &FieldOptions{
			SourceField:      field,
			DestinationField: field,
			WithContext:      false,
			Skip:             false,
		}

		tagOptions, _ := reflections.GetFieldTag(dc.Tagged, field, TagName)

		if tagOptions != "" {
			opts := dc.GetTagOptions(tagOptions)
			if _, ok := opts[FieldOptionName]; ok {
				fieldName := opts[FieldOptionName]
				if !dc.Reversed {
					fieldOptions.SourceField = fieldName
				} else {
					fieldOptions.DestinationField = fieldName
				}
			}
			if _, ok := opts[ContextOptionName]; ok {
				fieldOptions.WithContext = true
			}
			if _, ok := opts[SkipOptionName]; ok {
				fieldOptions.Skip = true
			}
		}

		if err := dc.SetField(fieldOptions); err != nil {
			return err
		}
	}
	return nil
}
Exemple #5
0
// createFieldInfos creates the fieldInfos for a struct s.
// Only information from the struct (headerName, fieldName and kind) is available,
// all field positions are initialized with an invalid value of -1
func createFieldInfos(s interface{}) (fieldInfos, error) {
	if reflect.TypeOf(s).Kind() != reflect.Struct {
		return nil, ErrNoStruct
	}
	fieldInfos := []fieldInfo{}
	headerNameMap := map[string]interface{}{} // to detect duplicate csv tag names
	fieldNames, err := reflections.Fields(s)
	if err != nil {
		return nil, err
	}
	for _, fieldName := range fieldNames {
		headerName, err := reflections.GetFieldTag(s, fieldName, "csv")
		if err != nil {
			return nil, err
		}
		// csv fieldtags that contain a dash are ignored
		if strings.Contains(headerName, "-") {
			continue
		}
		if _, ok := headerNameMap[headerName]; ok {
			return nil, fmt.Errorf("duplicate csv tag name: %s", headerName)
		}
		headerNameMap[headerName] = nil
		kind, err := reflections.GetFieldKind(s, fieldName)
		if err != nil {
			return nil, err
		}
		if len(headerName) == 0 {
			return nil, fmt.Errorf("empty csv tag for field: %s", fieldName)
		}
		fieldInfos = append(fieldInfos, fieldInfo{
			headerName: headerName,
			fieldName:  fieldName,
			position:   -1,
			kind:       kind,
		})
	}
	return fieldInfos, nil
}
Exemple #6
0
func formTagFromField(fieldName string, target interface{}) (string, error) {
	fieldKind, err := reflections.GetFieldKind(target, fieldName)
	f, _ := reflections.GetField(target, fieldName)
	fmt.Printf("Field %v\n", f)
	if err != nil {
		return "", err
	}

	choices, _ := reflections.GetFieldTag(target, fieldName, "choices")

	switch fieldKind {
	case reflect.String:
		if choices != "" {
			return "list", nil
		}
		return "input", nil
	case reflect.Slice:

		return "checkbox", nil
	case reflect.Bool:
		return "confirm", nil
	}
	return "", nil
}
// Reflects on the values in the commandLineOptions structure, and fills it
// with values either from the command line, or from the ENV.
func parseArgs(opts *commandLineOptions, args []string) {
	// Create a flag set for args
	flags := flag.NewFlagSet(commandLineName, flag.ExitOnError)

	// Get the fields for the strucutre
	fields, _ := reflections.Fields(opts)

	// Loop through each field of the structure, and define a flag for it
	for i := 0; i < len(fields); i++ {
		fieldName := fields[i]
		flagName, _ := reflections.GetFieldTag(opts, fieldName, "flag")
		fieldKind, _ := reflections.GetFieldKind(opts, fieldName)

		if fieldKind == reflect.String {
			flags.String(flagName, "", "")
		} else if fieldKind == reflect.Bool {
			flags.Bool(flagName, false, "")
		} else {
			exitAndError(fmt.Sprintf("Could not create flag for %s", fieldName))
		}
	}

	// Define our custom usage text
	flags.Usage = func() {
		fmt.Printf("%s\n", commandLineUsage)
	}

	// Search the args until we find a "--", which signifies the user has started
	// defining options.
	var argumentFlags []string
	started := false
	for i := 0; i < len(args); i++ {
		if strings.HasPrefix(args[i], "--") {
			started = true
		}

		if started {
			argumentFlags = append(argumentFlags, args[i])
		}
	}

	// Now parse the flags
	flags.Parse(argumentFlags)

	// Now the flag set has been populated with values, retrieve them and
	// set them (or use the ENV variable if empty)
	for i := 0; i < len(fields); i++ {
		fieldName := fields[i]
		fieldKind, _ := reflections.GetFieldKind(opts, fieldName)

		// Grab the flags we need
		flagName, _ := reflections.GetFieldTag(opts, fieldName, "flag")
		envName, _ := reflections.GetFieldTag(opts, fieldName, "env")
		required, _ := reflections.GetFieldTag(opts, fieldName, "required")

		// Grab the value from the flag
		value := flags.Lookup(flagName).Value.String()

		// If the value of the flag is empty, try the ENV
		if value == "" {
			value = os.Getenv(envName)
		}

		// Do validation
		if required == "true" && value == "" {
			exitAndError(fmt.Sprintf("missing %s", flagName))
		}

		// Set the value in the right way
		if fieldKind == reflect.String {
			reflections.SetField(opts, fieldName, value)
		} else if fieldKind == reflect.Bool {
			// The bool is converted to a string above
			if value == "true" {
				reflections.SetField(opts, fieldName, true)
			} else {
				reflections.SetField(opts, fieldName, false)
			}
		} else {
			exitAndError(fmt.Sprintf("Could not set value of %s", fieldName))
		}
	}
}
Exemple #8
0
// Loads the config from the CLI and config files that are present.
func (l *Loader) Load() error {
	// Try and find a config file, either passed in the command line using
	// --config, or in one of the default configuration file paths.
	if l.CLI.String("config") != "" {
		file := File{Path: l.CLI.String("config")}

		// Because this file was passed in manually, we should throw an error
		// if it doesn't exist.
		if file.Exists() {
			l.File = &file
		} else {
			return fmt.Errorf("A configuration file could not be found at: %s", file.AbsolutePath())
		}
	} else if len(l.DefaultConfigFilePaths) > 0 {
		for _, path := range l.DefaultConfigFilePaths {
			file := File{Path: path}

			// If the config file exists, save it to the loader and
			// don't bother checking the others.
			if file.Exists() {
				l.File = &file
				break
			}
		}
	}

	// If a file was found, then we should load it
	if l.File != nil {
		// Attempt to load the config file we've found
		if err := l.File.Load(); err != nil {
			return err
		}
	}

	// Now it's onto actually setting the fields. We start by getting all
	// the fields from the configuration interface
	var fields []string
	fields, _ = reflections.Fields(l.Config)

	// Loop through each of the fields, and look for tags and handle them
	// appropriately
	for _, fieldName := range fields {
		// Start by loading the value from the CLI context if the tag
		// exists
		cliName, _ := reflections.GetFieldTag(l.Config, fieldName, "cli")
		if cliName != "" {
			// Load the value from the CLI Context
			err := l.setFieldValueFromCLI(fieldName, cliName)
			if err != nil {
				return err
			}
		}

		// Are there any normalizations we need to make?
		normalization, _ := reflections.GetFieldTag(l.Config, fieldName, "normalize")
		if normalization != "" {
			// Apply the normalization
			err := l.normalizeField(fieldName, normalization)
			if err != nil {
				return err
			}
		}

		// Check for field deprecation
		deprecationError, _ := reflections.GetFieldTag(l.Config, fieldName, "deprecated")
		if deprecationError != "" {
			// If the deprecated field's value isn't emtpy, then we
			// return the deprecation error message.
			if !l.fieldValueIsEmpty(fieldName) {
				return fmt.Errorf(deprecationError)
			}
		}

		// Perform validations
		validationRules, _ := reflections.GetFieldTag(l.Config, fieldName, "validate")
		if validationRules != "" {
			// Determine the label for the field
			label, _ := reflections.GetFieldTag(l.Config, fieldName, "label")
			if label == "" {
				// Use the cli name if it exists, but if it
				// doesn't, just default to the structs field
				// name. Not great, but works!
				if cliName != "" {
					label = cliName
				} else {
					label = fieldName
				}
			}

			// Validate the fieid, and if it fails, return it's
			// error.
			err := l.validateField(fieldName, label, validationRules)
			if err != nil {
				return err
			}
		}
	}

	return nil
}
Exemple #9
0
func reflectField(fieldName string, target interface{}) (Field, error) {

	formTag, err := reflections.GetFieldTag(target, fieldName, "form")

	if err != nil {
		return nil, err
	}

	if formTag == "" {
		s, e := formTagFromField(fieldName, target)
		if e != nil || s == "" {
			return nil, e
		}
		formTag = s
	}

	if !validFieldType(fieldName, target, formTag) {
		return nil, fmt.Errorf("target field %s : %s", fieldName, formTag)
	}

	var message, choicesString string
	var choices []string

	message, err = reflections.GetFieldTag(target, fieldName, "message")

	if err != nil {
		return nil, err
	}

	if message == "" {
		message = fieldName
	}

	choicesString, err = reflections.GetFieldTag(target, fieldName, "choices")

	if err != nil {
		return nil, err
	}

	if choicesString != "" {
		choices = strings.Split(choicesString, ",")
		for i, c := range choices {
			choices[i] = strings.Trim(c, " ")
		}
	}

	var field Field
	switch formTag {
	case "input":
		field = &Input{
			Name:    fieldName,
			Message: message,
		}
	case "confirm":
		field = &Confirm{
			Name:    fieldName,
			Message: message,
		}
	case "password":
		field = &Password{
			Name:    fieldName,
			Message: message,
		}
	case "list":
		field = &List{
			Name:    fieldName,
			Message: message,
			Choices: choices,
		}
	case "checkbox":
		field = &Checkbox{
			Name:    fieldName,
			Message: message,
			Choices: choices,
		}
	}

	return field, nil

}