mirror of
https://github.com/rclone/rclone.git
synced 2024-11-26 02:14:42 +01:00
Make all config file variables be settable in the environment
These are set in the form RCLONE_CONFIG_remote_option where remote is the uppercased remote name and option is the uppercased config file option name. Note that RCLONE_CONFIG_remote_TYPE must be set if defining a new remote. Fixes #616
This commit is contained in:
parent
0d75d2585f
commit
f73ee5eade
6
b2/b2.go
6
b2/b2.go
@ -229,15 +229,15 @@ func NewFs(name, root string) (fs.Fs, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
account := fs.ConfigFile.MustValue(name, "account")
|
account := fs.ConfigFileGet(name, "account")
|
||||||
if account == "" {
|
if account == "" {
|
||||||
return nil, errors.New("account not found")
|
return nil, errors.New("account not found")
|
||||||
}
|
}
|
||||||
key := fs.ConfigFile.MustValue(name, "key")
|
key := fs.ConfigFileGet(name, "key")
|
||||||
if key == "" {
|
if key == "" {
|
||||||
return nil, errors.New("key not found")
|
return nil, errors.New("key not found")
|
||||||
}
|
}
|
||||||
endpoint := fs.ConfigFile.MustValue(name, "endpoint", defaultEndpoint)
|
endpoint := fs.ConfigFileGet(name, "endpoint", defaultEndpoint)
|
||||||
f := &Fs{
|
f := &Fs{
|
||||||
name: name,
|
name: name,
|
||||||
bucket: bucket,
|
bucket: bucket,
|
||||||
|
@ -29,7 +29,7 @@ When uses with the -l flag it lists the types too.
|
|||||||
`,
|
`,
|
||||||
Run: func(command *cobra.Command, args []string) {
|
Run: func(command *cobra.Command, args []string) {
|
||||||
cmd.CheckArgs(0, 0, command, args)
|
cmd.CheckArgs(0, 0, command, args)
|
||||||
remotes := fs.ConfigFile.GetSectionList()
|
remotes := fs.ConfigFileSections()
|
||||||
sort.Strings(remotes)
|
sort.Strings(remotes)
|
||||||
maxlen := 1
|
maxlen := 1
|
||||||
for _, remote := range remotes {
|
for _, remote := range remotes {
|
||||||
@ -39,7 +39,7 @@ When uses with the -l flag it lists the types too.
|
|||||||
}
|
}
|
||||||
for _, remote := range remotes {
|
for _, remote := range remotes {
|
||||||
if listLong {
|
if listLong {
|
||||||
remoteType := fs.ConfigFile.MustValue(remote, "type", "UNKNOWN")
|
remoteType := fs.ConfigFileGet(remote, "type", "UNKNOWN")
|
||||||
fmt.Printf("%-*s %s\n", maxlen+1, remote+":", remoteType)
|
fmt.Printf("%-*s %s\n", maxlen+1, remote+":", remoteType)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%s:\n", remote)
|
fmt.Printf("%s:\n", remote)
|
||||||
|
@ -48,11 +48,11 @@ func init() {
|
|||||||
|
|
||||||
// NewFs contstructs an Fs from the path, container:path
|
// NewFs contstructs an Fs from the path, container:path
|
||||||
func NewFs(name, rpath string) (fs.Fs, error) {
|
func NewFs(name, rpath string) (fs.Fs, error) {
|
||||||
mode, err := NewNameEncryptionMode(fs.ConfigFile.MustValue(name, "filename_encryption", "standard"))
|
mode, err := NewNameEncryptionMode(fs.ConfigFileGet(name, "filename_encryption", "standard"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
password := fs.ConfigFile.MustValue(name, "password", "")
|
password := fs.ConfigFileGet(name, "password", "")
|
||||||
if password == "" {
|
if password == "" {
|
||||||
return nil, errors.New("password not set in config file")
|
return nil, errors.New("password not set in config file")
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ func NewFs(name, rpath string) (fs.Fs, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to decrypt password")
|
return nil, errors.Wrap(err, "failed to decrypt password")
|
||||||
}
|
}
|
||||||
salt := fs.ConfigFile.MustValue(name, "password2", "")
|
salt := fs.ConfigFileGet(name, "password2", "")
|
||||||
if salt != "" {
|
if salt != "" {
|
||||||
salt, err = fs.Reveal(salt)
|
salt, err = fs.Reveal(salt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -71,7 +71,7 @@ func NewFs(name, rpath string) (fs.Fs, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to make cipher")
|
return nil, errors.Wrap(err, "failed to make cipher")
|
||||||
}
|
}
|
||||||
remote := fs.ConfigFile.MustValue(name, "remote")
|
remote := fs.ConfigFileGet(name, "remote")
|
||||||
if strings.HasPrefix(remote, name+":") {
|
if strings.HasPrefix(remote, name+":") {
|
||||||
return nil, errors.New("can't point crypt remote at itself - check the value of the remote setting")
|
return nil, errors.New("can't point crypt remote at itself - check the value of the remote setting")
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ func init() {
|
|||||||
// Configuration helper - called after the user has put in the defaults
|
// Configuration helper - called after the user has put in the defaults
|
||||||
func configHelper(name string) {
|
func configHelper(name string) {
|
||||||
// See if already have a token
|
// See if already have a token
|
||||||
token := fs.ConfigFile.MustValue(name, "token")
|
token := fs.ConfigFileGet(name, "token")
|
||||||
if token != "" {
|
if token != "" {
|
||||||
fmt.Printf("Already have a dropbox token - refresh?\n")
|
fmt.Printf("Already have a dropbox token - refresh?\n")
|
||||||
if !fs.Confirm() {
|
if !fs.Confirm() {
|
||||||
@ -86,9 +86,9 @@ func configHelper(name string) {
|
|||||||
token = db.AccessToken()
|
token = db.AccessToken()
|
||||||
|
|
||||||
// Stuff it in the config file if it has changed
|
// Stuff it in the config file if it has changed
|
||||||
old := fs.ConfigFile.MustValue(name, "token")
|
old := fs.ConfigFileGet(name, "token")
|
||||||
if token != old {
|
if token != old {
|
||||||
fs.ConfigFile.SetValue(name, "token", token)
|
fs.ConfigFileSet(name, "token", token)
|
||||||
fs.SaveConfig()
|
fs.SaveConfig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,11 +133,11 @@ func (f *Fs) String() string {
|
|||||||
func newDropbox(name string) (*dropbox.Dropbox, error) {
|
func newDropbox(name string) (*dropbox.Dropbox, error) {
|
||||||
db := dropbox.NewDropbox()
|
db := dropbox.NewDropbox()
|
||||||
|
|
||||||
appKey := fs.ConfigFile.MustValue(name, "app_key")
|
appKey := fs.ConfigFileGet(name, "app_key")
|
||||||
if appKey == "" {
|
if appKey == "" {
|
||||||
appKey = rcloneAppKey
|
appKey = rcloneAppKey
|
||||||
}
|
}
|
||||||
appSecret := fs.ConfigFile.MustValue(name, "app_secret")
|
appSecret := fs.ConfigFileGet(name, "app_secret")
|
||||||
if appSecret == "" {
|
if appSecret == "" {
|
||||||
appSecret = fs.MustReveal(rcloneEncryptedAppSecret)
|
appSecret = fs.MustReveal(rcloneEncryptedAppSecret)
|
||||||
}
|
}
|
||||||
@ -162,7 +162,7 @@ func NewFs(name, root string) (fs.Fs, error) {
|
|||||||
f.setRoot(root)
|
f.setRoot(root)
|
||||||
|
|
||||||
// Read the token from the config file
|
// Read the token from the config file
|
||||||
token := fs.ConfigFile.MustValue(name, "token")
|
token := fs.ConfigFileGet(name, "token")
|
||||||
|
|
||||||
// Set our custom context which enables our custom transport for timeouts etc
|
// Set our custom context which enables our custom transport for timeouts etc
|
||||||
db.SetContext(oauthutil.Context())
|
db.SetContext(oauthutil.Context())
|
||||||
|
126
fs/config.go
126
fs/config.go
@ -17,6 +17,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -47,8 +48,8 @@ const (
|
|||||||
|
|
||||||
// Global
|
// Global
|
||||||
var (
|
var (
|
||||||
// ConfigFile is the config file data structure
|
// configData is the config file data structure
|
||||||
ConfigFile *goconfig.ConfigFile
|
configData *goconfig.ConfigFile
|
||||||
// HomeDir is the home directory of the user
|
// HomeDir is the home directory of the user
|
||||||
HomeDir = configHome()
|
HomeDir = configHome()
|
||||||
// ConfigPath points to the config file
|
// ConfigPath points to the config file
|
||||||
@ -284,10 +285,10 @@ func LoadConfig() {
|
|||||||
|
|
||||||
// Load configuration file.
|
// Load configuration file.
|
||||||
var err error
|
var err error
|
||||||
ConfigFile, err = loadConfigFile()
|
configData, err = loadConfigFile()
|
||||||
if err == errorConfigFileNotFound {
|
if err == errorConfigFileNotFound {
|
||||||
Log(nil, "Config file %q not found - using defaults", ConfigPath)
|
Log(nil, "Config file %q not found - using defaults", ConfigPath)
|
||||||
ConfigFile, _ = goconfig.LoadFromReader(&bytes.Buffer{})
|
configData, _ = goconfig.LoadFromReader(&bytes.Buffer{})
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Fatalf("Failed to load config file %q: %v", ConfigPath, err)
|
log.Fatalf("Failed to load config file %q: %v", ConfigPath, err)
|
||||||
}
|
}
|
||||||
@ -483,7 +484,7 @@ func changeConfigPassword() {
|
|||||||
// if configKey has been set, the file will be encrypted.
|
// if configKey has been set, the file will be encrypted.
|
||||||
func SaveConfig() {
|
func SaveConfig() {
|
||||||
if len(configKey) == 0 {
|
if len(configKey) == 0 {
|
||||||
err := goconfig.SaveConfigFile(ConfigFile, ConfigPath)
|
err := goconfig.SaveConfigFile(configData, ConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to save config file: %v", err)
|
log.Fatalf("Failed to save config file: %v", err)
|
||||||
}
|
}
|
||||||
@ -494,7 +495,7 @@ func SaveConfig() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err := goconfig.SaveConfigData(ConfigFile, &buf)
|
err := goconfig.SaveConfigData(configData, &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to save config file: %v", err)
|
log.Fatalf("Failed to save config file: %v", err)
|
||||||
}
|
}
|
||||||
@ -545,7 +546,7 @@ func SaveConfig() {
|
|||||||
// disk first and overwrites the given value only.
|
// disk first and overwrites the given value only.
|
||||||
func ConfigSetValueAndSave(name, key, value string) (err error) {
|
func ConfigSetValueAndSave(name, key, value string) (err error) {
|
||||||
// Set the value in config in case we fail to reload it
|
// Set the value in config in case we fail to reload it
|
||||||
ConfigFile.SetValue(name, key, value)
|
configData.SetValue(name, key, value)
|
||||||
// Reload the config file
|
// Reload the config file
|
||||||
reloadedConfigFile, err := loadConfigFile()
|
reloadedConfigFile, err := loadConfigFile()
|
||||||
if err == errorConfigFileNotFound {
|
if err == errorConfigFileNotFound {
|
||||||
@ -560,7 +561,7 @@ func ConfigSetValueAndSave(name, key, value string) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Update the config file with the reloaded version
|
// Update the config file with the reloaded version
|
||||||
ConfigFile = reloadedConfigFile
|
configData = reloadedConfigFile
|
||||||
// Set the value in the reloaded version
|
// Set the value in the reloaded version
|
||||||
reloadedConfigFile.SetValue(name, key, value)
|
reloadedConfigFile.SetValue(name, key, value)
|
||||||
// Save it again
|
// Save it again
|
||||||
@ -570,7 +571,7 @@ func ConfigSetValueAndSave(name, key, value string) (err error) {
|
|||||||
|
|
||||||
// ShowRemotes shows an overview of the config file
|
// ShowRemotes shows an overview of the config file
|
||||||
func ShowRemotes() {
|
func ShowRemotes() {
|
||||||
remotes := ConfigFile.GetSectionList()
|
remotes := configData.GetSectionList()
|
||||||
if len(remotes) == 0 {
|
if len(remotes) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -578,13 +579,13 @@ func ShowRemotes() {
|
|||||||
fmt.Printf("%-20s %s\n", "Name", "Type")
|
fmt.Printf("%-20s %s\n", "Name", "Type")
|
||||||
fmt.Printf("%-20s %s\n", "====", "====")
|
fmt.Printf("%-20s %s\n", "====", "====")
|
||||||
for _, remote := range remotes {
|
for _, remote := range remotes {
|
||||||
fmt.Printf("%-20s %s\n", remote, ConfigFile.MustValue(remote, "type"))
|
fmt.Printf("%-20s %s\n", remote, ConfigFileGet(remote, "type"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChooseRemote chooses a remote name
|
// ChooseRemote chooses a remote name
|
||||||
func ChooseRemote() string {
|
func ChooseRemote() string {
|
||||||
remotes := ConfigFile.GetSectionList()
|
remotes := configData.GetSectionList()
|
||||||
sort.Strings(remotes)
|
sort.Strings(remotes)
|
||||||
return Choose("remote", remotes, nil, false)
|
return Choose("remote", remotes, nil, false)
|
||||||
}
|
}
|
||||||
@ -703,7 +704,7 @@ func ShowRemote(name string) {
|
|||||||
fmt.Printf("--------------------\n")
|
fmt.Printf("--------------------\n")
|
||||||
fmt.Printf("[%s]\n", name)
|
fmt.Printf("[%s]\n", name)
|
||||||
fs := MustFindByName(name)
|
fs := MustFindByName(name)
|
||||||
for _, key := range ConfigFile.GetKeyList(name) {
|
for _, key := range configData.GetKeyList(name) {
|
||||||
isPassword := false
|
isPassword := false
|
||||||
for _, option := range fs.Options {
|
for _, option := range fs.Options {
|
||||||
if option.Name == key && option.IsPassword {
|
if option.Name == key && option.IsPassword {
|
||||||
@ -711,7 +712,7 @@ func ShowRemote(name string) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value := ConfigFile.MustValue(name, key)
|
value := ConfigFileGet(name, key)
|
||||||
if isPassword && value != "" {
|
if isPassword && value != "" {
|
||||||
fmt.Printf("%s = *** ENCRYPTED ***\n", key)
|
fmt.Printf("%s = *** ENCRYPTED ***\n", key)
|
||||||
} else {
|
} else {
|
||||||
@ -730,7 +731,7 @@ func OkRemote(name string) bool {
|
|||||||
case 'e':
|
case 'e':
|
||||||
return false
|
return false
|
||||||
case 'd':
|
case 'd':
|
||||||
ConfigFile.DeleteSection(name)
|
configData.DeleteSection(name)
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
ErrorLog(nil, "Bad choice %c", i)
|
ErrorLog(nil, "Bad choice %c", i)
|
||||||
@ -741,7 +742,7 @@ func OkRemote(name string) bool {
|
|||||||
// MustFindByName finds the RegInfo for the remote name passed in or
|
// MustFindByName finds the RegInfo for the remote name passed in or
|
||||||
// exits with a fatal error.
|
// exits with a fatal error.
|
||||||
func MustFindByName(name string) *RegInfo {
|
func MustFindByName(name string) *RegInfo {
|
||||||
fsType := ConfigFile.MustValue(name, "type")
|
fsType := ConfigFileGet(name, "type")
|
||||||
if fsType == "" {
|
if fsType == "" {
|
||||||
log.Fatalf("Couldn't find type of fs for %q", name)
|
log.Fatalf("Couldn't find type of fs for %q", name)
|
||||||
}
|
}
|
||||||
@ -829,10 +830,10 @@ func fsOption() *Option {
|
|||||||
// NewRemote make a new remote from its name
|
// NewRemote make a new remote from its name
|
||||||
func NewRemote(name string) {
|
func NewRemote(name string) {
|
||||||
newType := ChooseOption(fsOption())
|
newType := ChooseOption(fsOption())
|
||||||
ConfigFile.SetValue(name, "type", newType)
|
configData.SetValue(name, "type", newType)
|
||||||
fs := MustFind(newType)
|
fs := MustFind(newType)
|
||||||
for _, option := range fs.Options {
|
for _, option := range fs.Options {
|
||||||
ConfigFile.SetValue(name, option.Name, ChooseOption(&option))
|
configData.SetValue(name, option.Name, ChooseOption(&option))
|
||||||
}
|
}
|
||||||
RemoteConfig(name)
|
RemoteConfig(name)
|
||||||
if OkRemote(name) {
|
if OkRemote(name) {
|
||||||
@ -849,12 +850,12 @@ func EditRemote(fs *RegInfo, name string) {
|
|||||||
for {
|
for {
|
||||||
for _, option := range fs.Options {
|
for _, option := range fs.Options {
|
||||||
key := option.Name
|
key := option.Name
|
||||||
value := ConfigFile.MustValue(name, key)
|
value := ConfigFileGet(name, key)
|
||||||
fmt.Printf("Value %q = %q\n", key, value)
|
fmt.Printf("Value %q = %q\n", key, value)
|
||||||
fmt.Printf("Edit? (y/n)>\n")
|
fmt.Printf("Edit? (y/n)>\n")
|
||||||
if Confirm() {
|
if Confirm() {
|
||||||
newValue := ChooseOption(&option)
|
newValue := ChooseOption(&option)
|
||||||
ConfigFile.SetValue(name, key, newValue)
|
configData.SetValue(name, key, newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RemoteConfig(name)
|
RemoteConfig(name)
|
||||||
@ -867,14 +868,14 @@ func EditRemote(fs *RegInfo, name string) {
|
|||||||
|
|
||||||
// DeleteRemote gets the user to delete a remote
|
// DeleteRemote gets the user to delete a remote
|
||||||
func DeleteRemote(name string) {
|
func DeleteRemote(name string) {
|
||||||
ConfigFile.DeleteSection(name)
|
configData.DeleteSection(name)
|
||||||
SaveConfig()
|
SaveConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditConfig edits the config file interactively
|
// EditConfig edits the config file interactively
|
||||||
func EditConfig() {
|
func EditConfig() {
|
||||||
for {
|
for {
|
||||||
haveRemotes := len(ConfigFile.GetSectionList()) != 0
|
haveRemotes := len(configData.GetSectionList()) != 0
|
||||||
what := []string{"eEdit existing remote", "nNew remote", "dDelete remote", "sSet configuration password", "qQuit config"}
|
what := []string{"eEdit existing remote", "nNew remote", "dDelete remote", "sSet configuration password", "qQuit config"}
|
||||||
if haveRemotes {
|
if haveRemotes {
|
||||||
fmt.Printf("Current remotes:\n\n")
|
fmt.Printf("Current remotes:\n\n")
|
||||||
@ -981,10 +982,87 @@ func Authorize(args []string) {
|
|||||||
defer DeleteRemote(name)
|
defer DeleteRemote(name)
|
||||||
|
|
||||||
// Indicate that we want fully automatic configuration.
|
// Indicate that we want fully automatic configuration.
|
||||||
ConfigFile.SetValue(name, ConfigAutomatic, "yes")
|
configData.SetValue(name, ConfigAutomatic, "yes")
|
||||||
if len(args) == 3 {
|
if len(args) == 3 {
|
||||||
ConfigFile.SetValue(name, ConfigClientID, args[1])
|
configData.SetValue(name, ConfigClientID, args[1])
|
||||||
ConfigFile.SetValue(name, ConfigClientSecret, args[2])
|
configData.SetValue(name, ConfigClientSecret, args[2])
|
||||||
}
|
}
|
||||||
fs.Config(name)
|
fs.Config(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// configToEnv converts an config section and name, eg ("myremote",
|
||||||
|
// "ignore-size") into an environment name
|
||||||
|
// "RCLONE_CONFIG_MYREMOTE_IGNORE_SIZE"
|
||||||
|
func configToEnv(section, name string) string {
|
||||||
|
return "RCLONE_CONFIG_" + strings.ToUpper(strings.Replace(section+"_"+name, "-", "_", -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigFileGet gets the config key under section returning the
|
||||||
|
// default or empty string if not set.
|
||||||
|
//
|
||||||
|
// It looks up defaults in the environment if they are present
|
||||||
|
func ConfigFileGet(section, key string, defaultVal ...string) string {
|
||||||
|
envKey := configToEnv(section, key)
|
||||||
|
newValue, found := os.LookupEnv(envKey)
|
||||||
|
if found {
|
||||||
|
defaultVal = []string{newValue}
|
||||||
|
}
|
||||||
|
return configData.MustValue(section, key, defaultVal...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigFileGetBool gets the config key under section returning the
|
||||||
|
// default or false if not set.
|
||||||
|
//
|
||||||
|
// It looks up defaults in the environment if they are present
|
||||||
|
func ConfigFileGetBool(section, key string, defaultVal ...bool) bool {
|
||||||
|
envKey := configToEnv(section, key)
|
||||||
|
newValue, found := os.LookupEnv(envKey)
|
||||||
|
if found {
|
||||||
|
newBool, err := strconv.ParseBool(newValue)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(nil, "Couldn't parse %q into bool - ignoring: %v", envKey, err)
|
||||||
|
} else {
|
||||||
|
defaultVal = []bool{newBool}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return configData.MustBool(section, key, defaultVal...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigFileGetInt gets the config key under section returning the
|
||||||
|
// default or 0 if not set.
|
||||||
|
//
|
||||||
|
// It looks up defaults in the environment if they are present
|
||||||
|
func ConfigFileGetInt(section, key string, defaultVal ...int) int {
|
||||||
|
envKey := configToEnv(section, key)
|
||||||
|
newValue, found := os.LookupEnv(envKey)
|
||||||
|
if found {
|
||||||
|
newInt, err := strconv.Atoi(newValue)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(nil, "Couldn't parse %q into int - ignoring: %v", envKey, err)
|
||||||
|
} else {
|
||||||
|
defaultVal = []int{newInt}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return configData.MustInt(section, key, defaultVal...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigFileSet sets the key in section to value. It doesn't save
|
||||||
|
// the config file.
|
||||||
|
func ConfigFileSet(section, key, value string) {
|
||||||
|
configData.SetValue(section, key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var matchEnv = regexp.MustCompile(`^RCLONE_CONFIG_(.*?)_TYPE=.*$`)
|
||||||
|
|
||||||
|
// ConfigFileSections returns the sections in the config file
|
||||||
|
// including any defined by environment variables.
|
||||||
|
func ConfigFileSections() []string {
|
||||||
|
sections := configData.GetSectionList()
|
||||||
|
for _, item := range os.Environ() {
|
||||||
|
matches := matchEnv.FindStringSubmatch(item)
|
||||||
|
if len(matches) == 2 {
|
||||||
|
sections = append(sections, strings.ToLower(matches[1]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sections
|
||||||
|
}
|
||||||
|
5
fs/fs.go
5
fs/fs.go
@ -430,9 +430,8 @@ func ParseRemote(path string) (fsInfo *RegInfo, configName, fsPath string, err e
|
|||||||
fsName, configName, fsPath = "local", "local", path
|
fsName, configName, fsPath = "local", "local", path
|
||||||
if parts != nil && !isDriveLetter(parts[1]) {
|
if parts != nil && !isDriveLetter(parts[1]) {
|
||||||
configName, fsPath = parts[1], parts[2]
|
configName, fsPath = parts[1], parts[2]
|
||||||
var err error
|
fsName = ConfigFileGet(configName, "type")
|
||||||
fsName, err = ConfigFile.GetValue(configName, "type")
|
if fsName == "" {
|
||||||
if err != nil {
|
|
||||||
return nil, "", "", ErrorNotFoundInConfigFile
|
return nil, "", "", ErrorNotFoundInConfigFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ func TestInit(t *testing.T) {
|
|||||||
fs.LoadConfig()
|
fs.LoadConfig()
|
||||||
// Set extra config if supplied
|
// Set extra config if supplied
|
||||||
for _, item := range ExtraConfig {
|
for _, item := range ExtraConfig {
|
||||||
fs.ConfigFile.SetValue(item.Name, item.Key, item.Value)
|
fs.ConfigFileSet(item.Name, item.Key, item.Value)
|
||||||
}
|
}
|
||||||
fs.Config.Verbose = *verbose
|
fs.Config.Verbose = *verbose
|
||||||
fs.Config.Quiet = !*verbose
|
fs.Config.Quiet = !*verbose
|
||||||
|
@ -62,7 +62,7 @@ func init() {
|
|||||||
Description: "Google Cloud Storage (this is not Google Drive)",
|
Description: "Google Cloud Storage (this is not Google Drive)",
|
||||||
NewFs: NewFs,
|
NewFs: NewFs,
|
||||||
Config: func(name string) {
|
Config: func(name string) {
|
||||||
if fs.ConfigFile.MustValue(name, "service_account_file") != "" {
|
if fs.ConfigFileGet(name, "service_account_file") != "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := oauthutil.Config("google cloud storage", name, storageConfig)
|
err := oauthutil.Config("google cloud storage", name, storageConfig)
|
||||||
@ -208,7 +208,7 @@ func NewFs(name, root string) (fs.Fs, error) {
|
|||||||
var oAuthClient *http.Client
|
var oAuthClient *http.Client
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
serviceAccountPath := fs.ConfigFile.MustValue(name, "service_account_file")
|
serviceAccountPath := fs.ConfigFileGet(name, "service_account_file")
|
||||||
if serviceAccountPath != "" {
|
if serviceAccountPath != "" {
|
||||||
oAuthClient, err = getServiceAccountClient(serviceAccountPath)
|
oAuthClient, err = getServiceAccountClient(serviceAccountPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -230,9 +230,9 @@ func NewFs(name, root string) (fs.Fs, error) {
|
|||||||
name: name,
|
name: name,
|
||||||
bucket: bucket,
|
bucket: bucket,
|
||||||
root: directory,
|
root: directory,
|
||||||
projectNumber: fs.ConfigFile.MustValue(name, "project_number"),
|
projectNumber: fs.ConfigFileGet(name, "project_number"),
|
||||||
objectACL: fs.ConfigFile.MustValue(name, "object_acl"),
|
objectACL: fs.ConfigFileGet(name, "object_acl"),
|
||||||
bucketACL: fs.ConfigFile.MustValue(name, "bucket_acl"),
|
bucketACL: fs.ConfigFileGet(name, "bucket_acl"),
|
||||||
}
|
}
|
||||||
if f.objectACL == "" {
|
if f.objectACL == "" {
|
||||||
f.objectACL = "private"
|
f.objectACL = "private"
|
||||||
|
@ -70,7 +70,7 @@ type Object struct {
|
|||||||
func NewFs(name, root string) (fs.Fs, error) {
|
func NewFs(name, root string) (fs.Fs, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
nounc, _ := fs.ConfigFile.GetValue(name, "nounc")
|
nounc := fs.ConfigFileGet(name, "nounc")
|
||||||
f := &Fs{
|
f := &Fs{
|
||||||
name: name,
|
name: name,
|
||||||
warned: make(map[string]struct{}),
|
warned: make(map[string]struct{}),
|
||||||
|
@ -54,15 +54,12 @@ type oldToken struct {
|
|||||||
// getToken returns the token saved in the config file under
|
// getToken returns the token saved in the config file under
|
||||||
// section name.
|
// section name.
|
||||||
func getToken(name string) (*oauth2.Token, error) {
|
func getToken(name string) (*oauth2.Token, error) {
|
||||||
tokenString, err := fs.ConfigFile.GetValue(string(name), fs.ConfigToken)
|
tokenString := fs.ConfigFileGet(name, fs.ConfigToken)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if tokenString == "" {
|
if tokenString == "" {
|
||||||
return nil, errors.New("empty token found - please run rclone config again")
|
return nil, errors.New("empty token found - please run rclone config again")
|
||||||
}
|
}
|
||||||
token := new(oauth2.Token)
|
token := new(oauth2.Token)
|
||||||
err = json.Unmarshal([]byte(tokenString), token)
|
err := json.Unmarshal([]byte(tokenString), token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -97,7 +94,7 @@ func putToken(name string, token *oauth2.Token) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tokenString := string(tokenBytes)
|
tokenString := string(tokenBytes)
|
||||||
old := fs.ConfigFile.MustValue(name, fs.ConfigToken)
|
old := fs.ConfigFileGet(name, fs.ConfigToken)
|
||||||
if tokenString != old {
|
if tokenString != old {
|
||||||
err = fs.ConfigSetValueAndSave(name, fs.ConfigToken, tokenString)
|
err = fs.ConfigSetValueAndSave(name, fs.ConfigToken, tokenString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -199,12 +196,12 @@ func Context() context.Context {
|
|||||||
// If any value is overridden, true is returned.
|
// If any value is overridden, true is returned.
|
||||||
func overrideCredentials(name string, config *oauth2.Config) bool {
|
func overrideCredentials(name string, config *oauth2.Config) bool {
|
||||||
changed := false
|
changed := false
|
||||||
ClientID := fs.ConfigFile.MustValue(name, fs.ConfigClientID)
|
ClientID := fs.ConfigFileGet(name, fs.ConfigClientID)
|
||||||
if ClientID != "" {
|
if ClientID != "" {
|
||||||
config.ClientID = ClientID
|
config.ClientID = ClientID
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
ClientSecret := fs.ConfigFile.MustValue(name, fs.ConfigClientSecret)
|
ClientSecret := fs.ConfigFileGet(name, fs.ConfigClientSecret)
|
||||||
if ClientSecret != "" {
|
if ClientSecret != "" {
|
||||||
config.ClientSecret = ClientSecret
|
config.ClientSecret = ClientSecret
|
||||||
changed = true
|
changed = true
|
||||||
@ -241,10 +238,10 @@ func NewClient(name string, config *oauth2.Config) (*http.Client, *TokenSource,
|
|||||||
// It may run an internal webserver to receive the results
|
// It may run an internal webserver to receive the results
|
||||||
func Config(id, name string, config *oauth2.Config) error {
|
func Config(id, name string, config *oauth2.Config) error {
|
||||||
changed := overrideCredentials(name, config)
|
changed := overrideCredentials(name, config)
|
||||||
automatic := fs.ConfigFile.MustValue(name, fs.ConfigAutomatic) != ""
|
automatic := fs.ConfigFileGet(name, fs.ConfigAutomatic) != ""
|
||||||
|
|
||||||
// See if already have a token
|
// See if already have a token
|
||||||
tokenString := fs.ConfigFile.MustValue(name, "token")
|
tokenString := fs.ConfigFileGet(name, "token")
|
||||||
if tokenString != "" {
|
if tokenString != "" {
|
||||||
fmt.Printf("Already have a token - refresh?\n")
|
fmt.Printf("Already have a token - refresh?\n")
|
||||||
if !fs.Confirm() {
|
if !fs.Confirm() {
|
||||||
|
18
s3/s3.go
18
s3/s3.go
@ -283,8 +283,8 @@ func s3ParsePath(path string) (bucket, directory string, err error) {
|
|||||||
func s3Connection(name string) (*s3.S3, *session.Session, error) {
|
func s3Connection(name string) (*s3.S3, *session.Session, error) {
|
||||||
// Make the auth
|
// Make the auth
|
||||||
v := credentials.Value{
|
v := credentials.Value{
|
||||||
AccessKeyID: fs.ConfigFile.MustValue(name, "access_key_id"),
|
AccessKeyID: fs.ConfigFileGet(name, "access_key_id"),
|
||||||
SecretAccessKey: fs.ConfigFile.MustValue(name, "secret_access_key"),
|
SecretAccessKey: fs.ConfigFileGet(name, "secret_access_key"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// first provider to supply a credential set "wins"
|
// first provider to supply a credential set "wins"
|
||||||
@ -307,7 +307,7 @@ func s3Connection(name string) (*s3.S3, *session.Session, error) {
|
|||||||
cred := credentials.NewChainCredentials(providers)
|
cred := credentials.NewChainCredentials(providers)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case fs.ConfigFile.MustBool(name, "env_auth", false):
|
case fs.ConfigFileGetBool(name, "env_auth", false):
|
||||||
// No need for empty checks if "env_auth" is true
|
// No need for empty checks if "env_auth" is true
|
||||||
case v.AccessKeyID == "" && v.SecretAccessKey == "":
|
case v.AccessKeyID == "" && v.SecretAccessKey == "":
|
||||||
// if no access key/secret and iam is explicitly disabled then fall back to anon interaction
|
// if no access key/secret and iam is explicitly disabled then fall back to anon interaction
|
||||||
@ -318,8 +318,8 @@ func s3Connection(name string) (*s3.S3, *session.Session, error) {
|
|||||||
return nil, nil, errors.New("secret_access_key not found")
|
return nil, nil, errors.New("secret_access_key not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint := fs.ConfigFile.MustValue(name, "endpoint")
|
endpoint := fs.ConfigFileGet(name, "endpoint")
|
||||||
region := fs.ConfigFile.MustValue(name, "region")
|
region := fs.ConfigFileGet(name, "region")
|
||||||
if region == "" && endpoint == "" {
|
if region == "" && endpoint == "" {
|
||||||
endpoint = "https://s3.amazonaws.com/"
|
endpoint = "https://s3.amazonaws.com/"
|
||||||
}
|
}
|
||||||
@ -367,11 +367,11 @@ func NewFs(name, root string) (fs.Fs, error) {
|
|||||||
c: c,
|
c: c,
|
||||||
bucket: bucket,
|
bucket: bucket,
|
||||||
ses: ses,
|
ses: ses,
|
||||||
acl: fs.ConfigFile.MustValue(name, "acl"),
|
acl: fs.ConfigFileGet(name, "acl"),
|
||||||
root: directory,
|
root: directory,
|
||||||
locationConstraint: fs.ConfigFile.MustValue(name, "location_constraint"),
|
locationConstraint: fs.ConfigFileGet(name, "location_constraint"),
|
||||||
sse: fs.ConfigFile.MustValue(name, "server_side_encryption"),
|
sse: fs.ConfigFileGet(name, "server_side_encryption"),
|
||||||
storageClass: fs.ConfigFile.MustValue(name, "storage_class"),
|
storageClass: fs.ConfigFileGet(name, "storage_class"),
|
||||||
}
|
}
|
||||||
if *s3ACL != "" {
|
if *s3ACL != "" {
|
||||||
f.acl = *s3ACL
|
f.acl = *s3ACL
|
||||||
|
@ -144,15 +144,15 @@ func parsePath(path string) (container, directory string, err error) {
|
|||||||
|
|
||||||
// swiftConnection makes a connection to swift
|
// swiftConnection makes a connection to swift
|
||||||
func swiftConnection(name string) (*swift.Connection, error) {
|
func swiftConnection(name string) (*swift.Connection, error) {
|
||||||
userName := fs.ConfigFile.MustValue(name, "user")
|
userName := fs.ConfigFileGet(name, "user")
|
||||||
if userName == "" {
|
if userName == "" {
|
||||||
return nil, errors.New("user not found")
|
return nil, errors.New("user not found")
|
||||||
}
|
}
|
||||||
apiKey := fs.ConfigFile.MustValue(name, "key")
|
apiKey := fs.ConfigFileGet(name, "key")
|
||||||
if apiKey == "" {
|
if apiKey == "" {
|
||||||
return nil, errors.New("key not found")
|
return nil, errors.New("key not found")
|
||||||
}
|
}
|
||||||
authURL := fs.ConfigFile.MustValue(name, "auth")
|
authURL := fs.ConfigFileGet(name, "auth")
|
||||||
if authURL == "" {
|
if authURL == "" {
|
||||||
return nil, errors.New("auth not found")
|
return nil, errors.New("auth not found")
|
||||||
}
|
}
|
||||||
@ -160,11 +160,11 @@ func swiftConnection(name string) (*swift.Connection, error) {
|
|||||||
UserName: userName,
|
UserName: userName,
|
||||||
ApiKey: apiKey,
|
ApiKey: apiKey,
|
||||||
AuthUrl: authURL,
|
AuthUrl: authURL,
|
||||||
AuthVersion: fs.ConfigFile.MustInt(name, "auth_version", 0),
|
AuthVersion: fs.ConfigFileGetInt(name, "auth_version", 0),
|
||||||
Tenant: fs.ConfigFile.MustValue(name, "tenant"),
|
Tenant: fs.ConfigFileGet(name, "tenant"),
|
||||||
Region: fs.ConfigFile.MustValue(name, "region"),
|
Region: fs.ConfigFileGet(name, "region"),
|
||||||
Domain: fs.ConfigFile.MustValue(name, "domain"),
|
Domain: fs.ConfigFileGet(name, "domain"),
|
||||||
TenantDomain: fs.ConfigFile.MustValue(name, "tenant_domain"),
|
TenantDomain: fs.ConfigFileGet(name, "tenant_domain"),
|
||||||
ConnectTimeout: 10 * fs.Config.ConnectTimeout, // Use the timeouts in the transport
|
ConnectTimeout: 10 * fs.Config.ConnectTimeout, // Use the timeouts in the transport
|
||||||
Timeout: 10 * fs.Config.Timeout, // Use the timeouts in the transport
|
Timeout: 10 * fs.Config.Timeout, // Use the timeouts in the transport
|
||||||
Transport: fs.Config.Transport(),
|
Transport: fs.Config.Transport(),
|
||||||
@ -191,7 +191,7 @@ func NewFsWithConnection(name, root string, c *swift.Connection) (fs.Fs, error)
|
|||||||
root: directory,
|
root: directory,
|
||||||
}
|
}
|
||||||
// StorageURL overloading
|
// StorageURL overloading
|
||||||
storageURL := fs.ConfigFile.MustValue(name, "storage_url")
|
storageURL := fs.ConfigFileGet(name, "storage_url")
|
||||||
if storageURL != "" {
|
if storageURL != "" {
|
||||||
f.c.StorageUrl = storageURL
|
f.c.StorageUrl = storageURL
|
||||||
f.c.Auth = newAuth(f.c.Auth, storageURL)
|
f.c.Auth = newAuth(f.c.Auth, storageURL)
|
||||||
|
@ -101,7 +101,7 @@ func (f *Fs) String() string {
|
|||||||
// read access token from ConfigFile string
|
// read access token from ConfigFile string
|
||||||
func getAccessToken(name string) (*oauth2.Token, error) {
|
func getAccessToken(name string) (*oauth2.Token, error) {
|
||||||
// Read the token from the config file
|
// Read the token from the config file
|
||||||
tokenConfig := fs.ConfigFile.MustValue(name, "token")
|
tokenConfig := fs.ConfigFileGet(name, "token")
|
||||||
//Get access token from config string
|
//Get access token from config string
|
||||||
decoder := json.NewDecoder(strings.NewReader(tokenConfig))
|
decoder := json.NewDecoder(strings.NewReader(tokenConfig))
|
||||||
var result *oauth2.Token
|
var result *oauth2.Token
|
||||||
|
Loading…
Reference in New Issue
Block a user