ini

package
v3.0.0-rc49 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package ini implements a lossless reader and writer for the INI dialect used by the OpenSVC configuration files.

The parse tree keeps a reference to the source bytes each element was produced from. Elements left untouched are written back verbatim, so writing a document nobody modified reproduces the input byte for byte, comments, blank lines, alignment and multiline layout included. Only the elements actually modified are re-encoded.

This is what lets "config edit" round trip a configuration file through the daemon without reformatting it, and lets a value be replaced in place, as "config show --redact-secrets" needs.

Index

Constants

View Source
const (
	// DefaultSection is the name of the section holding the keys defined
	// before the first section header.
	DefaultSection = "DEFAULT"
)

Variables

This section is empty.

Functions

func Unquote

func Unquote(s string) string

Unquote strips the surrounding quote pair a value would be stripped of when read from a document, so a value given on a command line and the same value written in a document mean the same thing.

The pair is stripped only when the quote appears nowhere else in the value, which is the rule the parser follows.

Types

type File

type File struct {
	// Format tunes the encoding of the added and modified elements.
	Format Format
	// contains filtered or unexported fields
}

File is a parsed INI document.

The document is held as an ordered list of nodes, one per section header and one per key, each keeping the source bytes it was parsed from. Sections and keys are indexes over that list.

func Empty

func Empty(opts ...Options) *File

Empty returns an empty document.

func Load

func Load(opts Options, sources ...any) (*File, error)

Load parses the given sources into a single document.

A source is either a file path, as a string, or the document bytes, as a []byte. Sources are merged in order: a key redefined by a later source keeps its first position and takes the later value.

Writing back is byte-identical only when the document was loaded from a single source, which is the case of every document OpenSVC writes back.

func (*File) Bytes

func (f *File) Bytes() ([]byte, error)

Bytes returns the document encoding.

func (*File) DeleteSection

func (f *File) DeleteSection(name string)

DeleteSection removes the named section and all its keys.

func (*File) GetSection

func (f *File) GetSection(name string) (*Section, error)

GetSection returns the named section, or an error when it does not exist.

func (*File) HasSection

func (f *File) HasSection(name string) bool

HasSection reports whether the named section exists.

func (*File) MaterializeDefaultSection

func (f *File) MaterializeDefaultSection()

MaterializeDefaultSection gives the default section a header to encode when it has none, so the document is written with the "[DEFAULT]" line and the keys of the default section are visibly grouped under it.

The default section of a parsed document has no header when the source had none: the keys defined before the first section header are its keys, and the document is written back without a header it never had. Materializing the header inserts it at the head of the document, before those keys.

A document that already has a default section header is left untouched, and so is its byte-identical write back. The header is encoded only when Format.DefaultHeader is set, which it is by default.

func (*File) NewSection

func (f *File) NewSection(name string) (*Section, error)

NewSection returns the named section, creating it when it does not exist.

func (*File) Options

func (f *File) Options() Options

Options returns the syntax options the document was parsed with.

func (*File) Reload

func (f *File) Reload() error

Reload parses the sources again, dropping every uncommitted change.

func (*File) Section

func (f *File) Section(name string) *Section

Section returns the named section, creating it when it does not exist.

func (*File) SectionStrings

func (f *File) SectionStrings() []string

SectionStrings returns the section names, in document order.

func (*File) Sections

func (f *File) Sections() []*Section

Sections returns the sections, in document order.

func (*File) String

func (f *File) String() string

String returns the document encoding, empty when it can not be encoded.

func (*File) WriteTo

func (f *File) WriteTo(w io.Writer) (int64, error)

WriteTo writes the document.

The elements that were not modified since the parsing are written back verbatim, so writing a document nobody changed reproduces its source bytes exactly. The added and modified ones are encoded following f.Format.

type Format

