mirror of
https://github.com/ipfs/kubo.git
synced 2025-09-10 14:34:24 +08:00
refactor(fsrepo) extract component.Component
This commit is contained in:
14
repo/fsrepo/component/component.go
Normal file
14
repo/fsrepo/component/component.go
Normal file
@ -0,0 +1,14 @@
|
||||
package component
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/jbenet/go-ipfs/repo/config"
|
||||
)
|
||||
|
||||
type Component interface {
|
||||
Open() error
|
||||
io.Closer
|
||||
}
|
||||
type Initializer func(path string, conf *config.Config) error
|
||||
type InitializationChecker func(path string) bool
|
@ -1,29 +1,27 @@
|
||||
package fsrepo
|
||||
package component
|
||||
|
||||
import (
|
||||
common "github.com/jbenet/go-ipfs/repo/common"
|
||||
config "github.com/jbenet/go-ipfs/repo/config"
|
||||
serialize "github.com/jbenet/go-ipfs/repo/fsrepo/serialize"
|
||||
util "github.com/jbenet/go-ipfs/util"
|
||||
)
|
||||
|
||||
var _ component = &configComponent{}
|
||||
var _ componentInitializationChecker = configComponentIsInitialized
|
||||
var _ Component = &ConfigComponent{}
|
||||
var _ Initializer = InitConfigComponent
|
||||
var _ InitializationChecker = ConfigComponentIsInitialized
|
||||
|
||||
// configComponent abstracts the config component of the FSRepo.
|
||||
// ConfigComponent abstracts the config component of the FSRepo.
|
||||
// NB: create with makeConfigComponent function.
|
||||
type configComponent struct {
|
||||
path string // required at instantiation
|
||||
// NOT THREAD-SAFE
|
||||
type ConfigComponent struct {
|
||||
Path string // required at instantiation
|
||||
config *config.Config // assigned on Open()
|
||||
}
|
||||
|
||||
// makeConfigComponent instantiates a valid configComponent.
|
||||
func makeConfigComponent(path string) configComponent {
|
||||
return configComponent{path: path}
|
||||
}
|
||||
|
||||
// fsrepoConfigInit initializes the FSRepo's configComponent.
|
||||
func initConfigComponent(path string, conf *config.Config) error {
|
||||
if configComponentIsInitialized(path) {
|
||||
// fsrepoConfigInit initializes the FSRepo's ConfigComponent.
|
||||
func InitConfigComponent(path string, conf *config.Config) error {
|
||||
if ConfigComponentIsInitialized(path) {
|
||||
return nil
|
||||
}
|
||||
configFilename, err := config.Filename(path)
|
||||
@ -33,19 +31,19 @@ func initConfigComponent(path string, conf *config.Config) error {
|
||||
// initialization is the one time when it's okay to write to the config
|
||||
// without reading the config from disk and merging any user-provided keys
|
||||
// that may exist.
|
||||
if err := writeConfigFile(configFilename, conf); err != nil {
|
||||
if err := serialize.WriteConfigFile(configFilename, conf); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Open returns an error if the config file is not present.
|
||||
func (c *configComponent) Open() error {
|
||||
configFilename, err := config.Filename(c.path)
|
||||
func (c *ConfigComponent) Open() error {
|
||||
configFilename, err := config.Filename(c.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf, err := load(configFilename)
|
||||
conf, err := serialize.Load(configFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -54,46 +52,46 @@ func (c *configComponent) Open() error {
|
||||
}
|
||||
|
||||
// Close satisfies the fsrepoComponent interface.
|
||||
func (c *configComponent) Close() error {
|
||||
func (c *ConfigComponent) Close() error {
|
||||
return nil // config doesn't need to be closed.
|
||||
}
|
||||
|
||||
func (c *configComponent) Config() *config.Config {
|
||||
func (c *ConfigComponent) Config() *config.Config {
|
||||
return c.config
|
||||
}
|
||||
|
||||
// SetConfig updates the config file.
|
||||
func (c *configComponent) SetConfig(updated *config.Config) error {
|
||||
func (c *ConfigComponent) SetConfig(updated *config.Config) error {
|
||||
return c.setConfigUnsynced(updated)
|
||||
}
|
||||
|
||||
// GetConfigKey retrieves only the value of a particular key.
|
||||
func (c *configComponent) GetConfigKey(key string) (interface{}, error) {
|
||||
filename, err := config.Filename(c.path)
|
||||
func (c *ConfigComponent) GetConfigKey(key string) (interface{}, error) {
|
||||
filename, err := config.Filename(c.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var cfg map[string]interface{}
|
||||
if err := readConfigFile(filename, &cfg); err != nil {
|
||||
if err := serialize.ReadConfigFile(filename, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return common.MapGetKV(cfg, key)
|
||||
}
|
||||
|
||||
// SetConfigKey writes the value of a particular key.
|
||||
func (c *configComponent) SetConfigKey(key string, value interface{}) error {
|
||||
filename, err := config.Filename(c.path)
|
||||
func (c *ConfigComponent) SetConfigKey(key string, value interface{}) error {
|
||||
filename, err := config.Filename(c.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var mapconf map[string]interface{}
|
||||
if err := readConfigFile(filename, &mapconf); err != nil {
|
||||
if err := serialize.ReadConfigFile(filename, &mapconf); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := common.MapSetKV(mapconf, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeConfigFile(filename, mapconf); err != nil {
|
||||
if err := serialize.WriteConfigFile(filename, mapconf); err != nil {
|
||||
return err
|
||||
}
|
||||
// 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 {
|
||||
return c.setConfigUnsynced(conf) // TODO roll this into this method
|
||||
}
|
||||
|
||||
// configComponentIsInitialized returns true if the repo is initialized at
|
||||
// ConfigComponentIsInitialized returns true if the repo is initialized at
|
||||
// provided |path|.
|
||||
func configComponentIsInitialized(path string) bool {
|
||||
func ConfigComponentIsInitialized(path string) bool {
|
||||
configFilename, err := config.Filename(path)
|
||||
if err != nil {
|
||||
return false
|
||||
@ -119,8 +117,8 @@ func configComponentIsInitialized(path string) bool {
|
||||
}
|
||||
|
||||
// setConfigUnsynced is for private use.
|
||||
func (r *configComponent) setConfigUnsynced(updated *config.Config) error {
|
||||
configFilename, err := config.Filename(r.path)
|
||||
func (r *ConfigComponent) setConfigUnsynced(updated *config.Config) error {
|
||||
configFilename, err := config.Filename(r.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -128,7 +126,7 @@ func (r *configComponent) setConfigUnsynced(updated *config.Config) error {
|
||||
// as a map, write the updated struct values to the map and write the map
|
||||
// to disk.
|
||||
var mapconf map[string]interface{}
|
||||
if err := readConfigFile(configFilename, &mapconf); err != nil {
|
||||
if err := serialize.ReadConfigFile(configFilename, &mapconf); err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := config.ToMap(updated)
|
||||
@ -138,7 +136,7 @@ func (r *configComponent) setConfigUnsynced(updated *config.Config) error {
|
||||
for k, v := range m {
|
||||
mapconf[k] = v
|
||||
}
|
||||
if err := writeConfigFile(configFilename, mapconf); err != nil {
|
||||
if err := serialize.WriteConfigFile(configFilename, mapconf); err != nil {
|
||||
return err
|
||||
}
|
||||
*r.config = *updated // copy so caller cannot modify this private config
|
@ -11,8 +11,10 @@ import (
|
||||
|
||||
repo "github.com/jbenet/go-ipfs/repo"
|
||||
config "github.com/jbenet/go-ipfs/repo/config"
|
||||
component "github.com/jbenet/go-ipfs/repo/fsrepo/component"
|
||||
lockfile "github.com/jbenet/go-ipfs/repo/fsrepo/lock"
|
||||
opener "github.com/jbenet/go-ipfs/repo/fsrepo/opener"
|
||||
serialize "github.com/jbenet/go-ipfs/repo/fsrepo/serialize"
|
||||
debugerror "github.com/jbenet/go-ipfs/util/debugerror"
|
||||
)
|
||||
|
||||
@ -49,21 +51,20 @@ type FSRepo struct {
|
||||
// config is loaded when FSRepo is opened and kept up to date when the
|
||||
// FSRepo is modified.
|
||||
// TODO test
|
||||
configComponent configComponent
|
||||
configComponent component.ConfigComponent
|
||||
}
|
||||
|
||||
type component interface {
|
||||
Open() error
|
||||
io.Closer
|
||||
type componentBuilder struct {
|
||||
Init component.Initializer
|
||||
IsInitialized component.InitializationChecker
|
||||
OpenHandler func(*FSRepo) error
|
||||
}
|
||||
type componentInitializationChecker func(path string) bool
|
||||
|
||||
// At returns a handle to an FSRepo at the provided |path|.
|
||||
func At(repoPath string) *FSRepo {
|
||||
// This method must not have side-effects.
|
||||
return &FSRepo{
|
||||
path: path.Clean(repoPath),
|
||||
configComponent: makeConfigComponent(repoPath),
|
||||
state: unopened, // explicitly set for clarity
|
||||
}
|
||||
}
|
||||
@ -78,7 +79,7 @@ func ConfigAt(repoPath string) (*config.Config, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return load(configFilename)
|
||||
return serialize.Load(configFilename)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if isInitializedUnsynced(path) {
|
||||
return nil
|
||||
}
|
||||
if err := initConfigComponent(path, conf); err != nil {
|
||||
for _, b := range componentBuilders() {
|
||||
if err := b.Init(path, conf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -150,21 +152,12 @@ func (r *FSRepo) Open() error {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, opener := range r.components() {
|
||||
if err := opener.Open(); err != nil {
|
||||
for _, b := range componentBuilders() {
|
||||
if err := b.OpenHandler(r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// datastore
|
||||
dspath, err := config.DataStorePath("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := initCheckDir(dspath); err != nil {
|
||||
return debugerror.Errorf("datastore: %s", err)
|
||||
}
|
||||
|
||||
logpath, err := config.LogsPath("")
|
||||
if err != nil {
|
||||
return debugerror.Wrap(err)
|
||||
@ -255,18 +248,7 @@ func IsInitialized(path string) bool {
|
||||
packageLock.Lock()
|
||||
defer packageLock.Unlock()
|
||||
|
||||
// componentInitCheckers are functions that indicate whether the component
|
||||
// is isInitialized
|
||||
var componentInitCheckers = []componentInitializationChecker{
|
||||
configComponentIsInitialized,
|
||||
// TODO add datastore component initialization checker
|
||||
}
|
||||
for _, isInitialized := range componentInitCheckers {
|
||||
if !isInitialized(path) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
return isInitializedUnsynced(path)
|
||||
}
|
||||
|
||||
// private methods below this point. NB: packageLock must held by caller.
|
||||
@ -274,7 +256,12 @@ func IsInitialized(path string) bool {
|
||||
// isInitializedUnsynced reports whether the repo is initialized. Caller must
|
||||
// hold openerCounter lock.
|
||||
func isInitializedUnsynced(path string) bool {
|
||||
return configComponentIsInitialized(path)
|
||||
for _, b := range componentBuilders() {
|
||||
if !b.IsInitialized(path) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// initCheckDir ensures the directory exists and is writable
|
||||
@ -327,9 +314,30 @@ func transitionToClosed(r *FSRepo) error {
|
||||
}
|
||||
|
||||
// components returns the FSRepo's constituent components
|
||||
func (r *FSRepo) components() []component {
|
||||
return []component{
|
||||
func (r *FSRepo) components() []component.Component {
|
||||
return []component.Component{
|
||||
&r.configComponent,
|
||||
// TODO add datastore
|
||||
}
|
||||
}
|
||||
|
||||
func componentBuilders() []componentBuilder {
|
||||
return []componentBuilder{
|
||||
|
||||
// ConfigComponent
|
||||
componentBuilder{
|
||||
Init: component.InitConfigComponent,
|
||||
IsInitialized: component.ConfigComponentIsInitialized,
|
||||
OpenHandler: func(r *FSRepo) error {
|
||||
cc := component.ConfigComponent{Path: r.path}
|
||||
if err := cc.Open(); err != nil {
|
||||
return err
|
||||
}
|
||||
r.configComponent = cc
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
||||
// TODO add datastore builder
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,8 @@ import (
|
||||
|
||||
var log = util.Logger("fsrepo")
|
||||
|
||||
// readConfigFile reads the config from `filename` into `cfg`.
|
||||
func readConfigFile(filename string, cfg interface{}) error {
|
||||
// ReadConfigFile reads the config from `filename` into `cfg`.
|
||||
func ReadConfigFile(filename string, cfg interface{}) error {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -28,8 +28,8 @@ func readConfigFile(filename string, cfg interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeConfigFile writes the config from `cfg` into `filename`.
|
||||
func writeConfigFile(filename string, cfg interface{}) error {
|
||||
// WriteConfigFile writes the config from `cfg` into `filename`.
|
||||
func WriteConfigFile(filename string, cfg interface{}) error {
|
||||
err := os.MkdirAll(filepath.Dir(filename), 0775)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -55,15 +55,15 @@ func encode(w io.Writer, value interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// load reads given file and returns the read config, or error.
|
||||
func load(filename string) (*config.Config, error) {
|
||||
// Load reads given file and returns the read config, or error.
|
||||
func Load(filename string) (*config.Config, error) {
|
||||
// if nothing is there, fail. User must run 'ipfs init'
|
||||
if !util.FileExists(filename) {
|
||||
return nil, debugerror.New("ipfs not initialized, please run 'ipfs init'")
|
||||
}
|
||||
|
||||
var cfg config.Config
|
||||
err := readConfigFile(filename, &cfg)
|
||||
err := ReadConfigFile(filename, &cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
@ -11,11 +11,11 @@ func TestConfig(t *testing.T) {
|
||||
const dsPath = "/path/to/datastore"
|
||||
cfgWritten := new(config.Config)
|
||||
cfgWritten.Datastore.Path = dsPath
|
||||
err := writeConfigFile(filename, cfgWritten)
|
||||
err := WriteConfigFile(filename, cfgWritten)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cfgRead, err := load(filename)
|
||||
cfgRead, err := Load(filename)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
Reference in New Issue
Block a user