diff --git a/.travis.yml b/.travis.yml index a7a4514dd..c33b92b46 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,6 +54,7 @@ install: - pip install -U pip - pip install pylint ruff flake8 pyfakefs keyring - pip install pyqt6 dbus-python + - pip install ddt PyYAML # add ssh public / private key pair to ensure user can start ssh session to localhost for tests - ssh-keygen -b 2048 -t rsa -f /home/travis/.ssh/id_rsa -N "" - cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys diff --git a/CHANGES b/CHANGES index 61d9e08de..0a98041b7 100644 --- a/CHANGES +++ b/CHANGES @@ -61,6 +61,7 @@ Version 1.6.0-dev (development of upcoming release) * Fixed: Use LC_ALL instead of LC_TIME to set the locale * Fixed: Optimize subparsers and usage output (#2132) * Fixed: Re-design about dialog (#1936) +* Fixed: Sort rsync include/exclude options according to specificity (#561, #1420) * Fixed: Stop waking up monitor when inhibit suspend on backup starts (#714, #1090) * Fixed: Avoid shutdown confirmation dialog on Budgie and Cinnamon desktop environments (#788) * Fixed: Crash in "Manage profiles" dialog when using "qt6ct" (#2128) diff --git a/common/snapshots.py b/common/snapshots.py index 9ac77e9d5..868160cea 100644 --- a/common/snapshots.py +++ b/common/snapshots.py @@ -1467,6 +1467,8 @@ def takeSnapshot(self, sid, now, include_folders): self.setTakeSnapshotMessage(0, _('Creating backup')) + self._rsync_cmd_args = cmd + # run rsync proc = tools.Execute(cmd, # TODO @@ -2343,13 +2345,15 @@ def rsyncSuffix(self, includeFolders=None, excludeFolders=None): Returns: (list): Rsync include and exclude options. - """ - # Create exclude patterns string - rsync_exclude = self.rsyncExclude(excludeFolders) - - # Create include patterns list - rsync_include, rsync_include2 = self.rsyncInclude(includeFolders) + DEREKVEIT 2024-07-31: This method is only called in one place, + self.takeSnapshot, which itself is only called in one place in + self.backup. The excludeFolders parameter is unused and could be + removed. The includeFolders parameter is always set simply from + self.config.include() in self.backup, so the includeFolders parameter + could be eliminated too by getting it from self.config here just as the + excludes are. + """ encode = self.config.ENCODE ret = ['--chmod=Du+wx'] @@ -2360,18 +2364,143 @@ def rsyncSuffix(self, includeFolders=None, excludeFolders=None): encode.exclude(self.config._MOUNT_ROOT) ) ]) - # TODO: fix bug #561: - # after rsync_exclude we need to explicitly include files inside - # excluded folders, recursive exclude folder-content again and finally - # add the rest from rsync_include2 - ret.extend(rsync_include) - ret.extend(rsync_exclude) - ret.extend(rsync_include2) + if getattr(self.config, "SELECTIONS_MODE", "") == "sorted": + # This is ignoring the includeFolders and excludeFolders arguments. + ret.extend([f"--{option}={path}" for option, path in self.pathSelections()]) + else: + rsync_exclude = self.rsyncExclude(excludeFolders) + rsync_include, rsync_include2 = self.rsyncInclude(includeFolders) + + # TODO: fix bug #561: + # after rsync_exclude we need to explicitly include files inside excluded + # folders, recursive exclude folder-content again and finally add the + # rest from rsync_include2 + ret.extend(rsync_include) + ret.extend(rsync_exclude) + ret.extend(rsync_include2) + + # Make exclusion rather than inclusion the default. ret.append('--exclude=*') ret.append(encode.chroot) return ret + def pathSelections(self): + """Return data for the --include= and --exclude= options of rsync. + + Returns a list of (