...

Source file src/edge-infra.dev/pkg/lib/ini/section.go

Documentation: edge-infra.dev/pkg/lib/ini

     1  package ini
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  )
     8  
     9  // Section represents a config section.
    10  type Section struct {
    11  	f        *File
    12  	Comment  string
    13  	name     string
    14  	keys     map[string]*Key
    15  	keyList  []string
    16  	keysHash map[string]string
    17  
    18  	isRawSection bool
    19  	rawBody      string
    20  }
    21  
    22  func newSection(f *File, name string) *Section {
    23  	return &Section{
    24  		f:        f,
    25  		name:     name,
    26  		keys:     make(map[string]*Key),
    27  		keyList:  make([]string, 0, 10),
    28  		keysHash: make(map[string]string),
    29  	}
    30  }
    31  
    32  // Name returns name of Section.
    33  func (s *Section) Name() string {
    34  	return s.name
    35  }
    36  
    37  // Body returns rawBody of Section if the section was marked as unparseable.
    38  // It still follows the other rules of the INI format surrounding leading/trailing whitespace.
    39  func (s *Section) Body() string {
    40  	return strings.TrimSpace(s.rawBody)
    41  }
    42  
    43  // SetBody updates body content only if section is raw.
    44  func (s *Section) SetBody(body string) {
    45  	if !s.isRawSection {
    46  		return
    47  	}
    48  	s.rawBody = body
    49  }
    50  
    51  // NewKey creates a new key to given section.
    52  func (s *Section) NewKey(name, val string) (*Key, error) {
    53  	if len(name) == 0 {
    54  		return nil, errors.New("error creating new key: empty key name")
    55  	} else if s.f.options.Insensitive || s.f.options.InsensitiveKeys {
    56  		name = strings.ToLower(name)
    57  	}
    58  
    59  	if s.f.BlockMode {
    60  		s.f.lock.Lock()
    61  		defer s.f.lock.Unlock()
    62  	}
    63  
    64  	if inSlice(name, s.keyList) {
    65  		if s.f.options.AllowShadows {
    66  			if err := s.keys[name].addShadow(val); err != nil {
    67  				return nil, err
    68  			}
    69  		} else {
    70  			s.keys[name].value = val
    71  			s.keysHash[name] = val
    72  		}
    73  		return s.keys[name], nil
    74  	}
    75  
    76  	s.keyList = append(s.keyList, name)
    77  	s.keys[name] = newKey(s, name, val)
    78  	s.keysHash[name] = val
    79  	return s.keys[name], nil
    80  }
    81  
    82  // NewBooleanKey creates a new boolean type key to given section.
    83  func (s *Section) NewBooleanKey(name string) (*Key, error) {
    84  	key, err := s.NewKey(name, "true")
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	key.isBooleanType = true
    90  	return key, nil
    91  }
    92  
    93  // GetKey returns key in section by given name.
    94  func (s *Section) GetKey(name string) (*Key, error) {
    95  	if s.f.BlockMode {
    96  		s.f.lock.RLock()
    97  	}
    98  	if s.f.options.Insensitive || s.f.options.InsensitiveKeys {
    99  		name = strings.ToLower(name)
   100  	}
   101  	key := s.keys[name]
   102  	if s.f.BlockMode {
   103  		s.f.lock.RUnlock()
   104  	}
   105  
   106  	if key == nil {
   107  		// Check if it is a child-section.
   108  		sname := s.name
   109  		for {
   110  			if i := strings.LastIndex(sname, s.f.options.ChildSectionDelimiter); i > -1 {
   111  				sname = sname[:i]
   112  				sec, err := s.f.GetSection(sname)
   113  				if err != nil {
   114  					continue
   115  				}
   116  				return sec.GetKey(name)
   117  			}
   118  			break
   119  		}
   120  		return nil, fmt.Errorf("error when getting key of section %q: key %q not exists", s.name, name)
   121  	}
   122  	return key, nil
   123  }
   124  
   125  // HasKey returns true if section contains a key with given name.
   126  func (s *Section) HasKey(name string) bool {
   127  	key, _ := s.GetKey(name)
   128  	return key != nil
   129  }
   130  
   131  // Deprecated: Use "HasKey" instead.
   132  func (s *Section) Haskey(name string) bool {
   133  	return s.HasKey(name)
   134  }
   135  
   136  // HasValue returns true if section contains given raw value.
   137  func (s *Section) HasValue(value string) bool {
   138  	if s.f.BlockMode {
   139  		s.f.lock.RLock()
   140  		defer s.f.lock.RUnlock()
   141  	}
   142  
   143  	for _, k := range s.keys {
   144  		if value == k.value {
   145  			return true
   146  		}
   147  	}
   148  	return false
   149  }
   150  
   151  // Key assumes named Key exists in section and returns a zero-value when not.
   152  func (s *Section) Key(name string) *Key {
   153  	key, err := s.GetKey(name)
   154  	if err != nil {
   155  		// It's OK here because the only possible error is empty key name,
   156  		// but if it's empty, this piece of code won't be executed.
   157  		key, _ = s.NewKey(name, "")
   158  		return key
   159  	}
   160  	return key
   161  }
   162  
   163  // Keys returns list of keys of section.
   164  func (s *Section) Keys() []*Key {
   165  	keys := make([]*Key, len(s.keyList))
   166  	for i := range s.keyList {
   167  		keys[i] = s.Key(s.keyList[i])
   168  	}
   169  	return keys
   170  }
   171  
   172  // ParentKeys returns list of keys of parent section.
   173  func (s *Section) ParentKeys() []*Key {
   174  	var parentKeys []*Key
   175  	sname := s.name
   176  	for {
   177  		if i := strings.LastIndex(sname, s.f.options.ChildSectionDelimiter); i > -1 {
   178  			sname = sname[:i]
   179  			sec, err := s.f.GetSection(sname)
   180  			if err != nil {
   181  				continue
   182  			}
   183  			parentKeys = append(parentKeys, sec.Keys()...)
   184  		} else {
   185  			break
   186  		}
   187  
   188  	}
   189  	return parentKeys
   190  }
   191  
   192  // KeyStrings returns list of key names of section.
   193  func (s *Section) KeyStrings() []string {
   194  	list := make([]string, len(s.keyList))
   195  	copy(list, s.keyList)
   196  	return list
   197  }
   198  
   199  // KeysHash returns keys hash consisting of names and values.
   200  func (s *Section) KeysHash() map[string]string {
   201  	if s.f.BlockMode {
   202  		s.f.lock.RLock()
   203  		defer s.f.lock.RUnlock()
   204  	}
   205  
   206  	hash := make(map[string]string, len(s.keysHash))
   207  	for key, value := range s.keysHash {
   208  		hash[key] = value
   209  	}
   210  	return hash
   211  }
   212  
   213  // DeleteKey deletes a key from section.
   214  func (s *Section) DeleteKey(name string) {
   215  	if s.f.BlockMode {
   216  		s.f.lock.Lock()
   217  		defer s.f.lock.Unlock()
   218  	}
   219  
   220  	for i, k := range s.keyList {
   221  		if k == name {
   222  			s.keyList = append(s.keyList[:i], s.keyList[i+1:]...)
   223  			delete(s.keys, name)
   224  			delete(s.keysHash, name)
   225  			return
   226  		}
   227  	}
   228  }
   229  
   230  // ChildSections returns a list of child sections of current section.
   231  // For example, "[parent.child1]" and "[parent.child12]" are child sections
   232  // of section "[parent]".
   233  func (s *Section) ChildSections() []*Section {
   234  	prefix := s.name + s.f.options.ChildSectionDelimiter
   235  	children := make([]*Section, 0, 3)
   236  	for _, name := range s.f.sectionList {
   237  		if strings.HasPrefix(name, prefix) {
   238  			children = append(children, s.f.sections[name]...)
   239  		}
   240  	}
   241  	return children
   242  }
   243  

View as plain text