美文网首页beego
beego config模块源码分析笔记三

beego config模块源码分析笔记三

作者: ljh123 | 来源:发表于2018-12-27 07:40 被阅读0次

    ini.go源码文件分析

    这个文件里的代码是实现了解析ini配置文件,为开发者提供了两个结构体。
    ini知识
    1)type IniConfig struct
    2)type IniConfigContainer struct

    一、type IniConfig struct
    IniConfig实现Config来解析ini文件。

    type IniConfig struct {
    }
    

    对开发者不可见内容
    1)func (ini IniConfig) parseFile(name string) (IniConfigContainer, error)

    func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
        data, err := ioutil.ReadFile(name)
        if err != nil {
            return nil, err
        }
    
        return ini.parseData(filepath.Dir(name), data)
    }
    

    2)func (ini IniConfig) parseData(dir string, data []byte) (IniConfigContainer, error)
    协程安全

    func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, error) {
        cfg := &IniConfigContainer{
            data:           make(map[string]map[string]string),
            sectionComment: make(map[string]string),
            keyComment:     make(map[string]string),
            RWMutex:        sync.RWMutex{},
        }
        cfg.Lock()
        defer cfg.Unlock()
    
        var comment bytes.Buffer
        buf := bufio.NewReader(bytes.NewBuffer(data))
        // check the BOM
        head, err := buf.Peek(3)
            // 239=∩,187=╗,191=┐
        if err == nil && head[0] == 239 && head[1] == 187 && head[2] == 191 {
            for i := 1; i <= 3; i++ {
                buf.ReadByte()
            }
        }
        section := defaultSection
        tmpBuf := bytes.NewBuffer(nil)
        for {
            tmpBuf.Reset()
    
            shouldBreak := false
            for {
                tmp, isPrefix, err := buf.ReadLine()
                if err == io.EOF {
                    shouldBreak = true
                    break
                }
    
                //It might be a good idea to throw a error on all unknonw errors?
                if _, ok := err.(*os.PathError); ok {
                    return nil, err
                }
    
                tmpBuf.Write(tmp)
                if isPrefix {
                    continue
                }
    
                if !isPrefix {
                    break
                }
            }
            if shouldBreak {
                break
            }
    
            line := tmpBuf.Bytes()
            line = bytes.TrimSpace(line)
            if bytes.Equal(line, bEmpty) {
                continue
            }
            var bComment []byte
            switch {
            case bytes.HasPrefix(line, bNumComment):
                bComment = bNumComment
            case bytes.HasPrefix(line, bSemComment):
                bComment = bSemComment
            }
            if bComment != nil {
                line = bytes.TrimLeft(line, string(bComment))
                // Need append to a new line if multi-line comments.
                if comment.Len() > 0 {
                    comment.WriteByte('\n')
                }
                comment.Write(line)
                continue
            }
    
            if bytes.HasPrefix(line, sectionStart) && bytes.HasSuffix(line, sectionEnd) {
                section = strings.ToLower(string(line[1 : len(line)-1])) // section name case insensitive
                if comment.Len() > 0 {
                    cfg.sectionComment[section] = comment.String()
                    comment.Reset()
                }
                if _, ok := cfg.data[section]; !ok {
                    cfg.data[section] = make(map[string]string)
                }
                continue
            }
    
            if _, ok := cfg.data[section]; !ok {
                cfg.data[section] = make(map[string]string)
            }
            keyValue := bytes.SplitN(line, bEqual, 2)
    
            key := string(bytes.TrimSpace(keyValue[0])) // key name case insensitive
            key = strings.ToLower(key)
    
            // handle include "other.conf"
            if len(keyValue) == 1 && strings.HasPrefix(key, "include") {
    
                includefiles := strings.Fields(key)
                if includefiles[0] == "include" && len(includefiles) == 2 {
    
                    otherfile := strings.Trim(includefiles[1], "\"")
                    if !filepath.IsAbs(otherfile) {
                        otherfile = filepath.Join(dir, otherfile)
                    }
    
                    i, err := ini.parseFile(otherfile)
                    if err != nil {
                        return nil, err
                    }
    
                    for sec, dt := range i.data {
                        if _, ok := cfg.data[sec]; !ok {
                            cfg.data[sec] = make(map[string]string)
                        }
                        for k, v := range dt {
                            cfg.data[sec][k] = v
                        }
                    }
    
                    for sec, comm := range i.sectionComment {
                        cfg.sectionComment[sec] = comm
                    }
    
                    for k, comm := range i.keyComment {
                        cfg.keyComment[k] = comm
                    }
    
                    continue
                }
            }
    
            if len(keyValue) != 2 {
                return nil, errors.New("read the content error: \"" + string(line) + "\", should key = val")
            }
            val := bytes.TrimSpace(keyValue[1])
            if bytes.HasPrefix(val, bDQuote) {
                val = bytes.Trim(val, `"`)
            }
    
            cfg.data[section][key] = ExpandValueEnv(string(val))
            if comment.Len() > 0 {
                cfg.keyComment[section+"."+key] = comment.String()
                comment.Reset()
            }
    
        }
        return cfg, nil
    }
    

    对开发者可见内容
    1)
    二、type IniConfigContainer struct

    相关文章

      网友评论

        本文标题:beego config模块源码分析笔记三

        本文链接:https://www.haomeiwen.com/subject/cwvklqtx.html