Expand ~ to correct home directory on all OSes.

This fixes the behavior of expanding ~ on Windows and macOS, as well
as adding support for ~otheruser to expand to the home directory of
otheruser.

Modify the default sample config to reflect the change in the meaning
of ~ on Windows, and the unintended meaning of ~ on macOS.  Include
defaults for all 3 of the major operating system classes since
uncommenting the default Unix option on macOS or Windows would change
the blockchain data directory to a non-default location.
This commit is contained in:
Josh Rickmar 2018-02-16 11:39:31 -05:00 committed by Dave Collins
parent 7056c67835
commit c6f9474348
5 changed files with 183 additions and 36 deletions

View File

@ -8,7 +8,9 @@ import (
"fmt"
"net"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
"github.com/decred/dcrd/dcrutil"
@ -47,18 +49,53 @@ func normalizeAddress(addr string) string {
return addr
}
// cleanAndExpandPath expands environement variables and leading ~ in the
// cleanAndExpandPath expands environment 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(appHomeDir)
path = strings.Replace(path, "~", homeDir, 1)
// NOTE: The os.ExpandEnv doesn't work with Windows cmd.exe-style
// %VARIABLE%, but the variables can still be expanded via POSIX-style
// $VARIABLE.
path = os.ExpandEnv(path)
if !strings.HasPrefix(path, "~") {
return filepath.Clean(path)
}
// NOTE: The os.ExpandEnv doesn't work with Windows-style %VARIABLE%,
// but they variables can still be expanded via POSIX-style $VARIABLE.
return filepath.Clean(os.ExpandEnv(path))
// Expand initial ~ to the current user's home directory, or ~otheruser
// to otheruser's home directory. On Windows, both forward and backward
// slashes can be used.
path = path[1:]
var pathSeparators string
if runtime.GOOS == "windows" {
pathSeparators = string(os.PathSeparator) + "/"
} else {
pathSeparators = string(os.PathSeparator)
}
userName := ""
if i := strings.IndexAny(path, pathSeparators); i != -1 {
userName = path[:i]
path = path[i:]
}
homeDir := ""
var u *user.User
var err error
if userName == "" {
u, err = user.Current()
} else {
u, err = user.Lookup(userName)
}
if err == nil {
homeDir = u.HomeDir
}
// Fallback to CWD if user lookup fails or user has no home directory.
if homeDir == "" {
homeDir = "."
}
return filepath.Join(homeDir, path)
}
// loadConfig initializes and parses the config using a config file and command

View File

@ -10,8 +10,10 @@ import (
"io/ioutil"
"net"
"os"
"os/user"
"path/filepath"
"regexp"
"runtime"
"strings"
"github.com/decred/dcrd/dcrjson"
@ -146,18 +148,53 @@ func normalizeAddress(addr string, useTestNet, useSimNet, useWallet bool) string
return addr
}
// cleanAndExpandPath expands environement variables and leading ~ in the
// cleanAndExpandPath expands environment 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(dcrctlHomeDir)
path = strings.Replace(path, "~", homeDir, 1)
// NOTE: The os.ExpandEnv doesn't work with Windows cmd.exe-style
// %VARIABLE%, but the variables can still be expanded via POSIX-style
// $VARIABLE.
path = os.ExpandEnv(path)
if !strings.HasPrefix(path, "~") {
return filepath.Clean(path)
}
// NOTE: The os.ExpandEnv doesn't work with Windows-style %VARIABLE%,
// but they variables can still be expanded via POSIX-style $VARIABLE.
return filepath.Clean(os.ExpandEnv(path))
// Expand initial ~ to the current user's home directory, or ~otheruser
// to otheruser's home directory. On Windows, both forward and backward
// slashes can be used.
path = path[1:]
var pathSeparators string
if runtime.GOOS == "windows" {
pathSeparators = string(os.PathSeparator) + "/"
} else {
pathSeparators = string(os.PathSeparator)
}
userName := ""
if i := strings.IndexAny(path, pathSeparators); i != -1 {
userName = path[:i]
path = path[i:]
}
homeDir := ""
var u *user.User
var err error
if userName == "" {
u, err = user.Current()
} else {
u, err = user.Lookup(userName)
}
if err == nil {
homeDir = u.HomeDir
}
// Fallback to CWD if user lookup fails or user has no home directory.
if homeDir == "" {
homeDir = "."
}
return filepath.Join(homeDir, path)
}
// filesExists reports whether the named file or directory exists.

View File

