Skip to content

Commit 784eaa8

Browse files
committed
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>
1 parent a033f72 commit 784eaa8

File tree

4 files changed

+149
-14
lines changed

4 files changed

+149
-14
lines changed

git-config.go

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,69 @@
11
package goconfig
22

33
import (
4+
"sort"
45
"strconv"
56
"strings"
67
)
78

9+
// Scope is used to mark where config variable comes from
10+
type Scope int
11+
12+
// Define scopes for config variables
13+
const (
14+
ScopeInclude = 1 << iota
15+
ScopeSystem
16+
ScopeGlobal
17+
ScopeSelf
18+
19+
ScopeAll = 0xFFFF
20+
ScopeMask = ^ScopeInclude
21+
)
22+
23+
// String show user friendly display of scope
24+
func (v *Scope) String() string {
25+
i := int(*v)
26+
inc := ""
27+
if i&ScopeInclude == ScopeInclude {
28+
inc = "-inc"
29+
}
30+
31+
if i&ScopeSystem == ScopeSystem {
32+
return "system" + inc
33+
} else if i&ScopeGlobal == ScopeGlobal {
34+
return "global" + inc
35+
} else if i&ScopeSelf == ScopeSelf {
36+
return "self" + inc
37+
}
38+
return "unknown" + inc
39+
}
40+
841
// GitConfig maps section to key-value pairs
942
type GitConfig map[string]GitConfigKeys
1043

1144
// GitConfigKeys maps key to values
12-
type GitConfigKeys map[string][]string
45+
type GitConfigKeys map[string][]*GitConfigValue
46+
47+
// GitConfigValue holds value and its scope
48+
type GitConfigValue struct {
49+
scope Scope
50+
value string
51+
}
52+
53+
// Set is used to set value
54+
func (v *GitConfigValue) Set(value string) {
55+
v.value = value
56+
}
57+
58+
// Value is used to show value
59+
func (v *GitConfigValue) Value() string {
60+
return v.value
61+
}
62+
63+
// Scope is used to show user friendly scope
64+
func (v *GitConfigValue) Scope() string {
65+
return v.scope.String()
66+
}
1367

1468
// NewGitConfig returns GitConfig with initialized maps
1569
func NewGitConfig() GitConfig {
@@ -25,6 +79,7 @@ func (v GitConfig) Keys() []string {
2579
allKeys = append(allKeys, s+"."+key)
2680
}
2781
}
82+
sort.Strings(allKeys)
2883
return allKeys
2984
}
3085

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

4499
if _, ok := v[section][key]; !ok {
45-
v[section][key] = []string{}
100+
v[section][key] = []*GitConfigValue{}
46101
}
47-
v[section][key] = append(v[section][key], value)
102+
v[section][key] = append(v[section][key], &GitConfigValue{value: value})
48103
}
49104

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

