Skip to content
Permalink
Browse files

Mark values with scope, such as system, global, self

After mark values with scope, we can filter config values in order to
show config variables of specific scope.

Signed-off-by: Jiang Xin <zhiyou.jx@alibaba-inc.com>
  • Loading branch information...
jiangxin committed Mar 9, 2019
1 parent a033f72 commit 784eaa8d6f2f0822d41cb7ff3e4ed8c5bd1d7820
Showing with 149 additions and 14 deletions.
  1. +90 −9 git-config.go
  2. +55 −1 git-config_test.go
  3. +1 −1 goconfig.go
  4. +3 −3 load.go
@@ -1,15 +1,69 @@
package goconfig

import (
"sort"
"strconv"
"strings"
)

// Scope is used to mark where config variable comes from
type Scope int

// Define scopes for config variables
const (
ScopeInclude = 1 << iota
ScopeSystem
ScopeGlobal
ScopeSelf

ScopeAll = 0xFFFF
ScopeMask = ^ScopeInclude
)

// String show user friendly display of scope
func (v *Scope) String() string {
i := int(*v)
inc := ""
if i&ScopeInclude == ScopeInclude {
inc = "-inc"
}

if i&ScopeSystem == ScopeSystem {
return "system" + inc
} else if i&ScopeGlobal == ScopeGlobal {
return "global" + inc
} else if i&ScopeSelf == ScopeSelf {
return "self" + inc
}
return "unknown" + inc
}

// GitConfig maps section to key-value pairs
type GitConfig map[string]GitConfigKeys

// GitConfigKeys maps key to values
type GitConfigKeys map[string][]string
type GitConfigKeys map[string][]*GitConfigValue

// GitConfigValue holds value and its scope
type GitConfigValue struct {
scope Scope
value string
}

// Set is used to set value
func (v *GitConfigValue) Set(value string) {
v.value = value
}

// Value is used to show value
func (v *GitConfigValue) Value() string {
return v.value
}

// Scope is used to show user friendly scope
func (v *GitConfigValue) Scope() string {
return v.scope.String()
}

// NewGitConfig returns GitConfig with initialized maps
func NewGitConfig() GitConfig {
@@ -25,6 +79,7 @@ func (v GitConfig) Keys() []string {
allKeys = append(allKeys, s+"."+key)
}
}
sort.Strings(allKeys)
return allKeys
}

@@ -42,9 +97,9 @@ func (v GitConfig) _add(section, key, value string) {
}

if _, ok := v[section][key]; !ok {
v[section][key] = []string{}
v[section][key] = []*GitConfigValue{}
}
v[section][key] = append(v[section][key], value)
v[section][key] = append(v[section][key], &GitConfigValue{value: value})
}

