ini

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2019 License: BSD-3-Clause Imports: 10 Imported by: 7

Documentation

Overview

Package ini implement reading and writing INI configuration as defined by Git configuration file syntax.

Features

* Reading and writing on the same file should not change the content of file (including comment).

* Template friendly, through Val(), Vals(), and Subs().

Unsupported Features

Git `include` and `includeIf` directives.

Syntax

S.1.0. The `#` and `;` characters begin comments to the end of line.

S.1.1. Blank lines are ignored.

## Section

S.2.0. A section begins with the name of the section in square brackets.

S.2.1. A section continues until the next section begins.

S.2.2. Section name are case-insensitive.

S.2.3. Variable name must start with an alphabetic character, no whitespace before name or after '['.

S.2.4. Section name only allow alphanumeric characters, `-` and `.`.

S.2.5. Section can be further divided into subsections.

S.2.6. Section headers cannot span multiple lines.

S.2.7. You can have `[section]` if you have `[section "subsection"]`, but you don’t need to.

S.2.8. All the other lines (and the remainder of the line after the section header) are recognized as setting variables, in the form `name = value`.

## SubSection

S.3.0. To begin a subsection put its name in double quotes, separated by space from the section name, in the section header, for example

[section "subsection"]

S.3.1. Subsection name are case sensitive and can contain any characters except newline and the null byte.

S.3.2. Subsection name can include doublequote `"` and backslash by escaping them as `\"` and `\\`, respectively.

S.3.3. Other backslashes preceding other characters are dropped when reading subsection name; for example, `\t` is read as `t` and `\0` is read as `0`.

## Variable

S.4.0. Variable must belong to some section, which means that there must be a section header before the first setting of a variable.

S.4.1. Variable name are case-insensitive.

S.4.2. Variable name allow only alphanumeric characters and `-`.

S.4.3. Variable name must start with an alphabetic character.

S.4.4. Variable name without value is a short-hand to set the value to the boolean "true" value, e.g.

[section]
	thisistrue # equal to thisistrue=true

## Value

S.5.0. Value can be empty or not set, see S.4.4.

S.5.1. Internal whitespaces within the value are retained verbatim.

S.5.2. Value can be continued to the next line by ending it with a `\`; the backquote and the end-of-line are stripped.

S.5.3. Leading and trailing.whitespaces on value without double quote will be discarded.

S.5.4. Value can contain inline comment, e.g.

key = value # this is inline comment

S.5.5. Comment characters, '#' and ';', inside double quoted value will be read as content of value, not as comment,

key = "value # with hash"

S.5.6. Inside value enclosed double quotes, the following escape sequences are recognized: `\"` for doublequote, `\\` for backslash, `\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB) and `\b` for backspace (BS).

S.5.7. Other char escape sequences (including octal escape sequences) are invalid.

Extensions

## Variable

E.4.0. Allow dot ('.') and underscore ('_') characters on variable name.

References

https://git-scm.com/docs/git-config#_configuration_file

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsValueBoolTrue

func IsValueBoolTrue(v string) bool

IsValueBoolTrue will return true if variable contains boolean value for true. The following conditions is boolean true for value: "" (empty string), "true", "yes", "ya", "t", "1" (all of string is case insensitive).

Types

type Ini

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

Ini contains the parsed file.

func Open

func Open(filename string) (in *Ini, err error)

Open and parse INI formatted file.

On fail it will return incomplete instance of Ini with error.

func Parse

func Parse(text []byte) (in *Ini, err error)

Parse INI format from text.

func (*Ini) Add added in v0.7.0

func (in *Ini) Add(secName, subName, key, value string) bool

Add the new key and value to the last item in section and/or subsection.

If section or subsection is not exist it will create a new one. If section or key is empty, or value already exist it will not modify the INI object.

It will return true if new variable is added, otherwise it will return false.

Example
ini := new(Ini)

ini.Add("", "", "k1", "v1")
ini.Add("s1", "", "", "v2")

ini.Add("s1", "", "k1", "")
ini.Add("s1", "", "k1", "v1")
ini.Add("s1", "", "k1", "v2")
ini.Add("s1", "", "k1", "v1")

ini.Add("s1", "sub", "k1", "v1")
ini.Add("s1", "sub", "k1", "v1")

ini.Add("s2", "sub", "k1", "v1")

err := ini.Write(os.Stdout)
if err != nil {
	log.Fatal(err)
}
Output:

[s1]
k1 = true
k1 = v1
k1 = v2

[s1 "sub"]
k1 = v1

[s2 "sub"]
k1 = v1

func (*Ini) AsMap added in v0.7.0

func (in *Ini) AsMap(sectionName, subName string) (out map[string][]string)

AsMap return the INI contents as mapping of (section-name ":" subsection-name ":" variable-name) as key and the variable's values as slice of string.

If section name is not empty, only the keys will be listed in the map.

Example
input := []byte(`
[section]
key=value1
key2=

[section "sub"]
key=value1
key2=

[section]
key=value2
key2=false

[section "sub"]
key=value2
key=value3
`)

inis, err := Parse(input)
if err != nil {
	log.Fatal(err)
}

