From 9d362589233e50f9ca8befd3e9ef7f01b08e408b Mon Sep 17 00:00:00 2001 From: Dario Giovannetti Date: Sat, 14 Jan 2017 11:47:55 +0800 Subject: [PATCH] Comply with XDG Base Directory specification Fixes #868 --- docs/content/docs.md | 23 ++++++++----- fs/config.go | 80 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 78 insertions(+), 25 deletions(-) diff --git a/docs/content/docs.md b/docs/content/docs.md index 3ff35b4fe..459eeb53a 100644 --- a/docs/content/docs.md +++ b/docs/content/docs.md @@ -8,9 +8,9 @@ Configure --------- First you'll need to configure rclone. As the object storage systems -have quite complicated authentication these are kept in a config file -`.rclone.conf` in your home directory by default. (You can use the -`--config` option to choose a different config file.) +have quite complicated authentication these are kept in a config file. +(See the `--config` entry for how to find the config file and choose +its location.) The easiest way to make the config is to run rclone with the config option: @@ -281,11 +281,18 @@ they are incorrect as it would normally. ### --config=CONFIG_FILE ### -Specify the location of the rclone config file. Normally this is in -your home directory as a file called `.rclone.conf`. If you run -`rclone -h` and look at the help for the `--config` option you will -see where the default location is for you. Use this flag to override -the config location, eg `rclone --config=".myconfig" .config`. +Specify the location of the rclone config file. + +Normally the config file is in your home directory as a file called +`.config/rclone/rclone.conf` (or `.rclone.conf` if created with an +older version). If `$XDG_CONFIG_HOME` is set it will be at +`$XDG_CONFIG_HOME/rclone/rclone.conf` + +If you run `rclone -h` and look at the help for the `--config` option +you will see where the default location is for you. + +Use this flag to override the config location, eg `rclone +--config=".myconfig" .config`. ### --contimeout=TIME ### diff --git a/fs/config.go b/fs/config.go index b27e924c8..393f55d9b 100644 --- a/fs/config.go +++ b/fs/config.go @@ -16,7 +16,7 @@ import ( "log" "os" "os/user" - "path" + "path/filepath" "regexp" "sort" "strconv" @@ -31,7 +31,8 @@ import ( ) const ( - configFileName = ".rclone.conf" + configFileName = "rclone.conf" + hiddenConfigFileName = "." + configFileName // ConfigToken is the key used to store the token under ConfigToken = "token" @@ -50,10 +51,8 @@ const ( var ( // configData is the config file data structure configData *goconfig.ConfigFile - // HomeDir is the home directory of the user - HomeDir = configHome() // ConfigPath points to the config file - ConfigPath = path.Join(HomeDir, configFileName) + ConfigPath = makeConfigPath() // Config is the global config Config = &ConfigInfo{} // Flags @@ -215,25 +214,72 @@ type ConfigInfo struct { Suffix string } -// Find the config directory -func configHome() string { - // Find users home directory +// Return the path to the configuration file +func makeConfigPath() string { + // Find user's home directory usr, err := user.Current() + var homedir string if err == nil { - return usr.HomeDir + homedir = usr.HomeDir + } else { + // Fall back to reading $HOME - work around user.Current() not + // working for cross compiled binaries on OSX. + // https://github.com/golang/go/issues/6376 + homedir = os.Getenv("HOME") } - // Fall back to reading $HOME - work around user.Current() not - // working for cross compiled binaries on OSX. - // https://github.com/golang/go/issues/6376 - home := os.Getenv("HOME") - if home != "" { - return home + + // Possibly find the user's XDG config paths + // See XDG Base Directory specification + // https://specifications.freedesktop.org/basedir-spec/latest/ + xdgdir := os.Getenv("XDG_CONFIG_HOME") + var xdgcfgdir string + if xdgdir != "" { + xdgcfgdir = filepath.Join(xdgdir, "rclone") + } else if homedir != "" { + xdgdir = filepath.Join(homedir, ".config") + xdgcfgdir = filepath.Join(xdgdir, "rclone") } - ErrorLog(nil, "Couldn't find home directory or read HOME environment variable.") + + // Use $XDG_CONFIG_HOME/rclone/rclone.conf if already existing + var xdgconf string + if xdgcfgdir != "" { + xdgconf = filepath.Join(xdgcfgdir, configFileName) + _, err := os.Stat(xdgconf) + if err == nil { + return xdgconf + } + } + + // Use $HOME/.rclone.conf if already existing + var homeconf string + if homedir != "" { + homeconf = filepath.Join(homedir, hiddenConfigFileName) + _, err := os.Stat(homeconf) + if err == nil { + return homeconf + } + } + + // Try to create $XDG_CONFIG_HOME/rclone/rclone.conf + if xdgconf != "" { + // xdgconf != "" implies xdgcfgdir != "" + err := os.MkdirAll(xdgcfgdir, os.ModePerm) + if err == nil { + return xdgconf + } + } + + // Try to create $HOME/.rclone.conf + if homeconf != "" { + return homeconf + } + + // Default to ./.rclone.conf (current working directory) + ErrorLog(nil, "Couldn't find home directory or read HOME or XDG_CONFIG_HOME environment variables.") ErrorLog(nil, "Defaulting to storing config in current directory.") ErrorLog(nil, "Use -config flag to workaround.") ErrorLog(nil, "Error was: %v", err) - return "" + return hiddenConfigFileName } // LoadConfig loads the config file