1package goini 2 3import ( 4 "path/filepath" 5 "errors" 6 "log" 7) 8 9// Suppress error if they are not otherwise used. 10var _ = log.Printf 11 12const ( 13 InheritedFrom = "inherited_from" // The key of the INI path which will be inherited from 14) 15 16// LoadInheritedINI loads an INI file which inherits from another INI 17// e.g: 18// The common.ini has contents: 19// project=common 20// ip=192.168.0.1 21// 22// And the project.ini has contents: 23// project=ppp 24// combo=ppp 25// inherited_from=common.ini 26// 27// The project.ini has the same configure as below : 28// project=ppp 29// combo=ppp 30// ip=192.168.0.1 31// 32func LoadInheritedINI(filename string) (*INI, error) { 33 ini := New() 34 err := ini.ParseFile(filename) 35 if err != nil { 36 return nil, err 37 } 38 39 inherited, ok := ini.Get(InheritedFrom) 40 if !ok { 41 return ini, nil 42 } 43 44 inherited = GetPathByRelativePath(filename, inherited) 45 inheritedINI, err := LoadInheritedINI(inherited) 46 if err != nil { 47 return nil, errors.New(err.Error() + " " + inherited) 48 } 49 50 ini.Merge(inheritedINI, false) 51 return ini, nil 52} 53 54// Merge merges the data in another INI (from) to this INI (ini), and 55// from INI will not be changed 56func (ini *INI) Merge(from *INI, override bool) { 57 for section, kv := range from.sections { 58 for key, value := range kv { 59 _, found := ini.SectionGet(section, key) 60 if override || !found { 61 ini.SectionSet(section, key, value) 62 } 63 } 64 } 65} 66 67// GetPathByRelativePath gets the real path according to the relative file path 68// e.g. : 69// relativeFilePath = /home/goini/conf/common.conf 70// inheritedPath = app.conf 71// 72// and then the GetPathByRelativePath(relativeFilePath, inheritedPath) will 73// return /home/goini/conf/app.conf 74func GetPathByRelativePath(relativeFilePath, inheritedPath string) string { 75 if filepath.IsAbs(inheritedPath) { 76 return inheritedPath 77 } 78 79 dir, _ := filepath.Split(relativeFilePath) 80 return filepath.Join(dir, inheritedPath) 81}