Repository navigation
Deglobalise rclone config #4685
Description
Activity
- changed the title
[-][Question] Using rclone as a library with concurrency (various rclone configs)[/-][+]Deglobalise rclone config[/+]on Nov 5, 2020 Deglobalise rclone config
At the moment having global config is limiting rclone's ability to run different processes concurrently.
This is not noticeable in the command line, but when using rclone via the API or as a library it is very noticeable.
Globals which need fixing
Rclone global config is registered by
rc.AddOptionand these can be seen using the rclone API withrclone rc --loopback options/getThe top level general config blocks are these - these are used for all rclone commands more or less.
- filter - filters in use for listing
- main - configures the general non-backend flags
- log - configures --log-file/format/syslog
- rc - configures remote control server (and
rclone rcd)
These config blocks are used only by the relevant commands
- dlna - configures
rclone serve dlna - ftp - configures
rclone serve ftp - http - configures
rclone serve http - mount - configures
rclone mount - sftp - configures
rclone serve sftp - vfs - configures vfs flags for rclone mount/serve
High level plan
Create a system to attach the current configuration to a
context.Context.Wherever global config is used, fetch it from the context, so instead of reading config like this
fs.Config.DryRunRead it with
fs.GetConfig(ctx).DryRunWhere
fs.GetConfigwill read the ctx looking for a key for the main config. If one isn't found then it will use the (now private) default config.This will need functions to create the new config contexts - maybe with a merge non-default values into the new config. This will enable use of rclone as a library with non-global config. So something like
myConfig := fs.NewConfig() myConfig.DryRun = true // set custom config here newCtx := fs.SetConfig(ctx)This will need a similar Set/Get function for each config block, however only the global config is widely spread througout the rclone code so there may be a neater way of doing it. This needs a bit of thought.
As part of this plan the now global config variables should be made package private so they can't be read from different packages.
Potential difficulties
Context everwhere
Rclone was started (at the time of go 1.0!) well before the
context.Contextsystem was invented. There has been some effort threading context through rclone, but there are likely more places that it needs to go. So for this change to be successful it will be necessary to thread context through more of rclone.This is by and large a mechanical process and with the right editor support it doesn't take too long.
It will generate a lot of changes though!
See: #3257 for background.
Config everywhere
fs.Configis used in 91 files in rclone so doing the change to use a context driven configuration will generate a lot of changes. Again these are mostly mechanical in nature and probably can be scripted.filter.Activeis used in 13 files.Extension work
Use command line flag strings to create the context
So instead of the above, you'd write something like
newCtx := config.FromFlags(ctx, `--dry-run --bwlimit 10M --exclude "*.jpg"`)This would enable use from the API which would make the API much more usable
These flags could then go in the backend config say as a
flagssection for each backend.- added 11 commits that reference this issue
on Nov 6, 2020 29 remaining items
@ncw Thanks for your guidance, I've mostly managed to rebase our fork onto 1.55.0. I have two questions that have come up:
-
The Fs constructors now take a context and often seem to store that context internally. The fundamental sync operations (like
syncCopyMove) also take a context. Does the Fs pluck the current filter from the context with which it was constructed, or from the context passed intosyncCopyMove? -
It looks like there is now an explicit call needed to load the config file, as my test suite is failing with many errors like this:
internal error: no config file system found. Did you call configfile.LoadConfig(ctx)?
Right now our application fakes a config file by assigning to theConfigFileGetandConfigFileSetfunction pointers. Is there a call I can make to satisfy the above error without actually loading anything from the file system?
Thanks again for all of your excellent work on this library!
-
Thanks for your guidance, I've mostly managed to rebase our fork onto 1.55.0. I have two questions that have come up:
- The Fs constructors now take a context and often seem to store that context internally. The fundamental sync operations (like
syncCopyMove) also take a context. Does the Fs pluck the current filter from the context with which it was constructed, or from the context passed intosyncCopyMove?
The
Fsonly uses the filter for things like--low-level-retries. Filters are used from the one passed intosyncCopyMove. They can of course be the same one if you want.- It looks like there is now an explicit call needed to load the config file, as my test suite is failing with many errors like this:
internal error: no config file system found. Did you call ?
Right now our application fakes a config file by assigning to theConfigFileGetandConfigFileSetfunction pointers. Is there a call I can make to satisfy the above error without actually loading anything from the file system?
You can do several things...
The easiest thing for you would be to call
SetConfigPathwith an empty string indicating no config file, then callconfigfile.LoadConfig(ctx)as well as overridingConfigFileGetandConfigFileSetas you do at the momentLine 317 in 08a2df5
func SetConfigPath(path string) (err error) { Or you can implement the richer
StorageinterfaceLine 68 in 08a2df5
type Storage interface { And then call
SetStorageto set it.Line 333 in 08a2df5
func SetData(newData Storage) { You don't need to implement all the methods - you can just copy the skeleton here
rclone/fs/config/default_storage.go
Line 3 in 08a2df5
// Default config.Storage which panics with a useful error when used And implement
GetValueandSetValueshould be enough unless you are going to callrclone config- The Fs constructors now take a context and often seem to store that context internally. The fundamental sync operations (like
Awesome, thank you! I ended up going the "implement
Storage" route and that is working beautifully. I ended up implementing the full Storage interface because it was straightforward to do in-memory; I could push it upstream as a PR that may be useful to future users embedding rclone as a library, though the implementation was so straightforward it might not be worth it.Great!
If you'd like to send the in memory Storage that would be great. Quite possibly that should be the default and it is up to users to switch it out to something else.
- added 10 commits that reference this issue
on Jul 20, 2026
Hi,
I'm using rclone as a library but so far I had to prevent concurrent access (rclone config updates).
I was wondering if there is a plan to make rclone usable with various configs in parallel.
Thanks!