refactor(fsrepo) extract component.Component
Brian Tiger Chow committed
Jan 14, 2015 at 07:54 UTC
9f67ede6b22cfd2845b50f8f6a8b76c06d4cbb89
5 files changed
+101
-81
repo/fsrepo/component/component.go
new
+14
@@ -0,0 +1,14 @@
1
+package component
2
+
3
+import (
4
+ "io"
5
+
6
+ "github.com/jbenet/go-ipfs/repo/config"
7
+)
8
+
9
+type Component interface {
10
+ Open() error
11
+ io.Closer
12
+}
13
+type Initializer func(path string, conf *config.Config) error
14
+type InitializationChecker func(path string) bool
repo/fsrepo/component/config.go
renamed
+32
-34
@@ -1,29 +1,27 @@
1
-package fsrepo
1
+package component
2
3
import (
4
common "github.com/jbenet/go-ipfs/repo/common"
5
config "github.com/jbenet/go-ipfs/repo/config"
6
+ serialize "github.com/jbenet/go-ipfs/repo/fsrepo/serialize"
7
util "github.com/jbenet/go-ipfs/util"
8
)
9
9
-var _ component = &configComponent{}
10
-var _ componentInitializationChecker = configComponentIsInitialized
10
+var _ Component = &ConfigComponent{}
11
+var _ Initializer = InitConfigComponent
12
+var _ InitializationChecker = ConfigComponentIsInitialized
13
12
-// configComponent abstracts the config component of the FSRepo.
14
+// ConfigComponent abstracts the config component of the FSRepo.
15
// NB: create with makeConfigComponent function.
14
-type configComponent struct {
15
- path string // required at instantiation
16
+// NOT THREAD-SAFE
17
+type ConfigComponent struct {
18
+ Path string // required at instantiation
19
config *config.Config // assigned on Open()
20
}
21
19
-// makeConfigComponent instantiates a valid configComponent.
20
-func makeConfigComponent(path string) configComponent {
21
- return configComponent{path: path}
22
-}
23
-
24
-// fsrepoConfigInit initializes the FSRepo's configComponent.
25
-func initConfigComponent(path string, conf *config.Config) error {
26
- if configComponentIsInitialized(path) {
22
+// fsrepoConfigInit initializes the FSRepo's ConfigComponent.
23
+func InitConfigComponent(path string, conf *config.Config) error {
24
+ if ConfigComponentIsInitialized(path) {
25
return nil
26
}
27
configFilename, err := config.Filename(path)
@@ -33,19 +31,19 @@ func initConfigComponent(path string, conf *config.Config) error {
31
// initialization is the one time when it's okay to write to the config
32
// without reading the config from disk and merging any user-provided keys
33
// that may exist.
36
- if err := writeConfigFile(configFilename, conf); err != nil {
34
+ if err := serialize.WriteConfigFile(configFilename, conf); err != nil {
35
return err
36
}
37
return nil
38
}
39
40
// Open returns an error if the config file is not present.
43
-func (c *configComponent) Open() error {
44
- configFilename, err := config.Filename(c.path)
41
+func (c *ConfigComponent) Open() error {
42
+ configFilename, err := config.Filename(c.Path)
43
if err != nil {
44
return err
45
}
48
- conf, err := load(configFilename)
46
+ conf, err := serialize.Load(configFilename)
47
if err != nil {
48
return err
49
}
@@ -54,46 +52,46 @@ func (c *configComponent) Open() error {
52
}
53
54
// Close satisfies the fsrepoComponent interface.
57
-func (c *configComponent) Close() error {
55
+func (c *ConfigComponent) Close() error {
56
return nil // config doesn't need to be closed.
57
}
58
61
-func (c *configComponent) Config() *config.Config {
59
+func (c *ConfigComponent) Config() *config.Config {
60
return c.config
61
}
62
63
// SetConfig updates the config file.
66
-func (c *configComponent) SetConfig(updated *config.Config) error {
64
+func (c *ConfigComponent) SetConfig(updated *config.Config) error {
65
return c.setConfigUnsynced(updated)
66
}
67
68
// GetConfigKey retrieves only the value of a particular key.
71
-func (c *configComponent) GetConfigKey(key string) (interface{}, error) {
72
- filename, err := config.Filename(c.path)
69
+func (c *ConfigComponent) GetConfigKey(key string) (interface{}, error) {
70
+ filename, err := config.Filename(c.Path)
71
if err != nil {
72
return nil, err
73
}
74
var cfg map[string]interface{}
77
- if err := readConfigFile(filename, &cfg); err != nil {
75
+ if err := serialize.ReadConfigFile(filename, &cfg); err != nil {
76
return nil, err
77
}
78
return common.MapGetKV(cfg, key)
79
}
80
81
// SetConfigKey writes the value of a particular key.
84
-func (c *configComponent) SetConfigKey(key string, value interface{}) error {
85
- filename, err := config.Filename(c.path)
82
+func (c *ConfigComponent) SetConfigKey(key string, value interface{}) error {
83
+ filename, err := config.Filename(c.Path)
84
if err != nil {
85
return err
86
}
87
var mapconf map[string]interface{}
90
- if err := readConfigFile(filename, &mapconf); err != nil {
88
+ if err := serialize.ReadConfigFile(filename, &mapconf); err != nil {
89
return err
90
}
91
if err := common.MapSetKV(mapconf, key, value); err != nil {
92
return err
93
}
96
- if err := writeConfigFile(filename, mapconf); err != nil {
94
+ if err := serialize.WriteConfigFile(filename, mapconf); err != nil {
95
return err
96
}
97
// in order to get the updated values, read updated config from the
@@ -105,9 +103,9 @@ func (c *configComponent) SetConfigKey(key string, value interface{}) error {
103
return c.setConfigUnsynced(conf) // TODO roll this into this method
104
}
105
108
-// configComponentIsInitialized returns true if the repo is initialized at
106
+// ConfigComponentIsInitialized returns true if the repo is initialized at
107
// provided |path|.
110
-func configComponentIsInitialized(path string) bool {
108
+func ConfigComponentIsInitialized(path string) bool {
109
configFilename, err := config.Filename(path)
110
if err != nil {
111
return false
@@ -119,8 +117,8 @@ func configComponentIsInitialized(path string) bool {
117
}
118
119
// setConfigUnsynced is for private use.
122
-func (r *configComponent) setConfigUnsynced(updated *config.Config) error {
123
- configFilename, err := config.Filename(r.path)
120
+func (r *ConfigComponent) setConfigUnsynced(updated *config.Config) error {
121
+ configFilename, err := config.Filename(r.Path)
122
if err != nil {
123
return err
124
}
@@ -128,7 +126,7 @@ func (r *configComponent) setConfigUnsynced(updated *config.Config) error {
126
// as a map, write the updated struct values to the map and write the map
127
// to disk.
128
var mapconf map[string]interface{}
131
- if err := readConfigFile(configFilename, &mapconf); err != nil {
129
+ if err := serialize.ReadConfigFile(configFilename, &mapconf); err != nil {
130
return err
131
}
132
m, err := config.ToMap(updated)
@@ -138,7 +136,7 @@ func (r *configComponent) setConfigUnsynced(updated *config.Config) error {
136
for k, v := range m {
137
mapconf[k] = v
138
}
141
- if err := writeConfigFile(configFilename, mapconf); err != nil {
139
+ if err := serialize.WriteConfigFile(configFilename, mapconf); err != nil {
140
return err
141
}
142
*r.config = *updated // copy so caller cannot modify this private config
repo/fsrepo/fsrepo.go
+46
-38
@@ -11,8 +11,10 @@ import (
11
12
repo "github.com/jbenet/go-ipfs/repo"
13
config "github.com/jbenet/go-ipfs/repo/config"
14
+ component "github.com/jbenet/go-ipfs/repo/fsrepo/component"
15
lockfile "github.com/jbenet/go-ipfs/repo/fsrepo/lock"
16
opener "github.com/jbenet/go-ipfs/repo/fsrepo/opener"
17
+ serialize "github.com/jbenet/go-ipfs/repo/fsrepo/serialize"
18
debugerror "github.com/jbenet/go-ipfs/util/debugerror"
19
)
20
@@ -49,22 +51,21 @@ type FSRepo struct {
51
// config is loaded when FSRepo is opened and kept up to date when the
52
// FSRepo is modified.
53
// TODO test
52
- configComponent configComponent
54
+ configComponent component.ConfigComponent
55
}
56
55
-type component interface {
56
- Open() error
57
- io.Closer
57
+type componentBuilder struct {
58
+ Init component.Initializer
59
+ IsInitialized component.InitializationChecker
60
+ OpenHandler func(*FSRepo) error
61
}
59
-type componentInitializationChecker func(path string) bool
62
63
// At returns a handle to an FSRepo at the provided |path|.
64
func At(repoPath string) *FSRepo {
65
// This method must not have side-effects.
66
return &FSRepo{
65
- path: path.Clean(repoPath),
66
- configComponent: makeConfigComponent(repoPath),
67
- state: unopened, // explicitly set for clarity
67
+ path: path.Clean(repoPath),
68
+ state: unopened, // explicitly set for clarity
69
}
70
}
71
@@ -78,7 +79,7 @@ func ConfigAt(repoPath string) (*config.Config, error) {
79
if err != nil {
80
return nil, err
81
}
81
- return load(configFilename)
82
+ return serialize.Load(configFilename)
83
}
84
85
// Init initializes a new FSRepo at the given path with the provided config.
@@ -93,10 +94,11 @@ func Init(path string, conf *config.Config) error {
94
if isInitializedUnsynced(path) {
95
return nil
96
}
96
- if err := initConfigComponent(path, conf); err != nil {
97
- return err
97
+ for _, b := range componentBuilders() {
98
+ if err := b.Init(path, conf); err != nil {
99
+ return err
100
+ }
101
}
99
-
102
return nil
103
}
104
@@ -150,21 +152,12 @@ func (r *FSRepo) Open() error {
152
return err
153
}
154
153
- for _, opener := range r.components() {
154
- if err := opener.Open(); err != nil {
155
+ for _, b := range componentBuilders() {
156
+ if err := b.OpenHandler(r); err != nil {
157
return err
158
}
159
}
160
159
- // datastore
160
- dspath, err := config.DataStorePath("")
161
- if err != nil {
162
- return err
163
- }
164
- if err := initCheckDir(dspath); err != nil {
165
- return debugerror.Errorf("datastore: %s", err)
166
- }
167
-
161
logpath, err := config.LogsPath("")
162
if err != nil {
163
return debugerror.Wrap(err)
@@ -255,18 +248,7 @@ func IsInitialized(path string) bool {
248
packageLock.Lock()
249
defer packageLock.Unlock()
250
258
- // componentInitCheckers are functions that indicate whether the component
259
- // is isInitialized
260
- var componentInitCheckers = []componentInitializationChecker{
261
- configComponentIsInitialized,
262
- // TODO add datastore component initialization checker
263
- }
264
- for _, isInitialized := range componentInitCheckers {
265
- if !isInitialized(path) {
266
- return false
267
- }
268
- }
269
- return true
251
+ return isInitializedUnsynced(path)
252
}
253
254
// private methods below this point. NB: packageLock must held by caller.
@@ -274,7 +256,12 @@ func IsInitialized(path string) bool {
256
// isInitializedUnsynced reports whether the repo is initialized. Caller must
257
// hold openerCounter lock.
258
func isInitializedUnsynced(path string) bool {
277
- return configComponentIsInitialized(path)
259
+ for _, b := range componentBuilders() {
260
+ if !b.IsInitialized(path) {
261
+ return false
262
+ }
263
+ }
264
+ return true
265
}
266
267
// initCheckDir ensures the directory exists and is writable
@@ -327,9 +314,30 @@ func transitionToClosed(r *FSRepo) error {
314
}
315
316
// components returns the FSRepo's constituent components
330
-func (r *FSRepo) components() []component {
331
- return []component{
317
+func (r *FSRepo) components() []component.Component {
318
+ return []component.Component{
319
&r.configComponent,
320
// TODO add datastore
321
}
322
}
323
+
324
+func componentBuilders() []componentBuilder {
325
+ return []componentBuilder{
326
+
327
+ // ConfigComponent
328
+ componentBuilder{
329
+ Init: component.InitConfigComponent,
330
+ IsInitialized: component.ConfigComponentIsInitialized,
331
+ OpenHandler: func(r *FSRepo) error {
332
+ cc := component.ConfigComponent{Path: r.path}
333
+ if err := cc.Open(); err != nil {
334
+ return err
335
+ }
336
+ r.configComponent = cc
337
+ return nil
338
+ },
339
+ },
340
+
341
+ // TODO add datastore builder
342
+ }
343
+}
repo/fsrepo/serialize/serialize.go
renamed
+7
-7
@@ -15,8 +15,8 @@ import (
15
16
var log = util.Logger("fsrepo")
17
18
-// readConfigFile reads the config from `filename` into `cfg`.
19
-func readConfigFile(filename string, cfg interface{}) error {
18
+// ReadConfigFile reads the config from `filename` into `cfg`.
19
+func ReadConfigFile(filename string, cfg interface{}) error {
20
f, err := os.Open(filename)
21
if err != nil {
22
return err
@@ -28,8 +28,8 @@ func readConfigFile(filename string, cfg interface{}) error {
28
return nil
29
}
30
31
-// writeConfigFile writes the config from `cfg` into `filename`.
32
-func writeConfigFile(filename string, cfg interface{}) error {
31
+// WriteConfigFile writes the config from `cfg` into `filename`.
32
+func WriteConfigFile(filename string, cfg interface{}) error {
33
err := os.MkdirAll(filepath.Dir(filename), 0775)
34
if err != nil {
35
return err
@@ -55,15 +55,15 @@ func encode(w io.Writer, value interface{}) error {
55
return err
56
}
57
58
-// load reads given file and returns the read config, or error.
59
-func load(filename string) (*config.Config, error) {
58
+// Load reads given file and returns the read config, or error.
59
+func Load(filename string) (*config.Config, error) {
60
// if nothing is there, fail. User must run 'ipfs init'
61
if !util.FileExists(filename) {
62
return nil, debugerror.New("ipfs not initialized, please run 'ipfs init'")
63
}
64
65
var cfg config.Config
66
- err := readConfigFile(filename, &cfg)
66
+ err := ReadConfigFile(filename, &cfg)
67
if err != nil {
68
return nil, err
69
}
repo/fsrepo/serialize/serialize_test.go
renamed
+2
-2
@@ -11,11 +11,11 @@ func TestConfig(t *testing.T) {
11
const dsPath = "/path/to/datastore"
12
cfgWritten := new(config.Config)
13
cfgWritten.Datastore.Path = dsPath
14
- err := writeConfigFile(filename, cfgWritten)
14
+ err := WriteConfigFile(filename, cfgWritten)
15
if err != nil {
16
t.Error(err)
17
}
18
- cfgRead, err := load(filename)
18
+ cfgRead, err := Load(filename)
19
if err != nil {
20
t.Error(err)
21
return