@cryptotaxi247 / kubo / commits / 9f67ede6b

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