fsrepo.go 4.02 KB
Newer Older
1 2 3
package fsrepo

import (
4
	"fmt"
5
	"io"
6 7
	"os"
	"path/filepath"
8

9 10
	repo "github.com/jbenet/go-ipfs/repo"
	common "github.com/jbenet/go-ipfs/repo/common"
11 12
	config "github.com/jbenet/go-ipfs/repo/config"
	util "github.com/jbenet/go-ipfs/util"
13
	debugerror "github.com/jbenet/go-ipfs/util/debugerror"
14 15
)

16
type FSRepo struct {
17
	state  state
18
	path   string
19
	config *config.Config
20 21 22 23
}

func At(path string) *FSRepo {
	return &FSRepo{
24 25
		path:  path,
		state: unopened, // explicitly set for clarity
26 27 28
	}
}

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
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.
44
func (r *FSRepo) Open() error {
45 46 47 48 49 50
	if r.state != unopened {
		return debugerror.Errorf("repo is %s", r.state)
	}
	if !IsInitialized(r.path) {
		return debugerror.New("repo is not initialized")
	}
51
	// check repo path, then check all constituent parts.
52
	// TODO acquire repo lock
53 54 55 56 57
	// TODO if err := initCheckDir(logpath); err != nil { // }
	if err := initCheckDir(r.path); err != nil {
		return err
	}

58 59 60 61
	configFilename, err := config.Filename(r.path)
	if err != nil {
		return err
	}
62
	conf, err := load(configFilename)
63 64 65 66 67
	if err != nil {
		return err
	}
	r.config = conf

68 69 70 71 72 73 74 75 76
	// datastore
	dspath, err := config.DataStorePath("")
	if err != nil {
		return err
	}
	if err := initCheckDir(dspath); err != nil {
		return debugerror.Errorf("datastore: %s", err)
	}

77 78 79 80 81 82 83 84
	logpath, err := config.LogsPath("")
	if err != nil {
		return debugerror.Wrap(err)
	}
	if err := initCheckDir(logpath); err != nil {
		return debugerror.Errorf("logs: %s", err)
	}

85
	r.state = opened
86 87 88
	return nil
}

89 90 91 92 93 94 95
func (r *FSRepo) Config() *config.Config {
	if r.state != opened {
		panic(fmt.Sprintln("repo is", r.state))
	}
	return r.config
}

96
func (r *FSRepo) SetConfig(conf *config.Config) error {
97 98 99
	if r.state != opened {
		panic(fmt.Sprintln("repo is", r.state))
	}
100 101 102 103
	configFilename, err := config.Filename(r.path)
	if err != nil {
		return err
	}
104
	if err := writeConfigFile(configFilename, conf); err != nil {
105 106
		return err
	}
107
	*r.config = *conf // copy so caller cannot modify the private config
108 109 110
	return nil
}

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
// GetConfigKey retrieves only the value of a particular key
func (r *FSRepo) GetConfigKey(key string) (interface{}, error) {
	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 {
	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 := convertMapToConfig(mapconf)
	if err != nil {
		return err
	}
	return r.SetConfig(conf)
}

147
func (r *FSRepo) Close() error {
148 149 150
	if r.state != opened {
		return debugerror.Errorf("repo is %s", r.state)
	}
151 152 153 154
	return nil // TODO release repo lock
}

var _ io.Closer = &FSRepo{}
155
var _ repo.Interface = &FSRepo{}
156

157 158
// IsInitialized returns true if the repo is initialized at provided |path|.
func IsInitialized(path string) bool {
159 160 161 162 163 164 165 166 167
	configFilename, err := config.Filename(path)
	if err != nil {
		return false
	}
	if !util.FileExists(configFilename) {
		return false
	}
	return true
}
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182

// 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
}