package main import ( "flag" "fmt" "os" "reflect" "gopkg.in/yaml.v3" ) // Yaml struct of config type YamlConfig struct { Logger struct { File string `yaml:"file"` Level string `yaml:"level"` } Rest struct { Addr string `yaml:"addr"` Port uint16 `yaml:"port"` } Database struct { Type string `yaml:"type"` User string `yaml:"user"` Password string `yaml:"password"` Host string `yaml:"host"` Port string `yaml:"port"` Name string `yaml:"name"` } ParamFileDir string `yaml:"paramfiledir"` } var yamlConfig YamlConfig func ReadConfig(configFile string) { yamlFile, err := os.ReadFile(configFile) if err != nil { fmt.Printf("ioutil.ReadFile %s err %v", configFile, err) } // fmt.Println("yamlfile:", string(yamlFile)) err = yaml.Unmarshal(yamlFile, &yamlConfig) if err != nil { fmt.Printf("Unmarshal: %v when to struct", err) } } func GetYamlConfig() *YamlConfig { return &yamlConfig } //var mapYaml map[string]interface{} func ReadParamConfig(fileName string) *map[string]interface{} { file, err := os.ReadFile(fileName) if err != nil { fmt.Println("yamlFile.Get err", err) } mapYaml := make(map[string]interface{}) var node yaml.Node err = yaml.Unmarshal(file, &node) if err != nil { fmt.Printf("yaml.Unmarshal: %v when to struct", err) } err = unmarshalNode(&node, &mapYaml) if err != nil { fmt.Println("Failed to unmarshalNode:", err) } // var node yaml.Node // err = yaml.Unmarshal(file, &node) // if err != nil { // fmt.Printf("yaml.Unmarshal: %v when to struct", err) // } // err = unmarshalNode(&node, reflect.ValueOf(&mapYaml)) // if err != nil { // fmt.Println("Failed to unmarshalNode:", err) // } err = yaml.Unmarshal(file, &mapYaml) if err != nil { fmt.Printf("yaml.Unmarshal: %v when to struct", err) } // fmt.Println("mapYaml:", mapYaml) return &mapYaml } func GetAllFile(dir string, s []string) ([]string, error) { rd, err := os.ReadDir(dir) if err != nil { fmt.Println("read dir fail:", err) return s, err } for _, fi := range rd { if !fi.IsDir() { fullName := dir + "/" + fi.Name() s = append(s, fullName) } } return s, nil } const defaultConfigFile = "./loadpconf.yaml" var ( version string buildTime string goVer string ) var pfiles []string func init() { cfile := flag.String("c", defaultConfigFile, "config file") pfile := flag.String("p", "", "param file") pv := flag.Bool("v", false, "print version") ph := flag.Bool("h", false, "print help") flag.Parse() if *pv { fmt.Printf("OMC initems version: %s\n%s\n%s\n\n", version, buildTime, goVer) os.Exit(0) } if *ph { flag.Usage() os.Exit(0) } ReadConfig(*cfile) fmt.Println("pfile:", *pfile) if *pfile != "" { pfiles = append(pfiles, *pfile) } else { pfiles, _ = GetAllFile(yamlConfig.ParamFileDir, pfiles) } fmt.Println("pfiles:", pfiles) } func unmarshalNode(node *yaml.Node, out interface{}) error { switch node.Kind { case yaml.DocumentNode: return unmarshalNode(node.Content[0], out) case yaml.MappingNode: m := nodeToMap(node) return unmarshalMap(m, out) case yaml.SequenceNode: s := nodeToSlice(node) return unmarshalSlice(s, out) case yaml.ScalarNode: return unmarshalScalar(node, out) default: return fmt.Errorf("unknown node kind: %v", node.Kind) } } func nodeToMap(node *yaml.Node) map[string]*yaml.Node { m := make(map[string]*yaml.Node) for i := 0; i < len(node.Content); i += 2 { key := node.Content[i].Value value := node.Content[i+1] m[key] = value } return m } func unmarshalMap(m map[string]*yaml.Node, out interface{}) error { data, ok := out.(*map[string]interface{}) if !ok { return fmt.Errorf("out must be a map[string]interface{}") } *data = make(map[string]interface{}) for key, value := range m { var v interface{} err := unmarshalNode(value, &v) if err != nil { return err } (*data)[key] = v } return nil } func nodeToSlice(node *yaml.Node) []*yaml.Node { return node.Content } func unmarshalSlice(s []*yaml.Node, out interface{}) error { data, ok := out.(*[]interface{}) if !ok { return fmt.Errorf("out must be a []interface{}") } *data = make([]interface{}, len(s)) for i, value := range s { var v interface{} err := unmarshalNode(value, &v) if err != nil { return err } (*data)[i] = v } return nil } func unmarshalScalar(node *yaml.Node, out interface{}) error { switch node.Tag { case "!!str": val := reflect.ValueOf(node.Value) val.Elem().Set(reflect.ValueOf(out)) //*out = node.Value case "!!int": val := reflect.ValueOf(node.Value) val.Elem().Set(reflect.ValueOf(out)) //*out = node.Value case "!!float": val := reflect.ValueOf(node.Value) val.Elem().Set(reflect.ValueOf(out)) //*out = node.Value case "!!bool": val := reflect.ValueOf(node.Value == "true") val.Elem().Set(reflect.ValueOf(out)) //*out = node.Value == "true" case "!!null": val := reflect.ValueOf(node.Value) val.Elem().Set(reflect.ValueOf(out)) //*out = nil default: return fmt.Errorf("unknown scalar tag: %v", node.Tag) } return nil } /* func unmarshalNode(node *yaml.Node, out reflect.Value) error { switch node.Kind { case yaml.DocumentNode: return unmarshalNode(node.Content[0], out) case yaml.MappingNode: m := nodeToMap(node) return unmarshalMap(m, out) case yaml.SequenceNode: s := nodeToSlice(node) return unmarshalSlice(s, out) case yaml.ScalarNode: return unmarshalScalar(node, out) default: return fmt.Errorf("unknown node kind: %v", node.Kind) } } func nodeToMap(node *yaml.Node) map[string]*yaml.Node { m := make(map[string]*yaml.Node) for i := 0; i < len(node.Content); i += 2 { key := node.Content[i].Value value := node.Content[i+1] m[key] = value } return m } func unmarshalMap(m map[string]*yaml.Node, out reflect.Value) error { if out.Kind() != reflect.Ptr || out.IsNil() { return fmt.Errorf("out must be a non-nil pointer") } outType := out.Type().Elem() if outType.Kind() != reflect.Map { return fmt.Errorf("out must be a pointer to a map") } mapType := outType.Elem() if mapType.Kind() != reflect.Interface && mapType.Kind() != reflect.Map { return fmt.Errorf("out must be a pointer to a map of interface{}") } out.Set(reflect.MakeMap(outType)) for key, value := range m { var v reflect.Value if mapType.Kind() == reflect.Interface { v = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()) } else { v = reflect.New(mapType) } err := unmarshalNode(value, v.Elem()) if err != nil { return err } out.Elem().SetMapIndex(reflect.ValueOf(key), v.Elem()) } return nil } func nodeToSlice(node *yaml.Node) []*yaml.Node { return node.Content } func unmarshalSlice(s []*yaml.Node, out reflect.Value) error { if out.Kind() != reflect.Ptr || out.IsNil() { return fmt.Errorf("out must be a non-nil pointer") } outType := out.Type().Elem() if outType.Kind() != reflect.Slice { return fmt.Errorf("out must be a pointer to a slice") } sliceType := outType.Elem() if sliceType.Kind() != reflect.Interface && sliceType.Kind() != reflect.Slice { return fmt.Errorf("out must be a pointer to a slice of interface{}") } out.Set(reflect.MakeSlice(outType, len(s), len(s))) for i, value := range s { var v reflect.Value if sliceType.Kind() == reflect.Interface { v = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()) } else { v = reflect.New(sliceType) } err := unmarshalNode(value, v.Elem()) if err != nil { return err } out.Elem().Index(i).Set(v.Elem()) } return nil } func unmarshalScalar(node *yaml.Node, out reflect.Value) error { switch node.Tag { case "!!str": out.SetString(node.Value) case "!!int": i, err := strconv.ParseInt(node.Value, 10, 64) if err != nil { return err } out.SetInt(i) case "!!float": f, err := strconv.ParseFloat(node.Value, 64) if err != nil { return err } out.SetFloat(f) case "!!bool": b, err := strconv.ParseBool(node.Value) if err != nil { return err } out.SetBool(b) case "!!null": out.Set(reflect.Zero(out.Type())) default: return fmt.Errorf("unknown scalar tag: %v", node.Tag) } return nil } */