Skip to content

Commit 03683a9

Browse files
committed
Update PR
* Update PR
1 parent 071db82 commit 03683a9

2 files changed

Lines changed: 79 additions & 27 deletions

File tree

docs/end_to_end_testing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Placeholder document that will detail all test cases and coverage
44

5-
| <div style="width: 110px;">Test Case</div> | Description | Details |
5+
| Test Case | Description | Details |
66
|:---|:---|:---|
77
| 0001 | Basic Resync | - validate that the E2E framework can invoke the client<br> - validate that the configured environment is sufficient to run a basic sync<br> - provide a simple baseline smoke test before more advanced E2E scenarios |
88
| 0002 | 'sync_list' Validation | This validates sync_list as a policy-conformance test.<br><br>The test is considered successful when all observed sync operations involving the fixture tree match the active sync_list rules.<br><br>This test covers exclusions, inclusions, wildcard and globbing for paths and files. Specific 'sync_list' test coverage is as follows:<br>- Scenario SL-0001: root directory include with trailing slash<br>- Scenario SL-0002: root include without trailing slash<br>- Scenario SL-0003: non-root include by name<br>- Scenario SL-0004: include tree with nested exclusion<br>- Scenario SL-0005: included tree with hidden directory excluded<br>- Scenario SL-0006: file-specific include inside named directory<br>- Scenario SL-0007: rooted include of Programming tree<br>- Scenario SL-0008: exclude Android recursive build output and include Programming<br>- Scenario SL-0009: exclude Android recursive .cxx content and include Programming<br>- Scenario SL-0010: exclude Web recursive build output and include Programming<br>- Scenario SL-0011: exclude .gradle anywhere and include Programming<br>- Scenario SL-0012: exclude build/kotlin anywhere and include Programming<br>- Scenario SL-0013: exclude .venv and venv anywhere and include Programming<br>- Scenario SL-0014: exclude common cache and vendor directories and include Programming<br>- Scenario SL-0015: complex style Programming ruleset<br>- Scenario SL-0016: massive mixed rule set across Programming Documents and Work<br>- Scenario SL-0017: stress test kitchen sink rule set with broad include and targeted file include<br>- Scenario SL-0018: exact trailing slash configuration with cleanup validation<br>- Scenario SL-0019: no trailing slash workaround with cleanup validation<br>- Scenario SL-0020: focused trailing slash Projects regression for sibling path survival<br>- Scenario SL-0021: focused no trailing slash Projects regression for sibling path survival<br> |

src/sync.d

Lines changed: 78 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7871,49 +7871,101 @@ class SyncEngine {
78717871
// Resolve 'Directory not empty' error when deleting local files
78727872
try {
78737873
auto directoryEntries = dirEntries(path, SpanMode.depth, false);
7874+
bool pathShouldBeRemoved;
7875+
78747876
foreach (DirEntry child; directoryEntries) {
78757877
// set for error logging
78767878
currentPath = child.name;
7877-
7878-
// what sort of child is this?
7879-
if (isDir(child.name)) {
7880-
addLogEntry("Removing local directory: " ~ child.name);
7879+
7880+
// reset pathShouldBeRemoved
7881+
pathShouldBeRemoved = true;
7882+
7883+
// Issue #3655: Deletion of local data where 'sync_list' is expecting this to be kept
7884+
// If we are in a --download-only --cleanup-local-files + using a 'sync_list' the expectation here is that matches to 'sync_list' inclusion are kept
7885+
// If we get to this point, we have already validated '--download-only --cleanup-local-files' so this is now just about 'sync_list' inclusion
7886+
7887+
// Is 'sync_list' configured?
7888+
if (syncListConfigured) {
7889+
// Should this path be removed?
7890+
// selectiveSync.isPathExcludedViaSyncList() returns 'true' if the path is excluded, 'false' if the path is to be included
7891+
pathShouldBeRemoved = selectiveSync.isPathExcludedViaSyncList(child.name);
7892+
}
7893+
7894+
// What action should be taken?
7895+
if (pathShouldBeRemoved) {
7896+
// Path should be removed
7897+
// what sort of child is this?
7898+
if (isDir(child.name)) {
7899+
addLogEntry("Removing local directory: " ~ child.name);
7900+
} else {
7901+
addLogEntry("Removing local file: " ~ child.name);
7902+
}
7903+
7904+
// Are we in a --dry-run scenario?
7905+
if (!dryRun) {
7906+
// No --dry-run ... process local delete
7907+
if (exists(child)) {
7908+
try {
7909+
attrIsDir(child.linkAttributes) ? rmdir(child.name) : safeRemove(child.name);
7910+
} catch (FileException e) {
7911+
// display the error message
7912+
displayFileSystemErrorMessage(e.msg, thisFunctionName, currentPath);
7913+
}
7914+
}
7915+
}
78817916
} else {
7882-
addLogEntry("Removing local file: " ~ child.name);
7917+
// Path should be retained
7918+
// what sort of child is this?
7919+
if (isDir(child.name)) {
7920+
addLogEntry("Local directory should be retained due to 'sync_list' inclusion: " ~ child.name);
7921+
} else {
7922+
addLogEntry("Local file should be retained due to 'sync_list' inclusion: " ~ child.name);
7923+
}
78837924
}
78847925

7926+
7927+
7928+
7929+
7930+
}
7931+
// Clear directoryEntries
7932+
object.destroy(directoryEntries);
7933+
7934+
bool parentalPathShouldBeRemoved = true;
7935+
7936+
// Is 'sync_list' configured?
7937+
if (syncListConfigured) {
7938+
parentalPathShouldBeRemoved = selectiveSync.isPathExcludedViaSyncList(path);
7939+
}
7940+
7941+
// What action should be taken?
7942+
if (parentalPathShouldBeRemoved) {
7943+
7944+
// Remove the parental path now that it is empty of children
7945+
addLogEntry("Removing local directory: " ~ path);
78857946
// are we in a --dry-run scenario?
78867947
if (!dryRun) {
78877948
// No --dry-run ... process local delete
7888-
if (exists(child)) {
7949+
if (exists(path)) {
7950+
78897951
try {
7890-
attrIsDir(child.linkAttributes) ? rmdir(child.name) : safeRemove(child.name);
7952+
rmdirRecurse(path);
78917953
} catch (FileException e) {
78927954
// display the error message
7893-
displayFileSystemErrorMessage(e.msg, thisFunctionName, currentPath);
7955+
displayFileSystemErrorMessage(e.msg, thisFunctionName, path);
78947956
}
7957+
78957958
}
78967959
}
7897-
}
7898-
// Clear directoryEntries
7899-
object.destroy(directoryEntries);
7960+
} else {
7961+
// Path needs to be retained
7962+
addLogEntry("Local directory should be retained due to 'sync_list' inclusion: " ~ path);
7963+
7964+
79007965

7901-
// Remove the path now that it is empty of children
7902-
addLogEntry("Removing local directory: " ~ path);
7903-
// are we in a --dry-run scenario?
7904-
if (!dryRun) {
7905-
// No --dry-run ... process local delete
7906-
if (exists(path)) {
7907-
7908-
try {
7909-
rmdirRecurse(path);
7910-
} catch (FileException e) {
7911-
// display the error message
7912-
displayFileSystemErrorMessage(e.msg, thisFunctionName, path);
7913-
}
7914-
7915-
}
79167966
}
7967+
7968+
79177969
} catch (FileException e) {
79187970
// display the error message
79197971
displayFileSystemErrorMessage(e.msg, thisFunctionName, currentPath);

0 commit comments

Comments
 (0)