diff --git a/cmd/ipfs/init.go b/cmd/ipfs/init.go index 765afb053..4a65d18ce 100644 --- a/cmd/ipfs/init.go +++ b/cmd/ipfs/init.go @@ -78,16 +78,16 @@ IPFS and are now interfacing with the ipfs merkledag! For a short demo of what you can do, enter 'ipfs tour' ` -func initWithDefaults(configRoot string) error { - _, err := doInit(configRoot, false, nBitsForKeypairDefault) +func initWithDefaults(repoRoot string) error { + _, err := doInit(repoRoot, false, nBitsForKeypairDefault) return debugerror.Wrap(err) } -func doInit(configRoot string, force bool, nBitsForKeypair int) (interface{}, error) { +func doInit(repoRoot string, force bool, nBitsForKeypair int) (interface{}, error) { - u.POut("initializing ipfs node at %s\n", configRoot) + u.POut("initializing ipfs node at %s\n", repoRoot) - if fsrepo.ConfigIsInitialized(configRoot) && !force { + if fsrepo.IsInitialized(repoRoot) && !force { return nil, errCannotInitConfigExists } @@ -96,16 +96,23 @@ func doInit(configRoot string, force bool, nBitsForKeypair int) (interface{}, er return nil, err } - r := fsrepo.At(configRoot) - if err := r.Open(); err != nil { - return nil, err - } - if err := r.SetConfig(conf); err != nil { - return nil, err - } - if err := r.Close(); err != nil { - return nil, err + if !fsrepo.IsInitialized(repoRoot) { + if err := fsrepo.Init(repoRoot, conf); err != nil { + return nil, err + } + } else { + r := fsrepo.At(repoRoot) + if err := r.Open(); err != nil { + return nil, err + } + if err := r.SetConfig(conf); err != nil { + return nil, err + } + if err := r.Close(); err != nil { + return nil, err + } } + if err := repo.ConfigureEventLogger(conf.Logs); err != nil { return nil, err } diff --git a/cmd/ipfs/tour.go b/cmd/ipfs/tour.go index 18c8fce4b..b61cc50f7 100644 --- a/cmd/ipfs/tour.go +++ b/cmd/ipfs/tour.go @@ -9,8 +9,8 @@ import ( cmds "github.com/jbenet/go-ipfs/commands" config "github.com/jbenet/go-ipfs/repo/config" - tour "github.com/jbenet/go-ipfs/tour" fsrepo "github.com/jbenet/go-ipfs/repo/fsrepo" + tour "github.com/jbenet/go-ipfs/tour" ) var tourCmd = &cmds.Command{ @@ -188,9 +188,10 @@ func tourGet(id tour.ID) (*tour.Topic, error) { // TODO share func func writeConfig(path string, cfg *config.Config) error { - filename, err := config.Filename(path) - if err != nil { + r := fsrepo.At(path) + if err := r.Open(); err != nil { return err } - return fsrepo.WriteConfigFile(filename, cfg) + defer r.Close() + return r.SetConfig(cfg) } diff --git a/core/commands/bootstrap.go b/core/commands/bootstrap.go index 7d0a2788c..6cdda8974 100644 --- a/core/commands/bootstrap.go +++ b/core/commands/bootstrap.go @@ -5,6 +5,7 @@ import ( "io" cmds "github.com/jbenet/go-ipfs/commands" + repo "github.com/jbenet/go-ipfs/repo" config "github.com/jbenet/go-ipfs/repo/config" "github.com/jbenet/go-ipfs/repo/fsrepo" u "github.com/jbenet/go-ipfs/util" @@ -77,15 +78,12 @@ in the bootstrap list). return nil, err } - filename, err := config.Filename(req.Context().ConfigRoot) - if err != nil { - return nil, err - } - - cfg, err := req.Context().GetConfig() - if err != nil { + r := fsrepo.At(req.Context().ConfigRoot) + if err := r.Open(); err != nil { return nil, err } + defer r.Close() + cfg := r.Config() deflt, _, err := req.Option("default").Bool() if err != nil { @@ -102,7 +100,7 @@ in the bootstrap list). inputPeers = append(inputPeers, defltPeers...) } - added, err := bootstrapAdd(filename, cfg, inputPeers) + added, err := bootstrapAdd(r, cfg, inputPeers) if err != nil { return nil, err } @@ -147,15 +145,12 @@ var bootstrapRemoveCmd = &cmds.Command{ return nil, err } - filename, err := config.Filename(req.Context().ConfigRoot) - if err != nil { - return nil, err - } - - cfg, err := req.Context().GetConfig() - if err != nil { + r := fsrepo.At(req.Context().ConfigRoot) + if err := r.Open(); err != nil { return nil, err } + defer r.Close() + cfg := r.Config() all, _, err := req.Option("all").Bool() if err != nil { @@ -164,9 +159,9 @@ var bootstrapRemoveCmd = &cmds.Command{ var removed []config.BootstrapPeer if all { - removed, err = bootstrapRemoveAll(filename, cfg) + removed, err = bootstrapRemoveAll(r, cfg) } else { - removed, err = bootstrapRemove(filename, cfg, input) + removed, err = bootstrapRemove(r, cfg, input) } if err != nil { return nil, err @@ -233,7 +228,7 @@ func bootstrapWritePeers(w io.Writer, prefix string, peers []config.BootstrapPee return nil } -func bootstrapAdd(filename string, cfg *config.Config, peers []config.BootstrapPeer) ([]config.BootstrapPeer, error) { +func bootstrapAdd(r repo.Interface, cfg *config.Config, peers []config.BootstrapPeer) ([]config.BootstrapPeer, error) { added := make([]config.BootstrapPeer, 0, len(peers)) for _, peer := range peers { @@ -251,15 +246,14 @@ func bootstrapAdd(filename string, cfg *config.Config, peers []config.BootstrapP } } - err := fsrepo.WriteConfigFile(filename, cfg) - if err != nil { + if err := r.SetConfig(cfg); err != nil { return nil, err } return added, nil } -func bootstrapRemove(filename string, cfg *config.Config, toRemove []config.BootstrapPeer) ([]config.BootstrapPeer, error) { +func bootstrapRemove(r repo.Interface, cfg *config.Config, toRemove []config.BootstrapPeer) ([]config.BootstrapPeer, error) { removed := make([]config.BootstrapPeer, 0, len(toRemove)) keep := make([]config.BootstrapPeer, 0, len(cfg.Bootstrap)) @@ -279,21 +273,19 @@ func bootstrapRemove(filename string, cfg *config.Config, toRemove []config.Boot } cfg.Bootstrap = keep - err := fsrepo.WriteConfigFile(filename, cfg) - if err != nil { + if err := r.SetConfig(cfg); err != nil { return nil, err } return removed, nil } -func bootstrapRemoveAll(filename string, cfg *config.Config) ([]config.BootstrapPeer, error) { +func bootstrapRemoveAll(r repo.Interface, cfg *config.Config) ([]config.BootstrapPeer, error) { removed := make([]config.BootstrapPeer, len(cfg.Bootstrap)) copy(removed, cfg.Bootstrap) cfg.Bootstrap = nil - err := fsrepo.WriteConfigFile(filename, cfg) - if err != nil { + if err := r.SetConfig(cfg); err != nil { return nil, err } diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index fb666d869..e5e9fe825 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -1,6 +1,7 @@ package fsrepo import ( + "fmt" "io" "os" "path/filepath" @@ -11,17 +12,40 @@ import ( ) type FSRepo struct { + state state path string - config config.Config + config *config.Config } func At(path string) *FSRepo { return &FSRepo{ - path: path, + path: path, + state: unopened, // explicitly set for clarity } } +func Init(path string, conf *config.Config) error { + if IsInitialized(path) { + return nil + } + configFilename, err := config.Filename(path) + if err != nil { + return err + } + if err := writeConfigFile(configFilename, conf); err != nil { + return err + } + return nil +} + +// Open returns an error if the repo is not initialized. func (r *FSRepo) Open() error { + if r.state != unopened { + return debugerror.Errorf("repo is %s", r.state) + } + if !IsInitialized(r.path) { + return debugerror.New("repo is not initialized") + } // check repo path, then check all constituent parts. // TODO acquire repo lock // TODO if err := initCheckDir(logpath); err != nil { // } @@ -29,6 +53,16 @@ func (r *FSRepo) Open() error { return err } + configFilename, err := config.Filename(r.path) + if err != nil { + return err + } + conf, err := Load(configFilename) + if err != nil { + return err + } + r.config = conf + // datastore dspath, err := config.DataStorePath("") if err != nil { @@ -46,29 +80,43 @@ func (r *FSRepo) Open() error { return debugerror.Errorf("logs: %s", err) } + r.state = opened return nil } +func (r *FSRepo) Config() *config.Config { + if r.state != opened { + panic(fmt.Sprintln("repo is", r.state)) + } + return r.config +} + func (r *FSRepo) SetConfig(conf *config.Config) error { + if r.state != opened { + panic(fmt.Sprintln("repo is", r.state)) + } configFilename, err := config.Filename(r.path) if err != nil { return err } - if err := WriteConfigFile(configFilename, conf); err != nil { + if err := writeConfigFile(configFilename, conf); err != nil { return err } - r.config = *conf // copy so caller cannot modify the private config + *r.config = *conf // copy so caller cannot modify the private config return nil } func (r *FSRepo) Close() error { + if r.state != opened { + return debugerror.Errorf("repo is %s", r.state) + } return nil // TODO release repo lock } var _ io.Closer = &FSRepo{} -// ConfigIsInitialized returns true if the config exists in provided |path|. -func ConfigIsInitialized(path string) bool { +// IsInitialized returns true if the repo is initialized at provided |path|. +func IsInitialized(path string) bool { configFilename, err := config.Filename(path) if err != nil { return false diff --git a/repo/fsrepo/serialize.go b/repo/fsrepo/serialize.go index 5986d0f88..64d03112d 100644 --- a/repo/fsrepo/serialize.go +++ b/repo/fsrepo/serialize.go @@ -30,7 +30,7 @@ func ReadConfigFile(filename string, cfg interface{}) error { } // WriteConfigFile writes the config from `cfg` into `filename`. -func WriteConfigFile(filename string, cfg interface{}) error { +func writeConfigFile(filename string, cfg interface{}) error { err := os.MkdirAll(filepath.Dir(filename), 0775) if err != nil { return err @@ -125,7 +125,7 @@ func WriteConfigKey(filename, key string, value interface{}) error { } } - return WriteConfigFile(filename, cfg) + return writeConfigFile(filename, cfg) } // Load reads given file and returns the read config, or error. @@ -165,5 +165,5 @@ func RecordUpdateCheck(cfg *config.Config, filename string) { log.Error("config.Version.CheckPeriod not set. config broken?") } - WriteConfigFile(filename, cfg) + writeConfigFile(filename, cfg) } diff --git a/repo/fsrepo/serialize_test.go b/repo/fsrepo/serialize_test.go index 5de9674af..b2cb72a0c 100644 --- a/repo/fsrepo/serialize_test.go +++ b/repo/fsrepo/serialize_test.go @@ -11,7 +11,7 @@ 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) } diff --git a/repo/fsrepo/state.go b/repo/fsrepo/state.go new file mode 100644 index 000000000..e6ccf35c1 --- /dev/null +++ b/repo/fsrepo/state.go @@ -0,0 +1,22 @@ +package fsrepo + +type state int + +const ( + unopened = iota + opened + closed +) + +func (s state) String() string { + switch s { + case unopened: + return "unopened" + case opened: + return "opened" + case closed: + return "closed" + default: + return "invalid" + } +} diff --git a/repo/repo.go b/repo/repo.go index 6d702d9ac..22a586a78 100644 --- a/repo/repo.go +++ b/repo/repo.go @@ -1,6 +1,13 @@ package repo -import util "github.com/jbenet/go-ipfs/util" +import ( + config "github.com/jbenet/go-ipfs/repo/config" + util "github.com/jbenet/go-ipfs/util" +) + +type Interface interface { + SetConfig(*config.Config) error +} // IsInitialized returns true if the path is home to an initialized IPFS // repository.