Release v2.28.0 #304

Merged
TapTap merged 39 commits from dev into main 2026-09-20 01:17:26 +02:00
4 changed files with 12 additions and 21 deletions
Showing only changes of commit 00d628d4ba - Show all commits
+2 -6
View File
@@ -58,12 +58,8 @@ Each entry maps a case id to the aspects that may differ (`tree`, `stdout`,
```python ```python
CAVEATS = { CAVEATS = {
"max_delete": { # no known residuals at present -- the burn-down reached zero
"tree": "which destination extras survive a partial --max-delete abort " # "some_case_id": {"tree": "documented residual ... ref: RSYNC_COMPAT.md ..."},
"is deletion-order dependent and unspecified; rc=25 and the "
"number of survivors match rsync. ref: RSYNC_COMPAT.md "
"`--max-delete=NUM` row.",
},
} }
``` ```
+1 -13
View File
@@ -24,19 +24,7 @@ re-triaged when the row moves.
""" """
# case id -> {aspect: "reason (ref: RSYNC_COMPAT.md ...)"} # case id -> {aspect: "reason (ref: RSYNC_COMPAT.md ...)"}
CAVEATS = { CAVEATS = {}
# --max-delete stops the extras walk part-way and exits 25 in both
# implementations; which of the remaining extras survives depends on
# deletion order, which neither tool specifies. The exit code and the
# number of survivors match (asserted implicitly by the harness's rc
# comparison and the one-for-one diff below).
"max_delete": {
"tree": "which destination extras survive a partial --max-delete abort "
"is deletion-order dependent and unspecified; rc=25 and the "
"number of survivors match rsync. ref: RSYNC_COMPAT.md "
"`--max-delete=NUM` row.",
},
}
# Accepted aspect names (guards against typos in this file). # Accepted aspect names (guards against typos in this file).
ASPECTS = ("tree", "stdout", "extra", "rc") ASPECTS = ("tree", "stdout", "extra", "rc")
+7 -1
View File
@@ -92,6 +92,10 @@ class Case:
# rsync receives ``src + "/"``; FastSync mirrors the path it is given, so a # rsync receives ``src + "/"``; FastSync mirrors the path it is given, so a
# trailing-slash-sensitive case must hand FastSync the same form. # trailing-slash-sensitive case must hand FastSync the same form.
fs_src_suffix: str = "" fs_src_suffix: str = ""
# Some cases have an unspecified result (e.g. which extras survive a
# partial --max-delete abort): assert the case-specific invariants via
# extra_check and skip the exact-tree comparison.
compare_tree: bool = True
ci: bool = False ci: bool = False
ref: str = "" ref: str = ""
@@ -422,6 +426,7 @@ def run_differential( # noqa: PLR0913 (explicit scenario parameters)
extra_check: Optional[Callable] = None, extra_check: Optional[Callable] = None,
files_from: Optional[Tuple[str, ...]] = None, files_from: Optional[Tuple[str, ...]] = None,
fs_src_suffix: str = "", fs_src_suffix: str = "",
compare_tree: bool = True,
) -> Dict[str, object]: ) -> Dict[str, object]:
"""Run one rsync/FastSync pair and return the diff aspects. """Run one rsync/FastSync pair and return the diff aspects.
@@ -466,7 +471,7 @@ def run_differential( # noqa: PLR0913 (explicit scenario parameters)
"fastsync_rc": fs_result.returncode, "fastsync_rc": fs_result.returncode,
"rsync_stderr": rs.stderr, "rsync_stderr": rs.stderr,
"fastsync_stderr": fs_result.stderr or fs_result.stdout, "fastsync_stderr": fs_result.stderr or fs_result.stdout,
"tree": tree_diff(rroot, froot, _View()), "tree": tree_diff(rroot, froot, _View()) if compare_tree else [],
"stdout": [], "stdout": [],
"extra": [], "extra": [],
} }
@@ -491,6 +496,7 @@ def execute_case(case: Case, server) -> Dict[str, object]:
compare_modes=case.compare_modes, compare_hardlinks=case.compare_hardlinks, compare_modes=case.compare_modes, compare_hardlinks=case.compare_hardlinks,
ignore_paths=case.ignore_paths, extra_check=case.extra_check, ignore_paths=case.ignore_paths, extra_check=case.extra_check,
files_from=case.files_from, fs_src_suffix=case.fs_src_suffix, files_from=case.files_from, fs_src_suffix=case.fs_src_suffix,
compare_tree=case.compare_tree,
) )
@@ -207,7 +207,8 @@ _CASES = [
seed=seed_delete_excluded, server_args=DELETE, ref="--delete-excluded"), seed=seed_delete_excluded, server_args=DELETE, ref="--delete-excluded"),
H.Case("max_delete", "basic", ["-a", "--delete", "--max-delete=1"], H.Case("max_delete", "basic", ["-a", "--delete", "--max-delete=1"],
seed=seed_max_delete, server_args=DELETE, seed=seed_max_delete, server_args=DELETE,
extra_check=max_delete_count_check, ref="--max-delete"), extra_check=max_delete_count_check, compare_tree=False,
ref="--max-delete"),
# --- relative / dirs -------------------------------------------------- # --- relative / dirs --------------------------------------------------
H.Case("relative_general", "basic", ["-a", "-R"], layout=H.MIRROR_ABS, H.Case("relative_general", "basic", ["-a", "-R"], layout=H.MIRROR_ABS,