Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

true, unambiguous "global" section #10

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 41 additions & 21 deletions configparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var Delimiter = "="
// Configuration represents a configuration file with its sections and options.
type Configuration struct {
filePath string // configuration file
global *Section // for settings that don't go into a named section
sections map[string]*list.List // fully qualified section name as key
orderedSections []string // track the order of section names as they are parsed
mutex sync.RWMutex
Expand All @@ -41,6 +42,7 @@ type Configuration struct {
// A Section in a configuration.
type Section struct {
fqn string
isGlobal bool
options map[string]string
orderedOptions []string // track the order of the options as they are parsed
mutex sync.RWMutex
Expand All @@ -62,21 +64,21 @@ func Read(filePath string) (*Configuration, error) {
defer file.Close()

config := newConfiguration(filePath)
activeSection := config.addSection("global")
activeSection := config.global

scanner := bufio.NewScanner(bufio.NewReader(file))
for scanner.Scan() {
// TODO: maybe trim spaces here
line := scanner.Text()
if (len(line) < 0) {
if len(line) < 0 {
continue
}
}

if isSection(line) {
fqn := strings.Trim(line, " []")
activeSection = config.addSection(fqn)
continue
}
}
// save options and comments
addOption(activeSection, line)
}
Expand Down Expand Up @@ -114,22 +116,23 @@ func Save(c *Configuration, filePath string) (err error) {
}()
c.mutex.Unlock()

s, err := c.AllSections()
global, sections, err := c.AllSections()
if err != nil {
return err
}

c.mutex.Lock()
defer c.mutex.Unlock()

for _, v := range s {
w.WriteString(global.String())
for _, v := range sections {
w.WriteString(v.String())
}

return err
}

// NewSection creates and adds a new Section with the specified name.
// NewSection creates and adds a new non-global Section with the specified name.
func (c *Configuration) NewSection(fqn string) *Section {
return c.addSection(fqn)
}
Expand All @@ -147,7 +150,7 @@ func (c *Configuration) SetFilePath(filePath string) {
c.filePath = filePath
}

// StringValue returns the string value for the specified section and option.
// StringValue returns the string value for the specified non-global section and option.
func (c *Configuration) StringValue(section, option string) (value string, err error) {
s, err := c.Section(section)
if err != nil {
Expand All @@ -157,7 +160,7 @@ func (c *Configuration) StringValue(section, option string) (value string, err e
return
}

// Delete deletes the specified sections matched by a regex name and returns the deleted sections.
// Delete deletes the specified non-global sections matched by a regex name and returns the deleted sections.
func (c *Configuration) Delete(regex string) (sections []*Section, err error) {
sections, err = c.Find(regex)
c.mutex.Lock()
Expand All @@ -182,7 +185,12 @@ func (c *Configuration) Delete(regex string) (sections []*Section, err error) {
return sections, err
}

// Section returns the first section matching the fully qualified section name.
// GlobalSection returns the global section
func (c *Configuration) GlobalSection() *Section {
return c.global
}

// Section returns the first non-global section matching the fully qualified section name.
func (c *Configuration) Section(fqn string) (*Section, error) {
c.mutex.RLock()
defer c.mutex.RUnlock()
Expand All @@ -196,12 +204,13 @@ func (c *Configuration) Section(fqn string) (*Section, error) {
return nil, errors.New("Unable to find " + fqn)
}

// AllSections returns a slice of all sections available.
func (c *Configuration) AllSections() ([]*Section, error) {
return c.Sections("")
// AllSections returns the global, as well as a slice of all non-global sections.
func (c *Configuration) AllSections() (*Section, []*Section, error) {
s, err := c.Sections("")
return c.global, s, err
}

// Sections returns a slice of Sections matching the fully qualified section name.
// Sections returns a slice of non-global Sections matching the fully qualified section name.
func (c *Configuration) Sections(fqn string) ([]*Section, error) {
c.mutex.RLock()
defer c.mutex.RUnlock()
Expand Down Expand Up @@ -233,7 +242,7 @@ func (c *Configuration) Sections(fqn string) ([]*Section, error) {
return sections, nil
}

// Find returns a slice of Sections matching the regexp against the section name.
// Find returns a slice of non-global Sections matching the regexp against the section name.
func (c *Configuration) Find(regex string) ([]*Section, error) {
c.mutex.RLock()
defer c.mutex.RUnlock()
Expand All @@ -254,7 +263,7 @@ func (c *Configuration) Find(regex string) ([]*Section, error) {
return sections, nil
}

// PrintSection prints a text representation of all sections matching the fully qualified section name.
// PrintSection prints a text representation of all non-global sections matching the fully qualified section name.
func (c *Configuration) PrintSection(fqn string) {
c.mutex.RLock()
defer c.mutex.RUnlock()
Expand All @@ -275,6 +284,7 @@ func (c *Configuration) String() string {
defer c.mutex.RUnlock()

var parts []string
parts = append(parts, c.global.String())
for _, fqn := range c.orderedSections {
sections, _ := c.Sections(fqn)
for _, section := range sections {
Expand Down Expand Up @@ -366,11 +376,10 @@ func (s *Section) String() string {
defer s.mutex.RUnlock()

var parts []string
sName := "[" + s.fqn + "]\n"
if s.fqn == "global" {
sName = ""

if !s.isGlobal {
parts = append(parts, "["+s.fqn+"]\n")
}
parts = append(parts, sName)

for _, opt := range s.orderedOptions {
value := s.options[opt]
Expand All @@ -388,10 +397,20 @@ func (s *Section) String() string {
// Private
//

// newSection creates a new, blank section
func newSection(fqn string, isGlobal bool) *Section {
return &Section{
fqn: fqn,
isGlobal: isGlobal,
options: make(map[string]string),
}
}

// newConfiguration creates a new Configuration instance.
func newConfiguration(filePath string) *Configuration {
return &Configuration{
filePath: filePath,
global: newSection("", true),
sections: make(map[string]*list.List),
}
}
Expand Down Expand Up @@ -431,8 +450,9 @@ func parseOption(option string) (opt, value string) {
return
}

// addSection adds a new non-global section with the given name
func (c *Configuration) addSection(fqn string) *Section {
section := &Section{fqn: fqn, options: make(map[string]string)}
section := newSection(fqn, false)

var lst *list.List
if lst = c.sections[fqn]; lst == nil {
Expand Down