// Get value from key
@@ -106,9 +161,25 @@ func (v GitConfig) GetUint64(key string, defaultValue uint64) (uint64, error) {
func (v GitConfig) GetAll(key string) []string {
section, key := toSectionKey(key)

keys := v[section]
if keys != nil {
return keys[key]
values := []string{}

if v[section] != nil && v[section][key] != nil {
for _, value := range v[section][key] {
if value != nil {
values = append(values, value.value)
}
}
return values
}
return nil
}

// GetRaw gets all values of a key
func (v GitConfig) GetRaw(key string) []*GitConfigValue {
section, key := toSectionKey(key)

if v[section] != nil && v[section][key] != nil {
return v[section][key]
}
return nil
}
@@ -141,16 +212,26 @@ func toSectionKey(name string) (string, string) {

// Merge will merge another GitConfig, and new value(s) of the same key will
// append to the end of value list, and new value has higher priority.
func (v GitConfig) Merge(c GitConfig) GitConfig {
func (v GitConfig) Merge(c GitConfig, scope Scope) GitConfig {
for sec, keys := range c {
if _, ok := v[sec]; !ok {
v[sec] = make(GitConfigKeys)
}
for key, values := range keys {
if v[sec][key] == nil {
v[sec][key] = []string{}
v[sec][key] = []*GitConfigValue{}
}
for _, value := range values {
if value == nil {
continue
}
v[sec][key] = append(v[sec][key],
&GitConfigValue{
scope: (value.scope & ^ScopeMask) | scope,
value: value.Value(),
})

}
v[sec][key] = append(v[sec][key], values...)
}
}
return v
@@ -1,6 +1,7 @@
package goconfig

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
@@ -182,7 +183,7 @@ func TestMerge(t *testing.T) {
assert.Equal("other-c", cfg2.Get("a.c"))
assert.Equal("other-d", cfg2.Get("a.d"))

cfg.Merge(cfg2)
cfg.Merge(cfg2, ScopeInclude)
assert.Equal("value-b", cfg.Get("a.b"))
assert.Equal("other-c", cfg.Get("a.c"))
assert.Equal("other-d", cfg.Get("a.d"))
@@ -191,3 +192,56 @@ func TestMerge(t *testing.T) {
"other-c",
}, cfg.GetAll("a.c"))
}

func TestScope(t *testing.T) {
assert := assert.New(t)
assert.Equal(0x1, ScopeInclude)
assert.Equal(^0x1, ScopeMask)
}

func ExampleMerge() {
sys := NewGitConfig()
sys.Add("sect1.Name1", "value-1.1.1")
sys.Add("sect1.Name2", "value-1.1.2")

inc1 := NewGitConfig()
inc1.Add("sect1.Name3", "value-0.1.3")
inc1.Add("sect2.name1", "value-0.2.1")

sys.Merge(inc1, ScopeInclude)

global := NewGitConfig()
global.Add("sect1.name2", "value-2.1.2")
global.Add("sect1.name3", "value-2.1.3")
global.Add("sect1.name4", "value-2.1.4")
global.Add("sect3.name1", "value-2.3.1")

repo := NewGitConfig()
repo.Add("sect1.name2", "value-3.1.2")
repo.Add("sect1.name3", "value-3.1.3")
repo.Add("sect1.name4", "value-3.1.4")

all := NewGitConfig()
all.Merge(sys, ScopeSystem)
all.Merge(global, ScopeGlobal)
all.Merge(repo, ScopeSelf)

fmt.Println()
for _, k := range all.Keys() {
for _, value := range all.GetRaw(k) {
fmt.Printf("%s = %-8s (%s)\n", k, value.Value(), value.Scope())
}
}
// Output:
// sect1.name1 = value-1.1.1 (system)
// sect1.name2 = value-1.1.2 (system)
// sect1.name2 = value-2.1.2 (global)
// sect1.name2 = value-3.1.2 (self)
// sect1.name3 = value-0.1.3 (system-inc)
// sect1.name3 = value-2.1.3 (global)
// sect1.name3 = value-3.1.3 (self)
// sect1.name4 = value-2.1.4 (global)
// sect1.name4 = value-3.1.4 (self)
// sect2.name1 = value-0.2.1 (system-inc)
// sect3.name1 = value-2.3.1 (global)
}
@@ -103,7 +103,7 @@ func (cf *parser) parse() (GitConfig, error) {
if err != nil {
return cfg, err
}
cfg.Merge(config)
cfg.Merge(config, ScopeInclude)
}
}
}
@@ -116,15 +116,15 @@ func loadAll(name string, searching bool) (GitConfig, error) {
}

if sysConfig != nil {
cfg.Merge(sysConfig)
cfg.Merge(sysConfig, ScopeSystem)
}

if globalConfig != nil {
cfg.Merge(globalConfig)
cfg.Merge(globalConfig, ScopeGlobal)
}

if repoConfig != nil {
cfg.Merge(repoConfig)
cfg.Merge(repoConfig, ScopeSelf)
}

return cfg, nil

0 comments on commit 784eaa8

Please sign in to comment.
You can’t perform that action at this time.