Skip to content

bisync: fix rc options - #10015

Open
nielash wants to merge 4 commits into
rclone:masterfrom
nielash:fix-bisync-rc-options
Open

nielash wants to merge 4 commits into
rclone:masterfrom
nielash:fix-bisync-rc-options

Conversation

@nielash

@nielash nielash commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

What does this change do?

This fixes several ways the rc sync/bisync call behaved differently from the bisync command, most of which I found while adding test coverage for the rc.

1. Global --dry-run and --max-delete ignored by the rc

applyContext, which turns the global --max-delete and --dry-run into bisync's options, was only called by the command line (in RunE). So over the rc:

  • a dry run requested through _config or the flat dry_run parameter was ignored
  • when the maxDelete parameter was omitted, the --max-delete limit was 0%

This moves applyContext into Bisync() (on its own copy of the config), so the command line, the rc, and any other caller follow the same rules. The rc's maxDelete and dryRun parameters now just set the call's config. With no --max-delete anywhere, the limit is 50%, as #5680 says the rc should be.

One deliberate choice: when a global dry run and dryRun: false are both given, the run is a dry run. dryRun can ask for a dry run, but not cancel one -- when the two disagree, bisync takes the safer option.

It also documents the maxDelete rc parameter again. It was left out when the rc help started being generated from the command's flags (72c561d), since --max-delete is a global flag.

2. --max-delete above 100 is now an error

For bisync, --max-delete is a percentage -- "in range 0..100", as Ivan put it (#5164 (comment)) -- but the range was never enforced. A value above 100 was treated as 100%, so the --max-delete check never triggered. (The empty-listing and "all files were changed" checks still stopped a run that left nothing on a side unchanged, but deleting 8 of 10 files with 2 untouched went through.)

3. Legacy backupdir1/backupdir2 and invalid values (regression in v1.74.0)

bb78eb8 corrected the casing of backupdir1/backupdir2 to backupDir1/backupDir2 and meant to keep accepting the old names, but the fallback sat inside an rc.NotErrParamNotFound(err) check, which is only true for an invalid value. So the old names had no effect unless the new name was also given with an invalid value.

The same change made an invalid value for any optional parameter (e.g. "resync": "yes") be treated as if the parameter were missing, instead of returning an error. This restores the pre-v1.74 behavior: the old names work again, and an invalid value is an error. Missing or blank enum values still get their defaults, as checkSync has since 089df7d.

4. Flag parity test

TestRcFlagParity checks that every user-facing bisync flag can be set through the rc, so the rc can't quietly fall behind the command line again (as in #7799). It sends each flag's parameter with a wrongly typed value, which every getter rcBisync uses rejects, so the call fails only if the parameter is read.

Behavior changes to note

  • --max-delete above 100 is now an error (it used to be treated as 100%).
  • Over the rc, invalid parameter values are errors again, as they were before v1.74.0.
  • Options.MaxDelete and Options.DryRun are now set by Bisync() from the config, so Go callers should set --max-delete/--dry-run through the config instead.

New tests in cmd/bisync/rc_test.go run the rc call through jobs.NewJob, so _config and flat options are applied exactly as they are under rcd.

Note for #9812: its new maxDeleteRenamesAware rc parameter uses the pattern this PR fixes, so whichever merges second will need a one-line change (return nil, err), which TestRcFlagParity will flag.

Linked issue

None for these specifically -- found while adding rc test coverage. Related: #5680, #7799, #5164

Checklist

  • This change is trivial OR it has been discussed and agreed in the linked issue.
  • I have read the contribution guidelines.
  • (If I used AI tools to help write this code) I have read and understood the AI-assisted contributions guidance, and I have tested and take ownership of this change myself.
  • I have added tests for all changes in this PR if appropriate.
  • I have added documentation for the changes if appropriate.
  • All commit messages are in house style.
  • (Backend changes only) test_all passes for this backend and if submitting a new backend can provide a test account for the integration tester - see CONTRIBUTING.md.
  • This Pull Request is ready for review.

Before this change, `--max-delete` and `--dry-run` were read from the
global config by `applyContext`, which only the command line called. The
rc `sync/bisync` call started from empty `Options` and never ran it, so it
ignored both settings:

- A dry run requested through the global option (`_config`
  `{"DryRun": true}` or the flat `dry_run` parameter) was ignored.
  `setDryRun` resets `ci.DryRun` from `opt.DryRun` before copying, and
  `opt.DryRun` was only set by bisync's own `dryRun` parameter.
- When the `maxDelete` parameter was omitted, the `--max-delete` limit was
  0%. A `max_delete` set through `_config` or the flat parameter was not
  used for that limit, and applied to the inner syncs as a file count
  instead.

After this change, `Bisync` runs `applyContext` itself, on its own copy of
the config, so the command line, the rc, and any other caller follow the
same rules, and `Options.MaxDelete` and `Options.DryRun` are set by
`Bisync`. With no `--max-delete` anywhere, the limit is 50%, as rclone#5680 says
the rc should.

The rc's `maxDelete` and `dryRun` parameters now set the call's config.
`maxDelete` overrides the global `--max-delete`. `dryRun: true` asks for a
dry run, but `dryRun: false` doesn't cancel one from the global config, so
the run is a dry run if either asks for one. The `maxDelete` parameter is
also documented again; it was left out when the rc help became generated
from the command's flags.
Before this change, bisync treated a `--max-delete` above 100 as 100%, so
the `--max-delete` check never triggered. A run that left no file on a side
unchanged was still stopped, by the "all files were changed" or empty
listing checks, but one that deleted most files while leaving even one
unchanged was not.

For bisync, `--max-delete` has always been a
percentage, "in range 0..100" as Ivan put it when he designed it
(rclone#5164 (comment)), but the
range was never enforced. So a value meant as a file count, such as
`--max-delete 500`, turned the check off. Now that the rc takes
`--max-delete` from the global config too, that includes a `--max-delete`
the rcd itself was started with.

After this change, a `--max-delete` above 100 is an error, as the rc's
`maxDelete` parameter already was.
Before this change, since v1.74.0 (bb78eb8), the rc `sync/bisync` call
read the `backupdir1` and `backupdir2` parameters (the names used before
they were renamed to `backupDir1` and `backupDir2`) only when the new name
was also given with an invalid value, because the fallback sat inside an
`rc.NotErrParamNotFound(err)` check, which is true only for an invalid
value. Otherwise, `backupdir1` and `backupdir2` had no effect.

The same change made an invalid value for any optional parameter (for
example `"resync": "yes"`, or a `filtersFile` that isn't a string) be
treated as if the parameter were missing, instead of returning an error.

After this change, the old backup dir names are read when the new ones are
missing, and an invalid value returns an error again, as it did before
v1.74.0.
Before this change, nothing checked that the rc `sync/bisync` call accepted
every bisync flag, so the rc could fall behind the command line as flags
were added, as in rclone#7799.

After this change, `TestRcFlagParity` passes each non-hidden bisync flag to
the rc, under the parameter name `rc.md` uses, with a value of the wrong
type. Every getter `rcBisync` uses rejects it, so the call fails only if
the parameter is read, and the test names any flag the rc doesn't handle.
@nielash
nielash force-pushed the fix-bisync-rc-options branch from 9d208b4 to aa1e04a Compare September 30, 2026 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

1 participant