1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-09-10 09:52:20 +08:00
Files
kubo/repo/fsrepo/fsrepo.go
Brian Tiger Chow bbaf70974d move utility method
2015-01-13 03:09:32 -08:00

196 lines
4.5 KiB
Go

package fsrepo
import (
"fmt"
"io"
"os"
"path/filepath"
repo "github.com/jbenet/go-ipfs/repo"
common "github.com/jbenet/go-ipfs/repo/common"
config "github.com/jbenet/go-ipfs/repo/config"
util "github.com/jbenet/go-ipfs/util"
debugerror "github.com/jbenet/go-ipfs/util/debugerror"
)
// FSRepo represents an IPFS FileSystem Repo
type FSRepo struct {
state state
path string
config *config.Config
}
// At returns a handle to an FSRepo at the provided |path|.
func At(path string) *FSRepo {
return &FSRepo{
path: path,
state: unopened, // explicitly set for clarity
}
}
// Init initializes a new FSRepo at the given path with the provided config.
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 { // }
if err := initCheckDir(r.path); err != nil {
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 {
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)
}
if err := initCheckDir(logpath); err != nil {
return debugerror.Errorf("logs: %s", err)
}
r.state = opened
return nil
}
// Config returns the FSRepo's config. Result is undefined if the Repo is not
// Open.
func (r *FSRepo) Config() *config.Config {
if r.state != opened {
panic(fmt.Sprintln("repo is", r.state))
}
return r.config
}
// SetConfig updates the FSRepo's 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 {
return err
}
*r.config = *conf // copy so caller cannot modify the private config
return nil
}
// GetConfigKey retrieves only the value of a particular key.
func (r *FSRepo) GetConfigKey(key string) (interface{}, error) {
if r.state != opened {
return nil, debugerror.Errorf("repo is %s", r.state)
}
filename, err := config.Filename(r.path)
if err != nil {
return nil, err
}
var cfg map[string]interface{}
if err := readConfigFile(filename, &cfg); err != nil {
return nil, err
}
return common.MapGetKV(cfg, key)
}
// SetConfigKey writes the value of a particular key.
func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
if r.state != opened {
return debugerror.Errorf("repo is %s", r.state)
}
filename, err := config.Filename(r.path)
if err != nil {
return err
}
var mapconf map[string]interface{}
if err := 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 {
return err
}
conf, err := config.FromMap(mapconf)
if err != nil {
return err
}
return r.SetConfig(conf)
}
// Close closes the FSRepo, releasing held resources.
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{}
var _ repo.Interface = &FSRepo{}
// 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
}
if !util.FileExists(configFilename) {
return false
}
return true
}
// initCheckDir ensures the directory exists and is writable
func initCheckDir(path string) error {
// Construct the path if missing
if err := os.MkdirAll(path, os.ModePerm); err != nil {
return err
}
// Check the directory is writeable
if f, err := os.Create(filepath.Join(path, "._check_writeable")); err == nil {
os.Remove(f.Name())
} else {
return debugerror.New("'" + path + "' is not writeable")
}
return nil
}