iniMap := inis.AsMap("", "")

for k, v := range iniMap {
	fmt.Println(k, "=", v)
}

iniMap = inis.AsMap("section", "sub")

fmt.Println()
for k, v := range iniMap {
	fmt.Println(k, "=", v)
}
Output:

section::key = [value1 value2]
section::key2 = [true false]
section:sub:key = [value1 value2 value3]
section:sub:key2 = [true]

key = [value1 value2 value3]
key2 = [true]

func (*Ini) Get

func (in *Ini) Get(secName, subName, key, def string) (val string, ok bool)

Get the last key on section and/or subsection.

If key found it will return its value and true; otherwise it will return default value in def and false.

func (*Ini) GetBool

func (in *Ini) GetBool(secName, subName, key string, def bool) bool

GetBool return key's value as boolean. If no key found it will return default value.

func (*Ini) Gets added in v0.7.0

func (in *Ini) Gets(secName, subName, key string) (out []string)

Gets key's values as slice of string in the same section and subsection.

Example
input := []byte(`
[section]
key=value1

[section "sub"]
key=value2

[section]
key=value3

[section "sub"]
key=value4
key=value2
`)

inis, _ := Parse(input)

fmt.Println(inis.Gets("section", "", "key"))
fmt.Println(inis.Gets("section", "sub", "key"))
Output:

[value1 value3]
[value2 value4]

func (*Ini) Prune added in v0.7.0

func (in *Ini) Prune()

Prune remove all empty lines, comments, and merge all section and subsection with the same name into one group.

Example
input := []byte(`
[section]
key=value1 # comment
key2= ; another comment

[section "sub"]
key=value1

; here is comment on section
[section]
key=value2
key2=false

[section "sub"]
key=value2
key=value1
`)

in, err := Parse(input)
if err != nil {
	log.Fatal(err)
}

in.Prune()

err = in.Write(os.Stdout)
if err != nil {
	log.Fatal(err)
}
Output:

[section]
key = value1
key2 = true
key = value2
key2 = false

[section "sub"]
key = value2
key = value1

func (*Ini) Rebase added in v0.7.0

func (in *Ini) Rebase(other *Ini)

Rebase merge the other INI sections into this INI sections.

Example
input := []byte(`
		[section]
		key=value1
		key2=

		[section "sub"]
		key=value1
`)

other := []byte(`
		[section]
		key=value2
		key2=false

		[section "sub"]
		key=value2
		key=value1
`)

in, err := Parse(input)
if err != nil {
	log.Fatal(err)
}

in2, err := Parse(other)
if err != nil {
	log.Fatal(err)
}

in.Prune()
in2.Prune()

in.Rebase(in2)

err = in.Write(os.Stdout)
if err != nil {
	log.Fatal(err)
}
Output:

[section]
key = value1
key2 = true
key = value2
key2 = false

[section "sub"]
key = value2
key = value1

func (*Ini) Save

func (in *Ini) Save(filename string) (err error)

Save the current parsed Ini into file `filename`. It will overwrite the destination file if it's exist.

func (*Ini) Section added in v0.7.0

func (in *Ini) Section(secName, subName string) (sec *Section)

Section given section and/or subsection name, return the Section object that match with it. If section name is empty, it will return nil. If ini contains duplicate section (or subsection) it will merge all of its variables into one section.

Example
input := []byte(`
[section]
key=value1 # comment
key2= ; another comment

[section "sub"]
key=value1

[section] ; here is comment on section
key=value2
key2=false

[section "sub"]
key=value2
key=value1
`)

ini, err := Parse(input)
if err != nil {
	log.Fatal(err)
}

sec := ini.Section("section", "")
for _, v := range sec.vars {
	fmt.Println(v.key, "=", v.value)
}
Output:

key = value1
key2 = true
key = value2
key2 = false

func (*Ini) Set added in v0.7.0

func (in *Ini) Set(secName, subName, key, value string) bool

Set the last variable's value in section-subsection that match with the key. If section or subsection is not found, the new section-subsection will be created. If key not found, the new key-value variable will be added to the section.

It will return true if new key added or updated; otherwise it will return false.

Example
input := []byte(`
[section]
key=value1 # comment
key2= ; another comment

[section "sub"]
key=value1

[section] ; here is comment on section
key=value2
key2=false

[section "sub"]
key=value2
key=value1
`)

ini, err := Parse(input)
if err != nil {
	log.Fatal(err)
}

ini.Set("", "sub", "key", "value3")
ini.Set("sectionnotexist", "sub", "key", "value3")
ini.Set("section", "sub", "key", "value3")
ini.Set("section", "", "key", "value4")
ini.Set("section", "", "keynotexist", "value4")

err = ini.Write(os.Stdout)
if err != nil {
	log.Fatal(err)
}
Output:

[section]
key=value1 # comment
key2= ; another comment

[section "sub"]
key=value1

[section] ; here is comment on section
key=value4
key2=false

keynotexist = value4

[section "sub"]
key=value2
key=value3

[sectionnotexist "sub"]
key = value3

func (*Ini) Subs added in v0.7.0

