fsrepo components simplification: directly use config
Tommi Virtanen committed
Mar 11, 2015 at 11:04 UTC
22b6ee328bef20406fc1157c3266e33cce3150ad
2 files changed
+129
-182
repo/fsrepo/component/config.go
deleted
-156
@@ -1,156 +0,0 @@
1
-package component
2
-
3
-import (
4
- "strconv"
5
-
6
- common "github.com/jbenet/go-ipfs/repo/common"
7
- config "github.com/jbenet/go-ipfs/repo/config"
8
- serialize "github.com/jbenet/go-ipfs/repo/fsrepo/serialize"
9
- util "github.com/jbenet/go-ipfs/util"
10
-)
11
-
12
-var _ Component = &ConfigComponent{}
13
-var _ Initializer = InitConfigComponent
14
-var _ InitializationChecker = ConfigComponentIsInitialized
15
-
16
-// ConfigComponent abstracts the config component of the FSRepo.
17
-// NB: create with makeConfigComponent function.
18
-// NOT THREAD-SAFE
19
-type ConfigComponent struct {
20
- path string // required at instantiation
21
- config *config.Config // assigned on Open()
22
-}
23
-
24
-// fsrepoConfigInit initializes the FSRepo's ConfigComponent.
25
-func InitConfigComponent(path string, conf *config.Config) error {
26
- if ConfigComponentIsInitialized(path) {
27
- return nil
28
- }
29
- configFilename, err := config.Filename(path)
30
- if err != nil {
31
- return err
32
- }
33
- // initialization is the one time when it's okay to write to the config
34
- // without reading the config from disk and merging any user-provided keys
35
- // that may exist.
36
- if err := serialize.WriteConfigFile(configFilename, conf); err != nil {
37
- return err
38
- }
39
- return nil
40
-}
41
-
42
-// Open returns an error if the config file is not present. This component is
43
-// always called with a nil config parameter. Other components rely on the
44
-// config, to keep the interface uniform, it is special-cased.
45
-func (c *ConfigComponent) Open(_ *config.Config) error {
46
- configFilename, err := config.Filename(c.path)
47
- if err != nil {
48
- return err
49
- }
50
- conf, err := serialize.Load(configFilename)
51
- if err != nil {
52
- return err
53
- }
54
- c.config = conf
55
- return nil
56
-}
57
-
58
-// Close satisfies the fsrepoComponent interface.
59
-func (c *ConfigComponent) Close() error {
60
- return nil // config doesn't need to be closed.
61
-}
62
-
63
-func (c *ConfigComponent) Config() *config.Config {
64
- return c.config
65
-}
66
-
67
-// SetConfig updates the config file.
68
-func (c *ConfigComponent) SetConfig(updated *config.Config) error {
69
- return c.setConfigUnsynced(updated)
70
-}
71
-
72
-// GetConfigKey retrieves only the value of a particular key.
73
-func (c *ConfigComponent) GetConfigKey(key string) (interface{}, error) {
74
- filename, err := config.Filename(c.path)
75
- if err != nil {
76
- return nil, err
77
- }
78
- var cfg map[string]interface{}
79
- if err := serialize.ReadConfigFile(filename, &cfg); err != nil {
80
- return nil, err
81
- }
82
- return common.MapGetKV(cfg, key)
83
-}
84
-
85
-// SetConfigKey writes the value of a particular key.
86
-func (c *ConfigComponent) SetConfigKey(key string, value interface{}) error {
87
- filename, err := config.Filename(c.path)
88
- if err != nil {
89
- return err
90
- }
91
- switch v := value.(type) {
92
- case string:
93
- if i, err := strconv.Atoi(v); err == nil {
94
- value = i
95
- }
96
- }
97
- var mapconf map[string]interface{}
98
- if err := serialize.ReadConfigFile(filename, &mapconf); err != nil {
99
- return err
100
- }
101
- if err := common.MapSetKV(mapconf, key, value); err != nil {
102
- return err
103
- }
104
- conf, err := config.FromMap(mapconf)
105
- if err != nil {
106
- return err
107
- }
108
- if err := serialize.WriteConfigFile(filename, mapconf); err != nil {
109
- return err
110
- }
111
- return c.setConfigUnsynced(conf) // TODO roll this into this method
112
-}
113
-
114
-func (c *ConfigComponent) SetPath(p string) {
115
- c.path = p
116
-}
117
-
118
-// ConfigComponentIsInitialized returns true if the repo is initialized at
119
-// provided |path|.
120
-func ConfigComponentIsInitialized(path string) bool {
121
- configFilename, err := config.Filename(path)
122
- if err != nil {
123
- return false
124
- }
125
- if !util.FileExists(configFilename) {
126
- return false
127
- }
128
- return true
129
-}
130
-
131
-// setConfigUnsynced is for private use.
132
-func (r *ConfigComponent) setConfigUnsynced(updated *config.Config) error {
133
- configFilename, err := config.Filename(r.path)
134
- if err != nil {
135
- return err
136
- }
137
- // to avoid clobbering user-provided keys, must read the config from disk
138
- // as a map, write the updated struct values to the map and write the map
139
- // to disk.
140
- var mapconf map[string]interface{}
141
- if err := serialize.ReadConfigFile(configFilename, &mapconf); err != nil {
142
- return err
143
- }
144
- m, err := config.ToMap(updated)
145
- if err != nil {
146
- return err
147
- }
148
- for k, v := range m {
149
- mapconf[k] = v
150
- }
151
- if err := serialize.WriteConfigFile(configFilename, mapconf); err != nil {
152
- return err
153
- }
154
- *r.config = *updated // copy so caller cannot modify this private config
155
- return nil
156
-}
repo/fsrepo/fsrepo.go
+129
-26
@@ -6,10 +6,12 @@ import (
6
"io"
7
"os"
8
"path"
9
+ "strconv"
10
"sync"
11
12
ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
13
repo "github.com/jbenet/go-ipfs/repo"
14
+ "github.com/jbenet/go-ipfs/repo/common"
15
config "github.com/jbenet/go-ipfs/repo/config"
16
component "github.com/jbenet/go-ipfs/repo/fsrepo/component"
17
counter "github.com/jbenet/go-ipfs/repo/fsrepo/counter"
@@ -17,6 +19,7 @@ import (
19
serialize "github.com/jbenet/go-ipfs/repo/fsrepo/serialize"
20
dir "github.com/jbenet/go-ipfs/thirdparty/dir"
21
u "github.com/jbenet/go-ipfs/util"
22
+ util "github.com/jbenet/go-ipfs/util"
23
debugerror "github.com/jbenet/go-ipfs/util/debugerror"
24
)
25
@@ -50,10 +53,10 @@ type FSRepo struct {
53
state state
54
// path is the file-system path
55
path string
53
- // configComponent is loaded when FSRepo is opened and kept up to date when
54
- // the FSRepo is modified.
56
+ // config is set on Open, guarded by packageLock
57
+ config *config.Config
58
+
59
// TODO test
56
- configComponent component.ConfigComponent
60
datastoreComponent component.DatastoreComponent
61
eventlogComponent component.EventlogComponent
62
}
@@ -91,6 +94,36 @@ func ConfigAt(repoPath string) (*config.Config, error) {
94
return serialize.Load(configFilename)
95
}
96
97
+// configIsInitialized returns true if the repo is initialized at
98
+// provided |path|.
99
+func configIsInitialized(path string) bool {
100
+ configFilename, err := config.Filename(path)
101
+ if err != nil {
102
+ return false
103
+ }
104
+ if !util.FileExists(configFilename) {
105
+ return false
106
+ }
107
+ return true
108
+}
109
+
110
+func initConfig(path string, conf *config.Config) error {
111
+ if configIsInitialized(path) {
112
+ return nil
113
+ }
114
+ configFilename, err := config.Filename(path)
115
+ if err != nil {
116
+ return err
117
+ }
118
+ // initialization is the one time when it's okay to write to the config
119
+ // without reading the config from disk and merging any user-provided keys
120
+ // that may exist.
121
+ if err := serialize.WriteConfigFile(configFilename, conf); err != nil {
122
+ return err
123
+ }
124
+ return nil
125
+}
126
+
127
// Init initializes a new FSRepo at the given path with the provided config.
128
// TODO add support for custom datastores.
129
func Init(path string, conf *config.Config) error {
@@ -103,6 +136,11 @@ func Init(path string, conf *config.Config) error {
136
if isInitializedUnsynced(path) {
137
return nil
138
}
139
+
140
+ if err := initConfig(path, conf); err != nil {
141
+ return err
142
+ }
143
+
144
for _, b := range componentBuilders() {
145
if err := b.Init(path, conf); err != nil {
146
return err
@@ -139,6 +177,20 @@ func LockedByOtherProcess(repoPath string) bool {
177
return lockfile.Locked(repoPath) && openersCounter.NumOpeners(repoPath) == 0
178
}
179
180
+// openConfig returns an error if the config file is not present.
181
+func (r *FSRepo) openConfig() error {
182
+ configFilename, err := config.Filename(r.path)
183
+ if err != nil {
184
+ return err
185
+ }
186
+ conf, err := serialize.Load(configFilename)
187
+ if err != nil {
188
+ return err
189
+ }
190
+ r.config = conf
191
+ return nil
192
+}
193
+
194
// Open returns an error if the repo is not initialized.
195
func (r *FSRepo) Open() error {
196
@@ -167,6 +219,10 @@ func (r *FSRepo) Open() error {
219
return err
220
}
221
222
+ if err := r.openConfig(); err != nil {
223
+ return err
224
+ }
225
+
226
for _, b := range componentBuilders() {
227
if err := b.OpenHandler(r); err != nil {
228
return err
@@ -210,7 +266,34 @@ func (r *FSRepo) Config() *config.Config {
266
if r.state != opened {
267
panic(fmt.Sprintln("repo is", r.state))
268
}
213
- return r.configComponent.Config()
269
+ return r.config
270
+}
271
+
272
+// setConfigUnsynced is for private use.
273
+func (r *FSRepo) setConfigUnsynced(updated *config.Config) error {
274
+ configFilename, err := config.Filename(r.path)
275
+ if err != nil {
276
+ return err
277
+ }
278
+ // to avoid clobbering user-provided keys, must read the config from disk
279
+ // as a map, write the updated struct values to the map and write the map
280
+ // to disk.
281
+ var mapconf map[string]interface{}
282
+ if err := serialize.ReadConfigFile(configFilename, &mapconf); err != nil {
283
+ return err
284
+ }
285
+ m, err := config.ToMap(updated)
286
+ if err != nil {
287
+ return err
288
+ }
289
+ for k, v := range m {
290
+ mapconf[k] = v
291
+ }
292
+ if err := serialize.WriteConfigFile(configFilename, mapconf); err != nil {
293
+ return err
294
+ }
295
+ *r.config = *updated // copy so caller cannot modify this private config
296
+ return nil
297
}
298
299
// SetConfig updates the FSRepo's config.
@@ -220,7 +303,7 @@ func (r *FSRepo) SetConfig(updated *config.Config) error {
303
packageLock.Lock()
304
defer packageLock.Unlock()
305
223
- return r.configComponent.SetConfig(updated)
306
+ return r.setConfigUnsynced(updated)
307
}
308
309
// GetConfigKey retrieves only the value of a particular key.
@@ -231,7 +314,16 @@ func (r *FSRepo) GetConfigKey(key string) (interface{}, error) {
314
if r.state != opened {
315
return nil, debugerror.Errorf("repo is %s", r.state)
316
}
234
- return r.configComponent.GetConfigKey(key)
317
+
318
+ filename, err := config.Filename(r.path)
319
+ if err != nil {
320
+ return nil, err
321
+ }
322
+ var cfg map[string]interface{}
323
+ if err := serialize.ReadConfigFile(filename, &cfg); err != nil {
324
+ return nil, err
325
+ }
326
+ return common.MapGetKV(cfg, key)
327
}
328
329
// SetConfigKey writes the value of a particular key.
@@ -242,7 +334,32 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
334
if r.state != opened {
335
return debugerror.Errorf("repo is %s", r.state)
336
}
245
- return r.configComponent.SetConfigKey(key, value)
337
+
338
+ filename, err := config.Filename(r.path)
339
+ if err != nil {
340
+ return err
341
+ }
342
+ switch v := value.(type) {
343
+ case string:
344
+ if i, err := strconv.Atoi(v); err == nil {
345
+ value = i
346
+ }
347
+ }
348
+ var mapconf map[string]interface{}
349
+ if err := serialize.ReadConfigFile(filename, &mapconf); err != nil {
350
+ return err
351
+ }
352
+ if err := common.MapSetKV(mapconf, key, value); err != nil {
353
+ return err
354
+ }
355
+ conf, err := config.FromMap(mapconf)
356
+ if err != nil {
357
+ return err
358
+ }
359
+ if err := serialize.WriteConfigFile(filename, mapconf); err != nil {
360
+ return err
361
+ }
362
+ return r.setConfigUnsynced(conf) // TODO roll this into this method
363
}
364
365
// Datastore returns a repo-owned datastore. If FSRepo is Closed, return value
@@ -272,6 +389,9 @@ func IsInitialized(path string) bool {
389
// isInitializedUnsynced reports whether the repo is initialized. Caller must
390
// hold the packageLock.
391
func isInitializedUnsynced(path string) bool {
392
+ if !configIsInitialized(path) {
393
+ return false
394
+ }
395
for _, b := range componentBuilders() {
396
if !b.IsInitialized(path) {
397
return false
@@ -317,7 +437,6 @@ func (r *FSRepo) transitionToClosed() error {
437
// components returns the FSRepo's constituent components
438
func (r *FSRepo) components() []component.Component {
439
return []component.Component{
320
- &r.configComponent,
440
&r.datastoreComponent,
441
}
442
}
@@ -325,22 +444,6 @@ func (r *FSRepo) components() []component.Component {
444
func componentBuilders() []componentBuilder {
445
return []componentBuilder{
446
328
- // ConfigComponent must be initialized first because other components
329
- // depend on it.
330
- componentBuilder{
331
- Init: component.InitConfigComponent,
332
- IsInitialized: component.ConfigComponentIsInitialized,
333
- OpenHandler: func(r *FSRepo) error {
334
- c := component.ConfigComponent{}
335
- c.SetPath(r.path)
336
- if err := c.Open(nil); err != nil {
337
- return err
338
- }
339
- r.configComponent = c
340
- return nil
341
- },
342
- },
343
-
447
// DatastoreComponent
448
componentBuilder{
449
Init: component.InitDatastoreComponent,
@@ -348,7 +451,7 @@ func componentBuilders() []componentBuilder {
451
OpenHandler: func(r *FSRepo) error {
452
c := component.DatastoreComponent{}
453
c.SetPath(r.path)
351
- if err := c.Open(r.configComponent.Config()); err != nil {
454
+ if err := c.Open(r.config); err != nil {
455
return err
456
}
457
r.datastoreComponent = c
@@ -363,7 +466,7 @@ func componentBuilders() []componentBuilder {
466
OpenHandler: func(r *FSRepo) error {
467
c := component.EventlogComponent{}
468
c.SetPath(r.path)
366
- if err := c.Open(r.configComponent.Config()); err != nil {
469
+ if err := c.Open(r.config); err != nil {
470
return err
471
}
472
r.eventlogComponent = c