vendor/gopkg.in/ini.v1/file.go
changeset 256 6d9efbef00a9
parent 251 1c52a0eeb952
child 260 445e01aede7e
equal deleted inserted replaced
255:4f153a23adab 256:6d9efbef00a9
    23 	"os"
    23 	"os"
    24 	"strings"
    24 	"strings"
    25 	"sync"
    25 	"sync"
    26 )
    26 )
    27 
    27 
    28 // File represents a combination of a or more INI file(s) in memory.
    28 // File represents a combination of one or more INI files in memory.
    29 type File struct {
    29 type File struct {
    30 	options     LoadOptions
    30 	options     LoadOptions
    31 	dataSources []dataSource
    31 	dataSources []dataSource
    32 
    32 
    33 	// Should make things safe, but sometimes doesn't matter.
    33 	// Should make things safe, but sometimes doesn't matter.
    34 	BlockMode bool
    34 	BlockMode bool
    35 	lock      sync.RWMutex
    35 	lock      sync.RWMutex
    36 
    36 
    37 	// To keep data in order.
    37 	// To keep data in order.
    38 	sectionList []string
    38 	sectionList []string
       
    39 	// To keep track of the index of a section with same name.
       
    40 	// This meta list is only used with non-unique section names are allowed.
       
    41 	sectionIndexes []int
       
    42 
    39 	// Actual data is stored here.
    43 	// Actual data is stored here.
    40 	sections map[string]*Section
    44 	sections map[string][]*Section
    41 
    45 
    42 	NameMapper
    46 	NameMapper
    43 	ValueMapper
    47 	ValueMapper
    44 }
    48 }
    45 
    49 
    46 // newFile initializes File object with given data sources.
    50 // newFile initializes File object with given data sources.
    47 func newFile(dataSources []dataSource, opts LoadOptions) *File {
    51 func newFile(dataSources []dataSource, opts LoadOptions) *File {
    48 	if len(opts.KeyValueDelimiters) == 0 {
    52 	if len(opts.KeyValueDelimiters) == 0 {
    49 		opts.KeyValueDelimiters = "=:"
    53 		opts.KeyValueDelimiters = "=:"
    50 	}
    54 	}
       
    55 	if len(opts.KeyValueDelimiterOnWrite) == 0 {
       
    56 		opts.KeyValueDelimiterOnWrite = "="
       
    57 	}
       
    58 	if len(opts.ChildSectionDelimiter) == 0 {
       
    59 		opts.ChildSectionDelimiter = "."
       
    60 	}
       
    61 
    51 	return &File{
    62 	return &File{
    52 		BlockMode:   true,
    63 		BlockMode:   true,
    53 		dataSources: dataSources,
    64 		dataSources: dataSources,
    54 		sections:    make(map[string]*Section),
    65 		sections:    make(map[string][]*Section),
    55 		sectionList: make([]string, 0, 10),
       
    56 		options:     opts,
    66 		options:     opts,
    57 	}
    67 	}
    58 }
    68 }
    59 
    69 
    60 // Empty returns an empty file object.
    70 // Empty returns an empty file object.
    61 func Empty() *File {
    71 func Empty(opts ...LoadOptions) *File {
    62 	// Ignore error here, we sure our data is good.
    72 	var opt LoadOptions
    63 	f, _ := Load([]byte(""))
    73 	if len(opts) > 0 {
       
    74 		opt = opts[0]
       
    75 	}
       
    76 
       
    77 	// Ignore error here, we are sure our data is good.
       
    78 	f, _ := LoadSources(opt, []byte(""))
    64 	return f
    79 	return f
    65 }
    80 }
    66 
    81 
    67 // NewSection creates a new section.
    82 // NewSection creates a new section.
    68 func (f *File) NewSection(name string) (*Section, error) {
    83 func (f *File) NewSection(name string) (*Section, error) {
    69 	if len(name) == 0 {
    84 	if len(name) == 0 {
    70 		return nil, errors.New("error creating new section: empty section name")
    85 		return nil, errors.New("empty section name")
    71 	} else if f.options.Insensitive && name != DefaultSection {
    86 	}
       
    87 
       
    88 	if (f.options.Insensitive || f.options.InsensitiveSections) && name != DefaultSection {
    72 		name = strings.ToLower(name)
    89 		name = strings.ToLower(name)
    73 	}
    90 	}
    74 
    91 
    75 	if f.BlockMode {
    92 	if f.BlockMode {
    76 		f.lock.Lock()
    93 		f.lock.Lock()
    77 		defer f.lock.Unlock()
    94 		defer f.lock.Unlock()
    78 	}
    95 	}
    79 
    96 
    80 	if inSlice(name, f.sectionList) {
    97 	if !f.options.AllowNonUniqueSections && inSlice(name, f.sectionList) {
    81 		return f.sections[name], nil
    98 		return f.sections[name][0], nil
    82 	}
    99 	}
    83 
   100 
    84 	f.sectionList = append(f.sectionList, name)
   101 	f.sectionList = append(f.sectionList, name)
    85 	f.sections[name] = newSection(f, name)
   102 
    86 	return f.sections[name], nil
   103 	// NOTE: Append to indexes must happen before appending to sections,
       
   104 	// otherwise index will have off-by-one problem.
       
   105 	f.sectionIndexes = append(f.sectionIndexes, len(f.sections[name]))
       
   106 
       
   107 	sec := newSection(f, name)
       
   108 	f.sections[name] = append(f.sections[name], sec)
       
   109 
       
   110 	return sec, nil
    87 }
   111 }
    88 
   112 
    89 // NewRawSection creates a new section with an unparseable body.
   113 // NewRawSection creates a new section with an unparseable body.
    90 func (f *File) NewRawSection(name, body string) (*Section, error) {
   114 func (f *File) NewRawSection(name, body string) (*Section, error) {
    91 	section, err := f.NewSection(name)
   115 	section, err := f.NewSection(name)
   108 	return nil
   132 	return nil
   109 }
   133 }
   110 
   134 
   111 // GetSection returns section by given name.
   135 // GetSection returns section by given name.
   112 func (f *File) GetSection(name string) (*Section, error) {
   136 func (f *File) GetSection(name string) (*Section, error) {
       
   137 	secs, err := f.SectionsByName(name)
       
   138 	if err != nil {
       
   139 		return nil, err
       
   140 	}
       
   141 
       
   142 	return secs[0], err
       
   143 }
       
   144 
       
   145 // SectionsByName returns all sections with given name.
       
   146 func (f *File) SectionsByName(name string) ([]*Section, error) {
   113 	if len(name) == 0 {
   147 	if len(name) == 0 {
   114 		name = DefaultSection
   148 		name = DefaultSection
   115 	}
   149 	}
   116 	if f.options.Insensitive {
   150 	if f.options.Insensitive || f.options.InsensitiveSections {
   117 		name = strings.ToLower(name)
   151 		name = strings.ToLower(name)
   118 	}
   152 	}
   119 
   153 
   120 	if f.BlockMode {
   154 	if f.BlockMode {
   121 		f.lock.RLock()
   155 		f.lock.RLock()
   122 		defer f.lock.RUnlock()
   156 		defer f.lock.RUnlock()
   123 	}
   157 	}
   124 
   158 
   125 	sec := f.sections[name]
   159 	secs := f.sections[name]
   126 	if sec == nil {
   160 	if len(secs) == 0 {
   127 		return nil, fmt.Errorf("section '%s' does not exist", name)
   161 		return nil, fmt.Errorf("section %q does not exist", name)
   128 	}
   162 	}
   129 	return sec, nil
   163 
       
   164 	return secs, nil
   130 }
   165 }
   131 
   166 
   132 // Section assumes named section exists and returns a zero-value when not.
   167 // Section assumes named section exists and returns a zero-value when not.
   133 func (f *File) Section(name string) *Section {
   168 func (f *File) Section(name string) *Section {
   134 	sec, err := f.GetSection(name)
   169 	sec, err := f.GetSection(name)
   137 		// but if it's empty, this piece of code won't be executed.
   172 		// but if it's empty, this piece of code won't be executed.
   138 		sec, _ = f.NewSection(name)
   173 		sec, _ = f.NewSection(name)
   139 		return sec
   174 		return sec
   140 	}
   175 	}
   141 	return sec
   176 	return sec
       
   177 }
       
   178 
       
   179 // SectionWithIndex assumes named section exists and returns a new section when not.
       
   180 func (f *File) SectionWithIndex(name string, index int) *Section {
       
   181 	secs, err := f.SectionsByName(name)
       
   182 	if err != nil || len(secs) <= index {
       
   183 		// NOTE: It's OK here because the only possible error is empty section name,
       
   184 		// but if it's empty, this piece of code won't be executed.
       
   185 		newSec, _ := f.NewSection(name)
       
   186 		return newSec
       
   187 	}
       
   188 
       
   189 	return secs[index]
   142 }
   190 }
   143 
   191 
   144 // Sections returns a list of Section stored in the current instance.
   192 // Sections returns a list of Section stored in the current instance.
   145 func (f *File) Sections() []*Section {
   193 func (f *File) Sections() []*Section {
   146 	if f.BlockMode {
   194 	if f.BlockMode {
   148 		defer f.lock.RUnlock()
   196 		defer f.lock.RUnlock()
   149 	}
   197 	}
   150 
   198 
   151 	sections := make([]*Section, len(f.sectionList))
   199 	sections := make([]*Section, len(f.sectionList))
   152 	for i, name := range f.sectionList {
   200 	for i, name := range f.sectionList {
   153 		sections[i] = f.sections[name]
   201 		sections[i] = f.sections[name][f.sectionIndexes[i]]
   154 	}
   202 	}
   155 	return sections
   203 	return sections
   156 }
   204 }
   157 
   205 
   158 // ChildSections returns a list of child sections of given section name.
   206 // ChildSections returns a list of child sections of given section name.
   165 	list := make([]string, len(f.sectionList))
   213 	list := make([]string, len(f.sectionList))
   166 	copy(list, f.sectionList)
   214 	copy(list, f.sectionList)
   167 	return list
   215 	return list
   168 }
   216 }
   169 
   217 
   170 // DeleteSection deletes a section.
   218 // DeleteSection deletes a section or all sections with given name.
   171 func (f *File) DeleteSection(name string) {
   219 func (f *File) DeleteSection(name string) {
       
   220 	secs, err := f.SectionsByName(name)
       
   221 	if err != nil {
       
   222 		return
       
   223 	}
       
   224 
       
   225 	for i := 0; i < len(secs); i++ {
       
   226 		// For non-unique sections, it is always needed to remove the first one so
       
   227 		// in the next iteration, the subsequent section continue having index 0.
       
   228 		// Ignoring the error as index 0 never returns an error.
       
   229 		_ = f.DeleteSectionWithIndex(name, 0)
       
   230 	}
       
   231 }
       
   232 
       
   233 // DeleteSectionWithIndex deletes a section with given name and index.
       
   234 func (f *File) DeleteSectionWithIndex(name string, index int) error {
       
   235 	if !f.options.AllowNonUniqueSections && index != 0 {
       
   236 		return fmt.Errorf("delete section with non-zero index is only allowed when non-unique sections is enabled")
       
   237 	}
       
   238 
       
   239 	if len(name) == 0 {
       
   240 		name = DefaultSection
       
   241 	}
       
   242 	if f.options.Insensitive || f.options.InsensitiveSections {
       
   243 		name = strings.ToLower(name)
       
   244 	}
       
   245 
   172 	if f.BlockMode {
   246 	if f.BlockMode {
   173 		f.lock.Lock()
   247 		f.lock.Lock()
   174 		defer f.lock.Unlock()
   248 		defer f.lock.Unlock()
   175 	}
   249 	}
   176 
   250 
   177 	if len(name) == 0 {
   251 	// Count occurrences of the sections
   178 		name = DefaultSection
   252 	occurrences := 0
   179 	}
   253 
   180 
   254 	sectionListCopy := make([]string, len(f.sectionList))
   181 	for i, s := range f.sectionList {
   255 	copy(sectionListCopy, f.sectionList)
   182 		if s == name {
   256 
       
   257 	for i, s := range sectionListCopy {
       
   258 		if s != name {
       
   259 			continue
       
   260 		}
       
   261 
       
   262 		if occurrences == index {
       
   263 			if len(f.sections[name]) <= 1 {
       
   264 				delete(f.sections, name) // The last one in the map
       
   265 			} else {
       
   266 				f.sections[name] = append(f.sections[name][:index], f.sections[name][index+1:]...)
       
   267 			}
       
   268 
       
   269 			// Fix section lists
   183 			f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...)
   270 			f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...)
   184 			delete(f.sections, name)
   271 			f.sectionIndexes = append(f.sectionIndexes[:i], f.sectionIndexes[i+1:]...)
   185 			return
   272 
   186 		}
   273 		} else if occurrences > index {
   187 	}
   274 			// Fix the indices of all following sections with this name.
       
   275 			f.sectionIndexes[i-1]--
       
   276 		}
       
   277 
       
   278 		occurrences++
       
   279 	}
       
   280 
       
   281 	return nil
   188 }
   282 }
   189 
   283 
   190 func (f *File) reload(s dataSource) error {
   284 func (f *File) reload(s dataSource) error {
   191 	r, err := s.ReadCloser()
   285 	r, err := s.ReadCloser()
   192 	if err != nil {
   286 	if err != nil {
   201 func (f *File) Reload() (err error) {
   295 func (f *File) Reload() (err error) {
   202 	for _, s := range f.dataSources {
   296 	for _, s := range f.dataSources {
   203 		if err = f.reload(s); err != nil {
   297 		if err = f.reload(s); err != nil {
   204 			// In loose mode, we create an empty default section for nonexistent files.
   298 			// In loose mode, we create an empty default section for nonexistent files.
   205 			if os.IsNotExist(err) && f.options.Loose {
   299 			if os.IsNotExist(err) && f.options.Loose {
   206 				f.parse(bytes.NewBuffer(nil))
   300 				_ = f.parse(bytes.NewBuffer(nil))
   207 				continue
   301 				continue
   208 			}
   302 			}
   209 			return err
   303 			return err
       
   304 		}
       
   305 		if f.options.ShortCircuit {
       
   306 			return nil
   210 		}
   307 		}
   211 	}
   308 	}
   212 	return nil
   309 	return nil
   213 }
   310 }
   214 
   311 
   228 	}
   325 	}
   229 	return f.Reload()
   326 	return f.Reload()
   230 }
   327 }
   231 
   328 
   232 func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
   329 func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
   233 	equalSign := DefaultFormatLeft + "=" + DefaultFormatRight
   330 	equalSign := DefaultFormatLeft + f.options.KeyValueDelimiterOnWrite + DefaultFormatRight
   234 
   331 
   235 	if PrettyFormat || PrettyEqual {
   332 	if PrettyFormat || PrettyEqual {
   236 		equalSign = " = "
   333 		equalSign = fmt.Sprintf(" %s ", f.options.KeyValueDelimiterOnWrite)
   237 	}
   334 	}
   238 
   335 
   239 	// Use buffer to make sure target is safe until finish encoding.
   336 	// Use buffer to make sure target is safe until finish encoding.
   240 	buf := bytes.NewBuffer(nil)
   337 	buf := bytes.NewBuffer(nil)
   241 	for i, sname := range f.sectionList {
   338 	for i, sname := range f.sectionList {
   242 		sec := f.Section(sname)
   339 		sec := f.SectionWithIndex(sname, f.sectionIndexes[i])
   243 		if len(sec.Comment) > 0 {
   340 		if len(sec.Comment) > 0 {
   244 			// Support multiline comments
   341 			// Support multiline comments
   245 			lines := strings.Split(sec.Comment, LineBreak)
   342 			lines := strings.Split(sec.Comment, LineBreak)
   246 			for i := range lines {
   343 			for i := range lines {
   247 				if lines[i][0] != '#' && lines[i][0] != ';' {
   344 				if lines[i][0] != '#' && lines[i][0] != ';' {
   254 					return nil, err
   351 					return nil, err
   255 				}
   352 				}
   256 			}
   353 			}
   257 		}
   354 		}
   258 
   355 
   259 		if i > 0 || DefaultHeader {
   356 		if i > 0 || DefaultHeader || (i == 0 && strings.ToUpper(sec.name) != DefaultSection) {
   260 			if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
   357 			if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
   261 				return nil, err
   358 				return nil, err
   262 			}
   359 			}
   263 		} else {
   360 		} else {
   264 			// Write nothing if default section is empty
   361 			// Write nothing if default section is empty
   280 			}
   377 			}
   281 			continue
   378 			continue
   282 		}
   379 		}
   283 
   380 
   284 		// Count and generate alignment length and buffer spaces using the
   381 		// Count and generate alignment length and buffer spaces using the
   285 		// longest key. Keys may be modifed if they contain certain characters so
   382 		// longest key. Keys may be modified if they contain certain characters so
   286 		// we need to take that into account in our calculation.
   383 		// we need to take that into account in our calculation.
   287 		alignLength := 0
   384 		alignLength := 0
   288 		if PrettyFormat {
   385 		if PrettyFormat {
   289 			for _, kname := range sec.keyList {
   386 			for _, kname := range sec.keyList {
   290 				keyLength := len(kname)
   387 				keyLength := len(kname)
   358 				// In case key value contains "\n", "`", "\"", "#" or ";"
   455 				// In case key value contains "\n", "`", "\"", "#" or ";"
   359 				if strings.ContainsAny(val, "\n`") {
   456 				if strings.ContainsAny(val, "\n`") {
   360 					val = `"""` + val + `"""`
   457 					val = `"""` + val + `"""`
   361 				} else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") {
   458 				} else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") {
   362 					val = "`" + val + "`"
   459 					val = "`" + val + "`"
       
   460 				} else if len(strings.TrimSpace(val)) != len(val) {
       
   461 					val = `"` + val + `"`
   363 				}
   462 				}
   364 				if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil {
   463 				if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil {
   365 					return nil, err
   464 					return nil, err
   366 				}
   465 				}
   367 			}
   466 			}
   401 }
   500 }
   402 
   501 
   403 // SaveToIndent writes content to file system with given value indention.
   502 // SaveToIndent writes content to file system with given value indention.
   404 func (f *File) SaveToIndent(filename, indent string) error {
   503 func (f *File) SaveToIndent(filename, indent string) error {
   405 	// Note: Because we are truncating with os.Create,
   504 	// Note: Because we are truncating with os.Create,
   406 	// 	so it's safer to save to a temporary file location and rename afte done.
   505 	// 	so it's safer to save to a temporary file location and rename after done.
   407 	buf, err := f.writeToBuffer(indent)
   506 	buf, err := f.writeToBuffer(indent)
   408 	if err != nil {
   507 	if err != nil {
   409 		return err
   508 		return err
   410 	}
   509 	}
   411 
   510