diff --git a/cmd/ipfs/config.go b/cmd/ipfs/config.go index a3a10732eda0cc7ecce2dfa3ccaff53257be524c..5f600cac863b2edb93f4a7be72f67dd26be9f332 100644 --- a/cmd/ipfs/config.go +++ b/cmd/ipfs/config.go @@ -44,8 +44,12 @@ func init() { func configCmd(c *commander.Command, inp []string) error { - // todo: implement --config filename flag. - filename, err := config.Filename("") + confdir, err := getConfigDir(c.Parent) + if err != nil { + return err + } + + filename, err := config.Filename(confdir) if err != nil { return err } diff --git a/cmd/ipfs/init.go b/cmd/ipfs/init.go index f49f4a98416ce0583fdae6ae26aa2cc6cac22b52..f007972bae572a68f346df7e756f81ae4f58a58a 100644 --- a/cmd/ipfs/init.go +++ b/cmd/ipfs/init.go @@ -2,6 +2,7 @@ package main import ( "encoding/base64" + "path/filepath" "errors" "os" @@ -29,6 +30,7 @@ func init() { cmdIpfsInit.Flag.Int("b", 4096, "number of bits for keypair") cmdIpfsInit.Flag.String("p", "", "passphrase for encrypting keys") cmdIpfsInit.Flag.Bool("f", false, "force overwrite of existing config") + cmdIpfsInit.Flag.String("d", "", "Change default datastore location") } func initCmd(c *commander.Command, inp []string) error { @@ -36,19 +38,18 @@ func initCmd(c *commander.Command, inp []string) error { if err != nil { return err } - if configpath == "" { - configpath, err = u.TildeExpansion("~/.go-ipfs") - if err != nil { - return err - } - } u.POut("initializing ipfs node at %s\n", configpath) - filename, err := config.Filename(configpath + "/config") + filename, err := config.Filename(configpath) if err != nil { return errors.New("Couldn't get home directory path") } + dspath, ok := c.Flag.Lookup("d").Value.Get().(string) + if !ok { + return errors.New("failed to parse datastore flag") + } + fi, err := os.Lstat(filename) force, ok := c.Flag.Lookup("f").Value.Get().(bool) if !ok { @@ -62,13 +63,27 @@ func initCmd(c *commander.Command, inp []string) error { cfg := new(config.Config) cfg.Datastore = config.Datastore{} - dspath, err := u.TildeExpansion("~/.go-ipfs/datastore") - if err != nil { - return err + if len(dspath) == 0 { + dspath, err = config.DataStorePath("") + if err != nil { + return err + } } cfg.Datastore.Path = dspath cfg.Datastore.Type = "leveldb" + // Construct the data store if missing + if err := os.MkdirAll(dspath, os.ModePerm); err != nil { + return err + } + + // Check the directory is writeable + if f, err := os.Create(filepath.Join(dspath, "._check_writeable")); err == nil { + os.Remove(f.Name()) + } else { + return errors.New("Datastore '" + dspath + "' is not writeable") + } + cfg.Identity = config.Identity{} // setup the node addresses. @@ -114,12 +129,7 @@ func initCmd(c *commander.Command, inp []string) error { }, } - path, err := u.TildeExpansion(config.DefaultConfigFilePath) - if err != nil { - return err - } - - err = config.WriteConfigFile(path, cfg) + err = config.WriteConfigFile(filename, cfg) if err != nil { return err } diff --git a/cmd/ipfs/ipfs.go b/cmd/ipfs/ipfs.go index c160a873820b21a737e68abe40b5a83230f9033e..90de701ada3c2c8c0916a6e16af369be3d2474a3 100644 --- a/cmd/ipfs/ipfs.go +++ b/cmd/ipfs/ipfs.go @@ -53,7 +53,11 @@ Use "ipfs help <command>" for more information about a command. } func init() { - CmdIpfs.Flag.String("c", config.DefaultPathRoot, "specify config directory") + config, err := config.PathRoot() + if err != nil { + config = "" + } + CmdIpfs.Flag.String("c", config, "specify config directory") } func ipfsCmd(c *commander.Command, args []string) error { @@ -74,7 +78,12 @@ func main() { } func localNode(confdir string, online bool) (*core.IpfsNode, error) { - cfg, err := config.Load(confdir + "/config") + filename, err := config.Filename(confdir) + if err != nil { + return nil, err + } + + cfg, err := config.Load(filename) if err != nil { return nil, err } @@ -83,16 +92,19 @@ func localNode(confdir string, online bool) (*core.IpfsNode, error) { } // Gets the config "-c" flag from the command, or returns -// the empty string +// the default configuration root directory func getConfigDir(c *commander.Command) (string, error) { conf := c.Flag.Lookup("c").Value.Get() if conf == nil { - return "", nil + return config.PathRoot() } confStr, ok := conf.(string) if !ok { return "", errors.New("failed to retrieve config flag value.") } + if len(confStr) == 0 { + return config.PathRoot() + } return u.TildeExpansion(confStr) } diff --git a/config/config.go b/config/config.go index 8afdc595af48ab2006fb07da1be5bc4e156424af..31d1455c582d2e8923e30485ffe3632fe1480aca 100644 --- a/config/config.go +++ b/config/config.go @@ -6,6 +6,7 @@ import ( "encoding/base64" "errors" "os" + "path/filepath" u "github.com/jbenet/go-ipfs/util" ) @@ -42,11 +43,48 @@ type Config struct { Bootstrap []*BootstrapPeer // local nodes's bootstrap peers } -// DefaultPathRoot is the default parth for the IPFS node's root dir. const DefaultPathRoot = "~/.go-ipfs" +const DefaultConfigFile = "config" +const DefaultDataStoreDirectory = "datastore" +const EnvDir = "IPFS_DIR" + +// PathRoot returns the default configuration root directory +func PathRoot() (string, error) { + dir := os.Getenv(EnvDir) + var err error + if len(dir) == 0 { + dir, err = u.TildeExpansion(DefaultPathRoot) + } + return dir, err +} + +// Path returns the path `extension` relative to the configuration root. If an +// empty string is provided for `configroot`, the default root is used. +func Path(configroot, extension string) (string, error) { + if len(configroot) == 0 { + dir, err := PathRoot() + if err != nil { + return "", err + } else { + return filepath.Join(dir, extension), nil + } + + } else { + return filepath.Join(configroot, extension), nil + } +} + +// DataStorePath returns the default data store path given a configuration root +// (set an empty string to have the default configuration root) +func DataStorePath(configroot string) (string, error) { + return Path(configroot, DefaultDataStoreDirectory); +} -// DefaultConfigFilePath points to the ipfs node config file. -const DefaultConfigFilePath = DefaultPathRoot + "/config" +// Filename returns the configuration file path given a configuration root +// directory. If the configuration root directory is empty, use the default one +func Filename(configroot string) (string, error) { + return Path(configroot, DefaultConfigFile); +} // DecodePrivateKey is a helper to decode the users PrivateKey func (i *Identity) DecodePrivateKey(passphrase string) (crypto.PrivateKey, error) { @@ -60,30 +98,15 @@ func (i *Identity) DecodePrivateKey(passphrase string) (crypto.PrivateKey, error return x509.ParsePKCS1PrivateKey(pkb) } -// Filename returns the proper tilde expanded config filename. -func Filename(filename string) (string, error) { - if len(filename) == 0 { - filename = DefaultConfigFilePath - } - - // tilde expansion on config file - return u.TildeExpansion(filename) -} - // Load reads given file and returns the read config, or error. func Load(filename string) (*Config, error) { - filename, err := Filename(filename) - if err != nil { - return nil, err - } - // if nothing is there, fail. User must run 'ipfs init' if _, err := os.Stat(filename); os.IsNotExist(err) { return nil, errors.New("ipfs not initialized, please run 'ipfs init'") } var cfg Config - err = ReadConfigFile(filename, &cfg) + err := ReadConfigFile(filename, &cfg) if err != nil { return nil, err }