109-
keys := v[section]
110-
if keys != nil {
111-
return keys[key]
164+
values := []string{}
165+
166+
if v[section] != nil && v[section][key] != nil {
167+
for _, value := range v[section][key] {
168+
if value != nil {
169+
values = append(values, value.value)
170+
}
171+
}
172+
return values
173+
}
174+
return nil
175+
}
176+
177+
// GetRaw gets all values of a key
178+
func (v GitConfig) GetRaw(key string) []*GitConfigValue {
179+
section, key := toSectionKey(key)
180+
181+
if v[section] != nil && v[section][key] != nil {
182+
return v[section][key]
112183
}
113184
return nil
114185
}
@@ -141,16 +212,26 @@ func toSectionKey(name string) (string, string) {
141212

142213
// Merge will merge another GitConfig, and new value(s) of the same key will
143214
// append to the end of value list, and new value has higher priority.
144-
func (v GitConfig) Merge(c GitConfig) GitConfig {
215+
func (v GitConfig) Merge(c GitConfig, scope Scope) GitConfig {
145216
for sec, keys := range c {
146217
if _, ok := v[sec]; !ok {
147218
v[sec] = make(GitConfigKeys)
148219
}
149220
for key, values := range keys {
150221
if v[sec][key] == nil {
151-
v[sec][key] = []string{}
222+
v[sec][key] = []*GitConfigValue{}
223+
}
224+
for _, value := range values {
225+
if value == nil {
226+
continue
227+
}
228+
v[sec][key] = append(v[sec][key],
229+
&GitConfigValue{
230+
scope: (value.scope & ^ScopeMask) | scope,
231+
value: value.Value(),
232+
})
233+
152234
}
153-
v[sec][key] = append(v[sec][key], values...)
154235
}
155236
}
156237
return v

git-config_test.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package goconfig
22

33
import (
4+
"fmt"
45
"testing"
56

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

185-
cfg.Merge(cfg2)
186+
cfg.Merge(cfg2, ScopeInclude)
186187
assert.Equal("value-b", cfg.Get("a.b"))
187188
assert.Equal("other-c", cfg.Get("a.c"))
188189
assert.Equal("other-d", cfg.Get("a.d"))
@@ -191,3 +192,56 @@ func TestMerge(t *testing.T) {
191192
"other-c",
192193
}, cfg.GetAll("a.c"))
193194
}
195+
196+
func TestScope(t *testing.T) {
197+
assert := assert.New(t)
198+
assert.Equal(0x1, ScopeInclude)
199+
assert.Equal(^0x1, ScopeMask)
200+
}
201+
202+
func ExampleMerge() {
203+
sys := NewGitConfig()
204+
sys.Add("sect1.Name1", "value-1.1.1")
205+
sys.Add("sect1.Name2", "value-1.1.2")
206+
207+
inc1 := NewGitConfig()
208+
inc1.Add("sect1.Name3", "value-0.1.3")
209+
inc1.Add("sect2.name1", "value-0.2.1")
210+
211+
sys.Merge(inc1, ScopeInclude)
212+
213+
global := NewGitConfig()
214+
global.Add("sect1.name2", "value-2.1.2")
215+
global.Add("sect1.name3", "value-2.1.3")
216+
global.Add("sect1.name4", "value-2.1.4")
217+
global.Add("sect3.name1", "value-2.3.1")
218+
219+
repo := NewGitConfig()
220+
repo.Add("sect1.name2", "value-3.1.2")
221+
repo.Add("sect1.name3", "value-3.1.3")
222+
repo.Add("sect1.name4", "value-3.1.4")
223+
224+
all := NewGitConfig()
225+
all.Merge(sys, ScopeSystem)
226+
all.Merge(global, ScopeGlobal)
227+
all.Merge(repo, ScopeSelf)
228+
229+
fmt.Println()
230+
for _, k := range all.Keys() {
231+
for _, value := range all.GetRaw(k) {
232+
fmt.Printf("%s = %-8s (%s)\n", k, value.Value(), value.Scope())
233+
}
234+
}
235+
// Output:
236+
// sect1.name1 = value-1.1.1 (system)
237+
// sect1.name2 = value-1.1.2 (system)
238+
// sect1.name2 = value-2.1.2 (global)
239+
// sect1.name2 = value-3.1.2 (self)
240+
// sect1.name3 = value-0.1.3 (system-inc)
241+
// sect1.name3 = value-2.1.3 (global)
242+
// sect1.name3 = value-3.1.3 (self)
243+
// sect1.name4 = value-2.1.4 (global)
244+
// sect1.name4 = value-3.1.4 (self)
245+
// sect2.name1 = value-0.2.1 (system-inc)
246+
// sect3.name1 = value-2.3.1 (global)
247+
}

goconfig.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func (cf *parser) parse() (GitConfig, error) {
103103
if err != nil {
104104
return cfg, err
105105
}
106-
cfg.Merge(config)
106+
cfg.Merge(config, ScopeInclude)
107107
}
108108
}
109109
}

load.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,15 @@ func loadAll(name string, searching bool) (GitConfig, error) {
116116
}
117117

118118
if sysConfig != nil {
119-
cfg.Merge(sysConfig)
119+
cfg.Merge(sysConfig, ScopeSystem)
120120
}
121121

122122
if globalConfig != nil {
123-
cfg.Merge(globalConfig)
123+
cfg.Merge(globalConfig, ScopeGlobal)
124124
}
125125

126126
if repoConfig != nil {
127-
cfg.Merge(repoConfig)
127+
cfg.Merge(repoConfig, ScopeSelf)
128128
}
129129

130130
return cfg, nil

0 commit comments

Comments
 (0)