Skip to content

Commit

Permalink
Migrate to new app data directories.
Browse files Browse the repository at this point in the history
This commit makes use of the new btcutil.AppDataDir function which chooses
appropriate data directories for each supported operating system.  It also
adds code to the upgrade path to properly migrate existing data from the
old to new locations.

This is part of work toward issue #30.
  • Loading branch information
davecgh committed Nov 11, 2013
1 parent 41838b8 commit 72c186f
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 26 deletions.
27 changes: 6 additions & 21 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"github.com/conformal/btcdb"
_ "github.com/conformal/btcdb/ldb"
"github.com/conformal/btcutil"
"github.com/conformal/btcwire"
"github.com/conformal/go-flags"
"net"
Expand All @@ -20,6 +21,7 @@ import (

const (
defaultConfigFilename = "btcd.conf"
defaultDataDirname = "data"
defaultLogLevel = "info"
defaultBtcnet = btcwire.MainNet
defaultMaxPeers = 125
Expand All @@ -29,8 +31,9 @@ const (
)

var (
defaultConfigFile = filepath.Join(btcdHomeDir(), defaultConfigFilename)
defaultDataDir = filepath.Join(btcdHomeDir(), "data")
btcdHomeDir = btcutil.AppDataDir("btcd", false)
defaultConfigFile = filepath.Join(btcdHomeDir, defaultConfigFilename)
defaultDataDir = filepath.Join(btcdHomeDir, defaultDataDirname)
knownDbTypes = btcdb.SupportedDBs()
)

Expand Down Expand Up @@ -65,30 +68,12 @@ type config struct {
DebugLevel string `short:"d" long:"debuglevel" description:"Logging level {trace, debug, info, warn, error, critical}"`
}

// btcdHomeDir returns an OS appropriate home directory for btcd.
func btcdHomeDir() string {
// Search for Windows APPDATA first. This won't exist on POSIX OSes.
appData := os.Getenv("APPDATA")
if appData != "" {
return filepath.Join(appData, "btcd")
}

// Fall back to standard HOME directory that works for most POSIX OSes.
home := os.Getenv("HOME")
if home != "" {
return filepath.Join(home, ".btcd")
}

// In the worst case, use the current directory.
return "."
}

// cleanAndExpandPath expands environement variables and leading ~ in the
// passed path, cleans the result, and returns it.
func cleanAndExpandPath(path string) string {
// Expand initial ~ to OS specific home directory.
if strings.HasPrefix(path, "~") {
homeDir := filepath.Dir(btcdHomeDir())
homeDir := filepath.Dir(btcdHomeDir)
path = strings.Replace(path, "~", homeDir, 1)
}

Expand Down
7 changes: 4 additions & 3 deletions sample-btcd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

; The directory to store data such as the block chain and peer addresses. The
; block chain takes several GB, so this location must have a lot of free space.
; The default is ~/.btcd/data on POSIX OSes and $APPDATA/btcd/data on Windows.
; Environment variables are expanded so they may be used. NOTE: Windows
; The default is ~/.btcd/data on POSIX OSes, $LOCALAPPDATA/Btcd/data on Windows,
; ~/Library/Application Support/Btcd/data on Mac OS, and $home/btcd/data on
; Plan9. Environment variables are expanded so they may be used. NOTE: Windows
; environment variables are typically %VARIABLE%, but they must be accessed with
; $VARIABLE here. Also, ~ is expanded to $APPDATA on Windows.
; $VARIABLE here. Also, ~ is expanded to $LOCALAPPDATA on Windows.
; datadir=~/.btcd/data


Expand Down
105 changes: 103 additions & 2 deletions upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,46 @@
package main

import (
"io"
"os"
"path/filepath"
)

// dirEmpty returns whether or not the specified directory path is empty.
func dirEmpty(dirPath string) (bool, error) {
f, err := os.Open(dirPath)
defer f.Close()

// Read the names of a max of one entry from the directory. When the
// directory is empty, an io.EOF error will be returned, so allow it.
names, err := f.Readdirnames(1)
if err != nil && err != io.EOF {
return false, err
}

return len(names) == 0, nil
}

// oldBtcdHomeDir returns the OS specific home directory btcd used prior to
// version 0.3.3. This has since been replaced with btcutil.AppDataDir, but
// this function is still provided for the automatic upgrade path.
func oldBtcdHomeDir() string {
// Search for Windows APPDATA first. This won't exist on POSIX OSes.
appData := os.Getenv("APPDATA")
if appData != "" {
return filepath.Join(appData, "btcd")
}

// Fall back to standard HOME directory that works for most POSIX OSes.
home := os.Getenv("HOME")
if home != "" {
return filepath.Join(home, ".btcd")
}

// In the worst case, use the current directory.
return "."
}

// upgradeDBPathNet moves the database for a specific network from its
// location prior to btcd version 0.2.0 and uses heuristics to ascertain the old
// database type to rename to the new format.
Expand Down Expand Up @@ -56,7 +92,7 @@ func upgradeDBPaths() error {
// their names were suffixed by "testnet" and "regtest" for their
// respective networks. Check for the old database and update it to the
// new path introduced with version 0.2.0 accodingly.
oldDbRoot := filepath.Join(btcdHomeDir(), "db")
oldDbRoot := filepath.Join(oldBtcdHomeDir(), "db")
upgradeDBPathNet(filepath.Join(oldDbRoot, "btcd.db"), "mainnet")
upgradeDBPathNet(filepath.Join(oldDbRoot, "btcd_testnet.db"), "testnet")
upgradeDBPathNet(filepath.Join(oldDbRoot, "btcd_regtest.db"), "regtest")
Expand All @@ -70,7 +106,72 @@ func upgradeDBPaths() error {
return nil
}

// upgradeDataPaths moves the application data from its location prior to btcd
// version 0.3.3 to its new location.
func upgradeDataPaths() error {
// No need to migrate if the old and new home paths are the same.
oldHomePath := oldBtcdHomeDir()
newHomePath := btcdHomeDir
if oldHomePath == newHomePath {
return nil
}

// Only migrate if the old path exists and the new one doesn't.
if fileExists(oldHomePath) && !fileExists(newHomePath) {
// Create the new path.
log.Infof("Migrating application home path from '%s' to '%s'",
oldHomePath, newHomePath)
err := os.MkdirAll(newHomePath, 0700)
if err != nil {
return err
}

// Move old btcd.conf into new location if needed.
oldConfPath := filepath.Join(oldHomePath, defaultConfigFilename)
newConfPath := filepath.Join(newHomePath, defaultConfigFilename)
if fileExists(oldConfPath) && !fileExists(newConfPath) {
err := os.Rename(oldConfPath, newConfPath)
if err != nil {
return err
}
}

// Move old data directory into new location if needed.
oldDataPath := filepath.Join(oldHomePath, defaultDataDirname)
newDataPath := filepath.Join(newHomePath, defaultDataDirname)
if fileExists(oldDataPath) && !fileExists(newDataPath) {
err := os.Rename(oldDataPath, newDataPath)
if err != nil {
return err
}
}

// Remove the old home if it is empty or show a warning if not.
ohpEmpty, err := dirEmpty(oldHomePath)
if err != nil {
return err
}
if ohpEmpty {
err := os.Remove(oldHomePath)
if err != nil {
return err
}
} else {
log.Warnf("Not removing '%s' since it contains files "+
"not created by this application. You may "+
"want to manually move them or delete them.",
oldHomePath)
}
}

return nil
}

// doUpgrades performs upgrades to btcd as new versions require it.
func doUpgrades() error {
return upgradeDBPaths()
err := upgradeDBPaths()
if err != nil {
return err
}
return upgradeDataPaths()
}

0 comments on commit 72c186f

Please sign in to comment.