func readSetting()

in newt/syscfg/syscfg.go [445:572]


func readSetting(name string, lpkg *pkg.LocalPackage,
	vals map[interface{}]interface{}) (CfgEntry, error) {

	entry := CfgEntry{}

	entry.Name = name
	entry.PackageDef = lpkg
	entry.Description = stringValue(vals["description"])

	if boolValue(vals["defunct"]) {
		entry.State = CFG_SETTING_STATE_DEFUNCT
	} else if boolValue(vals["deprecated"]) {
		entry.State = CFG_SETTING_STATE_DEPRECATED
	} else if boolValue(vals["experimental"]) {
		entry.State = CFG_SETTING_STATE_EXPERIMENTAL
	} else {
		entry.State = CFG_SETTING_STATE_GOOD
	}

	stateVal, stateExist := vals["state"]
	if stateExist {
		if entry.State != CFG_SETTING_STATE_GOOD {
			util.OneTimeWarning("Setting %s has duplicated state definition, using \"state\".", name)
		}

		switch stringValue(stateVal) {
		case "defunct":
			entry.State = CFG_SETTING_STATE_DEFUNCT
		case "deprecated":
			entry.State = CFG_SETTING_STATE_DEPRECATED
		case "experimental":
			entry.State = CFG_SETTING_STATE_EXPERIMENTAL
		default:
			util.OneTimeWarning("Invalid \"state\" for setting %s, assuming regular state.", name)
		}
	}

	// The value field for setting definition is required.
	valueVal, valueExist := vals["value"]
	if valueExist {
		entry.Value = stringValue(valueVal)
	} else if entry.State == CFG_SETTING_STATE_DEFUNCT {
		// defunct settings do not need default value, we only care if
		// value was set anywhere and emit an error then
		entry.Value = ""
	} else {
		return entry, util.FmtNewtError(
			"setting %s does not have required value field", name)
	}

	if vals["type"] == nil {
		entry.SettingType = CFG_SETTING_TYPE_RAW
	} else {
		var ok bool
		typename := stringValue(vals["type"])
		entry.SettingType, ok = cfgSettingNameTypeMap[typename]
		if !ok {
			return entry, util.FmtNewtError(
				"setting %s specifies invalid type: %s", name, typename)
		}
	}
	entry.appendValue(lpkg, entry.Value)

	entry.Restrictions = []CfgRestriction{}
	restrictionStrings := cast.ToStringSlice(vals["restrictions"])
	for _, rstring := range restrictionStrings {
		r, err := readRestriction(name, rstring)
		if err != nil {
			return entry,
				util.PreNewtError(err, "error parsing setting %s", name)
		}
		entry.Restrictions = append(entry.Restrictions, r)
	}

	if vals["choices"] != nil && vals["range"] != nil {
		return entry, util.FmtNewtError(
			"setting %s uses both choice and range restrictions", name)
	}

	if vals["choices"] != nil {
		var choices []string
		switch vals["choices"].(type) {
		default:
			choices = cast.ToStringSlice(vals["choices"])
		case string:
			choices = strings.Split(vals["choices"].(string), ",")
		}

		entry.ValidChoices = choices

		sort.Slice(choices, func(a, b int) bool {
			return strings.ToLower(choices[a]) < strings.ToLower(choices[b])
		})

		for i, choice := range choices {
			if !cfgChoiceValRe.MatchString(choice) {
				return entry, util.FmtNewtError(
					"setting %s has invalid choice defined (%s) - "+
						"only letters, numbers and underscore are allowed", name, choice)
			}

			if i > 0 && strings.ToLower(choices[i-1]) == strings.ToLower(choice) {
				return entry, util.FmtNewtError(
					"setting %s has duplicated choice defined ('%s' and '%s')",
					name, choice, choices[i-1])
			}
		}

		r := CfgRestriction{
			BaseSetting: name,
			Code:        CFG_RESTRICTION_CODE_CHOICE,
		}

		entry.Restrictions = append(entry.Restrictions, r)
	}

	if vals["range"] != nil {
		r, err := createRangeRestriction(name, stringValue(vals["range"]))
		if err != nil {
			return entry,
				util.PreNewtError(err, "error parsing setting %s", name)
		}

		entry.Restrictions = append(entry.Restrictions, r)
	}

	return entry, nil
}