Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d7a8b5f3d |
@@ -70,6 +70,7 @@ class SyncEngine @Inject constructor(
|
||||
val localFiles = accessor.walkFiles(pair)
|
||||
|
||||
val allPaths = (localFiles.keys + remoteFiles.keys + knownStates.keys).toSet()
|
||||
val hasPriorSyncState = knownStates.isNotEmpty()
|
||||
val semaphore = Semaphore(4)
|
||||
|
||||
// Each async block returns its outcome; no shared mutable state across coroutines.
|
||||
@@ -87,7 +88,7 @@ class SyncEngine @Inject constructor(
|
||||
val local = localFiles[rel]
|
||||
val remote = remoteFiles[rel]
|
||||
val known = knownStates[rel]
|
||||
val decision = syncDecide(pair.syncDirection, pair.conflictStrategy, pair.deleteBehavior, local, remote, known)
|
||||
val decision = syncDecide(pair.syncDirection, pair.conflictStrategy, pair.deleteBehavior, local, remote, known, hasPriorSyncState)
|
||||
|
||||
when (decision) {
|
||||
SyncDecision.UPLOAD -> {
|
||||
@@ -228,6 +229,7 @@ internal fun syncDecide(
|
||||
local: LocalFileInfo?,
|
||||
remote: RemoteFile?,
|
||||
known: SyncFileStateEntity?,
|
||||
hasPriorSyncState: Boolean = false,
|
||||
): SyncDecision {
|
||||
val localExists = local != null
|
||||
val remoteExists = remote != null
|
||||
@@ -257,9 +259,21 @@ internal fun syncDecide(
|
||||
}
|
||||
|
||||
!localExists && remoteExists -> when {
|
||||
known == null -> when (direction) {
|
||||
SyncDirection.DOWNLOAD_ONLY, SyncDirection.TWO_WAY -> SyncDecision.DOWNLOAD
|
||||
else -> SyncDecision.SKIP
|
||||
known == null -> if (!hasPriorSyncState) {
|
||||
// Initial sync: no history at all — remote files are new, download them.
|
||||
when (direction) {
|
||||
SyncDirection.DOWNLOAD_ONLY, SyncDirection.TWO_WAY -> SyncDecision.DOWNLOAD
|
||||
else -> SyncDecision.SKIP
|
||||
}
|
||||
} else {
|
||||
// Pair has been synced before but this file has no state record
|
||||
// (e.g. uploaded before state-tracking was fixed). Treat the same
|
||||
// as a known remote-deletion: apply mirror/keep behavior.
|
||||
when {
|
||||
deleteBehavior == DeleteBehavior.KEEP -> SyncDecision.SKIP
|
||||
direction == SyncDirection.UPLOAD_ONLY || direction == SyncDirection.TWO_WAY -> SyncDecision.DELETE_REMOTE
|
||||
else -> SyncDecision.SKIP
|
||||
}
|
||||
}
|
||||
else -> when {
|
||||
deleteBehavior == DeleteBehavior.KEEP -> SyncDecision.SKIP
|
||||
|
||||
@@ -35,7 +35,8 @@ class SyncDecideTest {
|
||||
dir: SyncDirection = SyncDirection.TWO_WAY,
|
||||
conflict: ConflictStrategy = ConflictStrategy.KEEP_NEWEST,
|
||||
delete: DeleteBehavior = DeleteBehavior.MIRROR,
|
||||
) = syncDecide(dir, conflict, delete, local, remote, known)
|
||||
hasPriorState: Boolean = known != null,
|
||||
) = syncDecide(dir, conflict, delete, local, remote, known, hasPriorState)
|
||||
|
||||
// ── first sync (no known state) ───────────────────────────────────────────
|
||||
|
||||
@@ -126,6 +127,18 @@ class SyncDecideTest {
|
||||
assertEquals(SyncDecision.SKIP,
|
||||
decide(null, remote(), state(), dir = SyncDirection.DOWNLOAD_ONLY))
|
||||
|
||||
// ── local deleted, no state record (uploaded in broken version) ──────────
|
||||
|
||||
@Test fun `local deleted no known state but pair has prior history deletes remote`() =
|
||||
// hasPriorState=true means the pair has been synced before; file has no state
|
||||
// because it was uploaded when getFileMetadata was broken. Should still mirror deletion.
|
||||
assertEquals(SyncDecision.DELETE_REMOTE,
|
||||
decide(null, remote(), known = null, delete = DeleteBehavior.MIRROR, hasPriorState = true))
|
||||
|
||||
@Test fun `initial sync remote only no prior state downloads`() =
|
||||
assertEquals(SyncDecision.DOWNLOAD,
|
||||
decide(null, remote(), known = null, hasPriorState = false))
|
||||
|
||||
// ── first-seen SKIP saves baseline so later deletions are detected ────────
|
||||
|
||||
@Test fun `first sync both exist same mtime uploads local wins tie`() =
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
VERSION_NAME=1.0.11
|
||||
VERSION_CODE=12
|
||||
VERSION_NAME=1.0.12
|
||||
VERSION_CODE=13
|
||||
|
||||
Reference in New Issue
Block a user