type Format struct {
	// KeyValueDelimiter is written between a key name and its value,
	// surrounding spaces included. Defaults to " = ".
	KeyValueDelimiter string

	// LineBreak terminates a written line. Defaults to "\n".
	LineBreak string

	// DefaultHeader writes the default section header of a document
	// created empty. A parsed document is written back with the header
	// it had, or without one if it had none.
	DefaultHeader bool

	// BlankLineBeforeSection writes a blank line before an encoded
	// section header, so the sections of a document built from scratch
	// are separated. It writes none before the header heading the
	// document, and none where a blank line already stands.
	//
	// Like the rest of Format it only applies to an encoded header: a
	// section header written back from its source bytes keeps the blank
	// lines the source had, and no more.
	BlankLineBeforeSection bool
}

Format tunes the encoding of the elements that have no source bytes to be written back from: the ones added or modified since the parsing.

It has no effect on the untouched elements, which are always written back verbatim.

type Key

type Key struct {
	// contains filtered or unexported fields
}

Key is a name/value pair in a section.

func (*Key) Name

func (k *Key) Name() string

Name returns the key name.

func (*Key) Section

func (k *Key) Section() *Section

Section returns the section the key belongs to.

func (*Key) SetValue

func (k *Key) SetValue(value string)

SetValue sets the key value and drops the source formatting of the key line, which is encoded again on write. The comments preceding the key are kept.

func (*Key) SetValueKeepFormat

func (k *Key) SetValueKeepFormat(value string) bool

SetValueKeepFormat sets the key value by substituting it in the source text of the key line, so the key name, the spacing, the inline comment and the layout of a multiline value are all preserved. This is what a redaction needs: only the secret is replaced, the file is otherwise untouched.

It falls back to SetValue when the source text is unavailable, or when substituting would not parse back to value, and reports whether the formatting could be preserved.

func (*Key) String

func (k *Key) String() string

String returns the key value.

func (*Key) Value

func (k *Key) Value() string

Value returns the key value.

type Options

type Options struct {
	// Loose does not error out when a source file does not exist.
	Loose bool

	// AllowPythonMultilineValues continues a value on the following
	// lines when those lines begin with a space, a tab or a form feed.
	AllowPythonMultilineValues bool

	// SpaceBeforeInlineComment requires a whitespace before the '#' or
	// ';' introducing an inline comment. Without it, any '#' or ';' in a
	// value starts a comment.
	SpaceBeforeInlineComment bool

	// IgnoreInlineComment keeps the '#' and ';' markers and the text
	// following them in the value.
	IgnoreInlineComment bool

	// IgnoreContinuation does not join a line ending with a backslash
	// with the line that follows.
	IgnoreContinuation bool

	// KeyValueDelimiters lists the runes accepted as key/value separator
	// on read. Defaults to "=:".
	KeyValueDelimiters string

	// ChildSectionDelimiter separates a child section name from its
	// parent name. A key missing from a child section is looked up in
	// its parent. Defaults to ".".
	ChildSectionDelimiter string

	// DefaultSectionName is the name of the section holding the keys
	// defined before the first section header. Defaults to "DEFAULT".
	DefaultSectionName string
}

Options tunes the accepted syntax.

type Section

type Section struct {
	// contains filtered or unexported fields
}

Section is a named group of keys.

func (*Section) DeleteKey

func (s *Section) DeleteKey(name string)

DeleteKey removes the named key from the section.

func (*Section) GetKey

func (s *Section) GetKey(name string) (*Key, error)

GetKey returns the named key, or an error when it does not exist.

A key missing from a child section is looked up in its parent sections, the child section delimiter separating the names.

func (*Section) HasKey

func (s *Section) HasKey(name string) bool

HasKey reports whether the section, or one of its parent sections, has the named key.

func (*Section) Key

func (s *Section) Key(name string) *Key

Key returns the named key, creating an empty one when it does not exist.

func (*Section) KeyStrings

func (s *Section) KeyStrings() []string

KeyStrings returns the section key names, in document order.

func (*Section) Keys

func (s *Section) Keys() []*Key

Keys returns the section keys, in document order.

func (*Section) KeysHash

func (s *Section) KeysHash() map[string]string

KeysHash returns the section keys as a name to value map.

func (*Section) Name

func (s *Section) Name() string

Name returns the section name.

func (*Section) NewKey

func (s *Section) NewKey(name, value string) (*Key, error)

NewKey returns the named key with its value set, creating the key when it does not exist.

type Writer

type Writer = io.Writer

Writer is the interface WriteTo writes to.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL