Skip to content

Commit

Permalink
Mark values with scope, such as system, global, self
Browse files Browse the repository at this point in the history
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 12, 2019
1 parent a033f72 commit 784eaa8
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 14 deletions.
99 changes: 90 additions & 9 deletions git-config.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 {
Expand All @@ -25,6 +79,7 @@ func (v GitConfig) Keys() []string {
allKeys = append(allKeys, s+"."+key)
}
}
sort.Strings(allKeys)
return allKeys
}

Expand All @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down
56 changes: 55 additions & 1 deletion git-config_test.go
@@ -1,6 +1,7 @@
package goconfig

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -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"))
Expand All @@ -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)
}
2 changes: 1 addition & 1 deletion goconfig.go
Expand Up @@ -103,7 +103,7 @@ func (cf *parser) parse() (GitConfig, error) {
if err != nil {
return cfg, err
}
cfg.Merge(config)
cfg.Merge(config, ScopeInclude)
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions load.go
Expand Up @@ -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
Expand Down

0 comments on commit 784eaa8

Please sign in to comment.