mirror of
https://github.com/rclone/rclone.git
synced 2024-12-23 07:29:35 +01:00
config: when using auto confirm make user interaction configurable
* drive: don't run teamdrive config if auto confirm set * onedrive: don't run extra config if auto confirm set * make Confirm results customisable by config Fixes #1010
This commit is contained in:
parent
8e107b9657
commit
a30e80564d
@ -718,12 +718,16 @@ func parseExtensions(extensionsIn ...string) (extensions, mimeTypes []string, er
|
|||||||
|
|
||||||
// Figure out if the user wants to use a team drive
|
// Figure out if the user wants to use a team drive
|
||||||
func configTeamDrive(opt *Options, m configmap.Mapper, name string) error {
|
func configTeamDrive(opt *Options, m configmap.Mapper, name string) error {
|
||||||
|
// Stop if we are running non-interactive config
|
||||||
|
if fs.Config.AutoConfirm {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if opt.TeamDriveID == "" {
|
if opt.TeamDriveID == "" {
|
||||||
fmt.Printf("Configure this as a team drive?\n")
|
fmt.Printf("Configure this as a team drive?\n")
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Change current team drive ID %q?\n", opt.TeamDriveID)
|
fmt.Printf("Change current team drive ID %q?\n", opt.TeamDriveID)
|
||||||
}
|
}
|
||||||
if !config.ConfirmWithDefault(false) {
|
if !config.Confirm() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
client, err := createOAuthClient(opt, name, m)
|
client, err := createOAuthClient(opt, name, m)
|
||||||
|
@ -75,9 +75,8 @@ func init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are we running headless?
|
// Stop if we are running non-interactive config
|
||||||
if automatic, _ := m.Get(config.ConfigAutomatic); automatic != "" {
|
if fs.Config.AutoConfirm {
|
||||||
// Yes, okay we are done
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +198,7 @@ func init() {
|
|||||||
|
|
||||||
fmt.Printf("Found drive '%s' of type '%s', URL: %s\nIs that okay?\n", rootItem.Name, rootItem.ParentReference.DriveType, rootItem.WebURL)
|
fmt.Printf("Found drive '%s' of type '%s', URL: %s\nIs that okay?\n", rootItem.Name, rootItem.ParentReference.DriveType, rootItem.WebURL)
|
||||||
// This does not work, YET :)
|
// This does not work, YET :)
|
||||||
if !config.Confirm() {
|
if !config.ConfirmWithConfig(m, "config_drive_ok", true) {
|
||||||
log.Fatalf("Cancelled by user")
|
log.Fatalf("Cancelled by user")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,15 @@ For example to make a swift remote of name myremote using auto config
|
|||||||
you would do:
|
you would do:
|
||||||
|
|
||||||
rclone config create myremote swift env_auth true
|
rclone config create myremote swift env_auth true
|
||||||
|
|
||||||
|
Note that if the config process would normally ask a question the
|
||||||
|
default is taken. Each time that happens rclone will print a message
|
||||||
|
saying how to affect the value taken.
|
||||||
|
|
||||||
|
So for example if you wanted to configure a Google Drive remote but
|
||||||
|
using remote authorization you would do this:
|
||||||
|
|
||||||
|
rclone config create mydrive drive config_is_local false
|
||||||
`,
|
`,
|
||||||
RunE: func(command *cobra.Command, args []string) error {
|
RunE: func(command *cobra.Command, args []string) error {
|
||||||
cmd.CheckArgs(2, 256, command, args)
|
cmd.CheckArgs(2, 256, command, args)
|
||||||
@ -119,6 +128,11 @@ in pairs of <key> <value>.
|
|||||||
For example to update the env_auth field of a remote of name myremote you would do:
|
For example to update the env_auth field of a remote of name myremote you would do:
|
||||||
|
|
||||||
rclone config update myremote swift env_auth true
|
rclone config update myremote swift env_auth true
|
||||||
|
|
||||||
|
If the remote uses oauth the token will be updated, if you don't
|
||||||
|
require this add an extra parameter thus:
|
||||||
|
|
||||||
|
rclone config update myremote swift env_auth true config_refresh_token false
|
||||||
`,
|
`,
|
||||||
RunE: func(command *cobra.Command, args []string) error {
|
RunE: func(command *cobra.Command, args []string) error {
|
||||||
cmd.CheckArgs(3, 256, command, args)
|
cmd.CheckArgs(3, 256, command, args)
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/Unknwon/goconfig"
|
"github.com/Unknwon/goconfig"
|
||||||
"github.com/ncw/rclone/fs"
|
"github.com/ncw/rclone/fs"
|
||||||
"github.com/ncw/rclone/fs/accounting"
|
"github.com/ncw/rclone/fs/accounting"
|
||||||
|
"github.com/ncw/rclone/fs/config/configmap"
|
||||||
"github.com/ncw/rclone/fs/config/configstruct"
|
"github.com/ncw/rclone/fs/config/configstruct"
|
||||||
"github.com/ncw/rclone/fs/config/obscure"
|
"github.com/ncw/rclone/fs/config/obscure"
|
||||||
"github.com/ncw/rclone/fs/driveletter"
|
"github.com/ncw/rclone/fs/driveletter"
|
||||||
@ -57,8 +58,8 @@ const (
|
|||||||
// ConfigTokenURL is the config key used to store the token server endpoint
|
// ConfigTokenURL is the config key used to store the token server endpoint
|
||||||
ConfigTokenURL = "token_url"
|
ConfigTokenURL = "token_url"
|
||||||
|
|
||||||
// ConfigAutomatic indicates that we want non-interactive configuration
|
// ConfigAuthorize indicates that we just want "rclone authorize"
|
||||||
ConfigAutomatic = "config_automatic"
|
ConfigAuthorize = "config_authorize"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Global
|
// Global
|
||||||
@ -639,21 +640,38 @@ func Command(commands []string) byte {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfirmWithDefault asks the user for Yes or No and returns true or false.
|
|
||||||
//
|
|
||||||
// If AutoConfirm is set, it will return the Default value passed in
|
|
||||||
func ConfirmWithDefault(Default bool) bool {
|
|
||||||
if fs.Config.AutoConfirm {
|
|
||||||
return Default
|
|
||||||
}
|
|
||||||
return Command([]string{"yYes", "nNo"}) == 'y'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm asks the user for Yes or No and returns true or false
|
// Confirm asks the user for Yes or No and returns true or false
|
||||||
//
|
//
|
||||||
// If AutoConfirm is set, it will return true
|
// If AutoConfirm is set, it will return true
|
||||||
func Confirm() bool {
|
func Confirm() bool {
|
||||||
return ConfirmWithDefault(true)
|
return Command([]string{"yYes", "nNo"}) == 'y'
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfirmWithConfig asks the user for Yes or No and returns true or
|
||||||
|
// false.
|
||||||
|
//
|
||||||
|
// If AutoConfirm is set, it will look up the value in m and return
|
||||||
|
// that, but if it isn't set then it will return the Default value
|
||||||
|
// passed in
|
||||||
|
func ConfirmWithConfig(m configmap.Getter, configName string, Default bool) bool {
|
||||||
|
if fs.Config.AutoConfirm {
|
||||||
|
configString, ok := m.Get(configName)
|
||||||
|
if ok {
|
||||||
|
configValue, err := strconv.ParseBool(configString)
|
||||||
|
if err != nil {
|
||||||
|
fs.Errorf(nil, "Failed to parse config parameter %s=%q as boolean - using default %v: %v", configName, configString, Default, err)
|
||||||
|
} else {
|
||||||
|
Default = configValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
answer := "No"
|
||||||
|
if Default {
|
||||||
|
answer = "Yes"
|
||||||
|
}
|
||||||
|
fmt.Printf("Auto confirm is set: answering %s, override by setting config parameter %s=%v\n", answer, configName, !Default)
|
||||||
|
return Default
|
||||||
|
}
|
||||||
|
return Confirm()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choose one of the defaults or type a new string if newOk is set
|
// Choose one of the defaults or type a new string if newOk is set
|
||||||
@ -943,8 +961,6 @@ func CreateRemote(name string, provider string, keyValues rc.Params) error {
|
|||||||
getConfigData().DeleteSection(name)
|
getConfigData().DeleteSection(name)
|
||||||
// Set the type
|
// Set the type
|
||||||
getConfigData().SetValue(name, "type", provider)
|
getConfigData().SetValue(name, "type", provider)
|
||||||
// Show this is automatically configured
|
|
||||||
getConfigData().SetValue(name, ConfigAutomatic, "yes")
|
|
||||||
// Set the remaining values
|
// Set the remaining values
|
||||||
return UpdateRemote(name, keyValues)
|
return UpdateRemote(name, keyValues)
|
||||||
}
|
}
|
||||||
@ -1227,6 +1243,7 @@ func SetPassword() {
|
|||||||
// rclone authorize "fs name"
|
// rclone authorize "fs name"
|
||||||
// rclone authorize "fs name" "client id" "client secret"
|
// rclone authorize "fs name" "client id" "client secret"
|
||||||
func Authorize(args []string) {
|
func Authorize(args []string) {
|
||||||
|
defer suppressConfirm()()
|
||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 1, 3:
|
case 1, 3:
|
||||||
default:
|
default:
|
||||||
@ -1243,8 +1260,8 @@ func Authorize(args []string) {
|
|||||||
// Make sure we delete it
|
// Make sure we delete it
|
||||||
defer DeleteRemote(name)
|
defer DeleteRemote(name)
|
||||||
|
|
||||||
// Indicate that we want fully automatic configuration.
|
// Indicate that we are running rclone authorize
|
||||||
getConfigData().SetValue(name, ConfigAutomatic, "yes")
|
getConfigData().SetValue(name, ConfigAuthorize, "true")
|
||||||
if len(args) == 3 {
|
if len(args) == 3 {
|
||||||
getConfigData().SetValue(name, ConfigClientID, args[1])
|
getConfigData().SetValue(name, ConfigClientID, args[1])
|
||||||
getConfigData().SetValue(name, ConfigClientSecret, args[2])
|
getConfigData().SetValue(name, ConfigClientSecret, args[2])
|
||||||
|
@ -358,18 +358,26 @@ func ConfigErrorCheck(id, name string, m configmap.Mapper, errorHandler func(*ht
|
|||||||
|
|
||||||
func doConfig(id, name string, m configmap.Mapper, errorHandler func(*http.Request) AuthError, oauthConfig *oauth2.Config, offline bool, opts []oauth2.AuthCodeOption) error {
|
func doConfig(id, name string, m configmap.Mapper, errorHandler func(*http.Request) AuthError, oauthConfig *oauth2.Config, offline bool, opts []oauth2.AuthCodeOption) error {
|
||||||
oauthConfig, changed := overrideCredentials(name, m, oauthConfig)
|
oauthConfig, changed := overrideCredentials(name, m, oauthConfig)
|
||||||
auto, ok := m.Get(config.ConfigAutomatic)
|
authorizeOnlyValue, ok := m.Get(config.ConfigAuthorize)
|
||||||
automatic := ok && auto != ""
|
authorizeOnly := ok && authorizeOnlyValue != "" // set if being run by "rclone authorize"
|
||||||
|
|
||||||
// See if already have a token
|
// See if already have a token
|
||||||
tokenString, ok := m.Get("token")
|
tokenString, ok := m.Get("token")
|
||||||
if ok && tokenString != "" {
|
if ok && tokenString != "" {
|
||||||
fmt.Printf("Already have a token - refresh?\n")
|
fmt.Printf("Already have a token - refresh?\n")
|
||||||
if !config.Confirm() {
|
if !config.ConfirmWithConfig(m, "config_refresh_token", true) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ask the user whether they are using a local machine
|
||||||
|
isLocal := func() bool {
|
||||||
|
fmt.Printf("Use auto config?\n")
|
||||||
|
fmt.Printf(" * Say Y if not sure\n")
|
||||||
|
fmt.Printf(" * Say N if you are working on a remote or headless machine\n")
|
||||||
|
return config.ConfirmWithConfig(m, "config_is_local", true)
|
||||||
|
}
|
||||||
|
|
||||||
// Detect whether we should use internal web server
|
// Detect whether we should use internal web server
|
||||||
useWebServer := false
|
useWebServer := false
|
||||||
switch oauthConfig.RedirectURL {
|
switch oauthConfig.RedirectURL {
|
||||||
@ -378,14 +386,10 @@ func doConfig(id, name string, m configmap.Mapper, errorHandler func(*http.Reque
|
|||||||
fmt.Printf("Make sure your Redirect URL is set to %q in your custom config.\n", oauthConfig.RedirectURL)
|
fmt.Printf("Make sure your Redirect URL is set to %q in your custom config.\n", oauthConfig.RedirectURL)
|
||||||
}
|
}
|
||||||
useWebServer = true
|
useWebServer = true
|
||||||
if automatic {
|
if authorizeOnly {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
fmt.Printf("Use auto config?\n")
|
if !isLocal() {
|
||||||
fmt.Printf(" * Say Y if not sure\n")
|
|
||||||
fmt.Printf(" * Say N if you are working on a remote or headless machine\n")
|
|
||||||
auto := config.Confirm()
|
|
||||||
if !auto {
|
|
||||||
fmt.Printf("For this to work, you will need rclone available on a machine that has a web browser available.\n")
|
fmt.Printf("For this to work, you will need rclone available on a machine that has a web browser available.\n")
|
||||||
fmt.Printf("Execute the following on your machine:\n")
|
fmt.Printf("Execute the following on your machine:\n")
|
||||||
if changed {
|
if changed {
|
||||||
@ -407,12 +411,9 @@ func doConfig(id, name string, m configmap.Mapper, errorHandler func(*http.Reque
|
|||||||
return PutToken(name, m, token, true)
|
return PutToken(name, m, token, true)
|
||||||
}
|
}
|
||||||
case TitleBarRedirectURL:
|
case TitleBarRedirectURL:
|
||||||
useWebServer = automatic
|
useWebServer = authorizeOnly
|
||||||
if !automatic {
|
if !authorizeOnly {
|
||||||
fmt.Printf("Use auto config?\n")
|
useWebServer = isLocal()
|
||||||
fmt.Printf(" * Say Y if not sure\n")
|
|
||||||
fmt.Printf(" * Say N if you are working on a remote or headless machine or Y didn't work\n")
|
|
||||||
useWebServer = config.Confirm()
|
|
||||||
}
|
}
|
||||||
if useWebServer {
|
if useWebServer {
|
||||||
// copy the config and set to use the internal webserver
|
// copy the config and set to use the internal webserver
|
||||||
@ -479,12 +480,12 @@ func doConfig(id, name string, m configmap.Mapper, errorHandler func(*http.Reque
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Print code if we do automatic retrieval
|
// Print code if we do automatic retrieval
|
||||||
if automatic {
|
if authorizeOnly {
|
||||||
result, err := json.Marshal(token)
|
result, err := json.Marshal(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to marshal token")
|
return errors.Wrap(err, "failed to marshal token")
|
||||||
}
|
}
|
||||||
fmt.Printf("Paste the following into your remote machine --->\n%s\n<---End paste", result)
|
fmt.Printf("Paste the following into your remote machine --->\n%s\n<---End paste\n", result)
|
||||||
}
|
}
|
||||||
return PutToken(name, m, token, true)
|
return PutToken(name, m, token, true)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user