func (in *Ini) Subs(secName string) (subs []*Section)

Subs return all non empty subsections (and its variable) that have the same section name.

This function is shortcut to be used in templating.

Example
input := []byte(`
[section]
key=value1 # comment
key2= ; another comment

[section "sub"]
key=value1

[section] ; here is comment on section
key=value2
key2=false

[section "sub"]
key=value2
key=value1
`)

ini, err := Parse(input)
if err != nil {
	log.Fatal(err)
}

subs := ini.Subs("section")

for _, sub := range subs {
	fmt.Println(sub.SubName(), sub.Vals("key"))
}
Output:

sub [value2 value1]

func (*Ini) Unset added in v0.7.0

func (in *Ini) Unset(secName, subName, key string) bool

Unset remove the last variable's in section and/or subsection that match with the key. If key found it will return true, otherwise it will return false.

Example
input := []byte(`
[section]
key=value1 # comment
key2= ; another comment

[section "sub"]
key=value1

; here is comment on section
[section]
key=value2
key2=false

[section "sub"]
key=value2
key=value1
`)

ini, err := Parse(input)
if err != nil {
	log.Fatal(err)
}

ini.Unset("", "sub", "keynotexist")
ini.Unset("sectionnotexist", "sub", "keynotexist")
ini.Unset("section", "sub", "keynotexist")
ini.Unset("section", "sub", "key")
ini.Unset("section", "", "keynotexist")
ini.Unset("section", "", "key")

err = ini.Write(os.Stdout)
if err != nil {
	log.Fatal(err)
}
Output:

[section]
key=value1 # comment
key2= ; another comment

[section "sub"]
key=value1

; here is comment on section
[section]
key2=false

[section "sub"]
key=value2

func (*Ini) Val added in v0.7.0

func (in *Ini) Val(keyPath string) (val string)

Val return the last variable value using a string as combination of section, subsection, and key with ":" as separator. If key not found, it will return empty string.

For example, to get the value of key "k" in section "s" and subsection "sub", call

V("s:sub:k")

This function is shortcut to be used in templating.

Example
input := `
[section]
key=value1
key2=

[section "sub"]
key=value1

[section]
key=value2
key2=false

[section "sub"]
key=value2
key=value3
`

ini, err := Parse([]byte(input))
if err != nil {
	log.Fatal(err)
}

fmt.Println(ini.Val("section:sub:key"))
fmt.Println(ini.Val("section:sub:key2"))
fmt.Println(ini.Val("section::key"))
fmt.Println(ini.Val("section:key"))
Output:

value3

value2

func (*Ini) Vals added in v0.7.0

func (in *Ini) Vals(keyPath string) (vals []string)

Vals return all values as slice of string. The keyPath is combination of section, subsection, and key using colon ":" as separator. If key not found, it will return an empty slice.

For example, to get all values of key "k" in section "s" and subsection "sub", call

Vals("s:sub:k")

This function is shortcut to be used in templating.

Example
input := `
[section]
key=value1
key2=

[section "sub"]
key=value1
key=value2

[section]
key=value2
key2=false

[section "sub"]
key=value2
key=value3
`

ini, err := Parse([]byte(input))
if err != nil {
	log.Fatal(err)
}

fmt.Println(ini.Vals("section:key"))
fmt.Println(ini.Vals("section::key"))
fmt.Println(ini.Vals("section:sub:key2"))
fmt.Println(ini.Vals("section:sub:key"))
Output:

[]
[value1 value2]
[]
[value1 value2 value3]

func (*Ini) Vars added in v0.7.0

func (in *Ini) Vars(sectionPath string) (vars map[string]string)

Vars return all variables in section and/or subsection as map of string. If there is a duplicate in key's name, only the last key value that will be store on map value.

This method is a shortcut that can be used in templating.

Example
input := `
[section]
key=value1
key2=

[section "sub"]
key=value1
key=value2

[section]
key=value2
key2=false

[section "sub"]
key=value2
key=value3
`

ini, err := Parse([]byte(input))
if err != nil {
	log.Fatal(err)
}

for k, v := range ini.Vars("section:") {
	fmt.Println(k, "=", v)
}

fmt.Println()
for k, v := range ini.Vars("section:sub") {
	fmt.Println(k, "=", v)
}
Output:

section::key = value2
section::key2 = false

key = value3

func (*Ini) Write

func (in *Ini) Write(w io.Writer) (err error)

Write the current parsed Ini into writer `w`.

type Section

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

Section represent section header in INI file format and their variables.

Remember that section's name is case insensitive.

func (*Section) Name

func (sec *Section) Name() string

Name return the section's name.

func (*Section) String

func (sec *Section) String() string

String return formatted INI section header.

func (*Section) SubName added in v0.7.0

func (sec *Section) SubName() string

SubName return subsection's name.

func (*Section) Val added in v0.7.0

func (sec *Section) Val(key string) string

Val return the last defined variable key in section.

func (*Section) Vals added in v0.7.0

func (sec *Section) Vals(key string) []string

Vals return all variables in section as slice of string.

Jump to

Keyboard shortcuts

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