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

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

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

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

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

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

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

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

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

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

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

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

func (r *FSRepo) Close() error {
111 112 113
	if r.state != opened {
		return debugerror.Errorf("repo is %s", r.state)
	}
114 115 116 117
	return nil // TODO release repo lock
}

var _ io.Closer = &FSRepo{}
118
var _ repo.Interface = &FSRepo{}
119

120 121
// IsInitialized returns true if the repo is initialized at provided |path|.
func IsInitialized(path string) bool {
122 123 124 125 126 127 128 129 130
	configFilename, err := config.Filename(path)
	if err != nil {
		return false
	}
	if !util.FileExists(configFilename) {
		return false
	}
	return true
}
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145

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