@ -10,12 +10,13 @@ import (
"fmt"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/decred/dcrd/certgen"
"github.com/decred/dcrd/dcrutil"
flags "github.com/jessevdk/go-flags"
)
@ -79,19 +80,53 @@ func main() {
}
}
// cleanAndExpandPath expands environement variables and leading ~ in the
// cleanAndExpandPath expands environment 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, "~") {
appHomeDir := dcrutil.AppDataDir("gencerts", false)
homeDir := filepath.Dir(appHomeDir)
path = strings.Replace(path, "~", homeDir, 1)
// NOTE: The os.ExpandEnv doesn't work with Windows cmd.exe-style
// %VARIABLE%, but the variables can still be expanded via POSIX-style
// $VARIABLE.
path = os.ExpandEnv(path)
if !strings.HasPrefix(path, "~") {
return filepath.Clean(path)
}
// NOTE: The os.ExpandEnv doesn't work with Windows-style %VARIABLE%,
// but they variables can still be expanded via POSIX-style $VARIABLE.
return filepath.Clean(os.ExpandEnv(path))
// Expand initial ~ to the current user's home directory, or ~otheruser
// to otheruser's home directory. On Windows, both forward and backward
// slashes can be used.
path = path[1:]
var pathSeparators string
if runtime.GOOS == "windows" {
pathSeparators = string(os.PathSeparator) + "/"
} else {
pathSeparators = string(os.PathSeparator)
}
userName := ""
if i := strings.IndexAny(path, pathSeparators); i != -1 {
userName = path[:i]
path = path[i:]
}
homeDir := ""
var u *user.User
var err error
if userName == "" {
u, err = user.Current()
} else {
u, err = user.Lookup(userName)
}
if err == nil {
homeDir = u.HomeDir
}
// Fallback to CWD if user lookup fails or user has no home directory.
if homeDir == "" {
homeDir = "."
}
return filepath.Join(homeDir, path)
}
// filesExists reports whether the named file or directory exists.

View File

@ -12,6 +12,7 @@ import (
"fmt"
"net"
"os"
"os/user"
"path/filepath"
"regexp"
"runtime"
@ -179,15 +180,50 @@ type serviceOptions struct {
// cleanAndExpandPath expands environment 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(defaultHomeDir)
path = strings.Replace(path, "~", homeDir, 1)
// NOTE: The os.ExpandEnv doesn't work with Windows cmd.exe-style
// %VARIABLE%, but the variables can still be expanded via POSIX-style
// $VARIABLE.
path = os.ExpandEnv(path)
if !strings.HasPrefix(path, "~") {
return filepath.Clean(path)
}
// NOTE: The os.ExpandEnv doesn't work with Windows-style %VARIABLE%,
// but they variables can still be expanded via POSIX-style $VARIABLE.
return filepath.Clean(os.ExpandEnv(path))
// Expand initial ~ to the current user's home directory, or ~otheruser
// to otheruser's home directory. On Windows, both forward and backward
// slashes can be used.
path = path[1:]
var pathSeparators string
if runtime.GOOS == "windows" {
pathSeparators = string(os.PathSeparator) + "/"
} else {
pathSeparators = string(os.PathSeparator)
}
userName := ""
if i := strings.IndexAny(path, pathSeparators); i != -1 {
userName = path[:i]
path = path[i:]
}
homeDir := ""
var u *user.User
var err error
if userName == "" {
u, err = user.Current()
} else {
u, err = user.Lookup(userName)
}
if err == nil {
homeDir = u.HomeDir
}
// Fallback to CWD if user lookup fails or user has no home directory.
if homeDir == "" {
homeDir = "."
}
return filepath.Join(homeDir, path)
}
// validLogLevel returns whether or not logLevel is a valid debug log level.

View File

@ -14,11 +14,13 @@ const FileContents = `[Application Options]
; 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 ~/.dcrd/data on POSIX OSes, $LOCALAPPDATA/Dcrd/data on Windows,
; ~/Library/Application Support/Dcrd/data on Mac OS, and $homed/dcrd/data on
; ~/Library/Application Support/Dcrd/data on macOS, and $homed/dcrd/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 $LOCALAPPDATA on Windows.
; datadir=~/.dcrd/data
; $VARIABLE here.
; datadir=~/.dcrd/data ; Unix
; datadir=$LOCALAPPDATA/Dcrd/data ; Windows
; datadir=~/Library/Application Support/Dcrd/data ; macOS
; ------------------------------------------------------------------------------