Skip to content

Commit cee2756

Browse files
committed
Refactor: Streamline LocalPath delete logic
- Simplify apply-to-all permission and unknown issue handling. - Remove redundant target-specific traversal and processing. - Delete files using `Files.delete()` instead of a placeholder. - Improve error handling for `NoSuchFileException` within the unknown error block.
1 parent 54c4bbe commit cee2756

1 file changed

Lines changed: 37 additions & 62 deletions

File tree

app-common-io/src/main/java/eu/darken/butler/common/files/local/LocalPathDeleteExtensions.kt

Lines changed: 37 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ import eu.darken.butler.common.debug.logging.logTag
77
import eu.darken.butler.common.files.LocalPath
88
import eu.darken.butler.common.files.actions.DeleteAction
99
import eu.darken.butler.common.files.actions.PathActionIssue
10-
import eu.darken.butler.common.files.errors.ReadException
1110
import eu.darken.butler.common.files.errors.WriteException
1211
import eu.darken.butler.common.files.metadata.FileType
1312
import eu.darken.butler.common.io.R
1413
import kotlinx.coroutines.currentCoroutineContext
15-
import kotlinx.coroutines.delay
1614
import kotlinx.coroutines.isActive
1715
import java.io.IOException
1816
import java.nio.file.Files
@@ -41,19 +39,16 @@ suspend fun Collection<LocalPath>.delete(
4139
val deleted = linkedSetOf<LocalPathLookup>()
4240
var bytesTotal = 0L
4341

44-
// Apply-to-all state management
45-
var skipAllPermissionIssues = false
42+
var issueSkippAllPermission = false
43+
var issueSkippAllUnknown = false
4644

47-
// Process each original target separately for cleaner progress tracking
4845
this.forEachIndexed { index, currentTopLevel ->
4946
log(TAG, VERBOSE) { "delete(): Processing target ${index + 1}/${this.size}: $currentTopLevel" }
5047

51-
// Collect all items for this specific target
5248
val toVisit = ArrayDeque<LocalPath>().apply { add(currentTopLevel) }
5349
val files = ArrayDeque<LocalPathLookup>()
5450
val dirsPost = ArrayDeque<LocalPathLookup>()
5551

56-
// Traverse this target's tree
5752
while (toVisit.isNotEmpty() && currentCoroutineContext().isActive) {
5853
val localPath = toVisit.removeFirst()
5954
val lookup = localPath.performLookup()
@@ -89,7 +84,6 @@ suspend fun Collection<LocalPath>.delete(
8984
suspend fun tryDelete(target: LocalPathLookup) {
9085
while (currentCoroutineContext().isActive) {
9186
try {
92-
9387
onProgress?.invoke(
9488
DeleteAction.State.Progress(
9589
target = target,
@@ -120,92 +114,73 @@ suspend fun Collection<LocalPath>.delete(
120114
} else null
121115
)
122116
)
123-
delay(50) // FIXME Just for testing
124-
// Files.delete(target.file.toPath()) // FIXME Just for testing.
117+
Files.delete(target.lookedUp.file.toPath())
125118
bytesTotal += size
126119
deleted += target
127120
itemsProcessed++
128121
break
129-
} catch (e: NoSuchFileException) {
130-
log(TAG, WARN) { "delete(): File doesn't exist: $target" }
131-
if (ignoreMissing) break else throw ReadException(path = target.lookedUp, cause = e)
132-
133122
} catch (securityError: SecurityException) {
134123
log(TAG, ERROR) { "delete(): Security exception on $target: $securityError" }
135124

136-
if (skipAllPermissionIssues) {
125+
if (issueSkippAllPermission) {
137126
log(TAG, INFO) { "Skipping permission issue (apply-to-all): $target" }
138127
break
139128
}
140129

141130
val deleteError = WriteException(path = target.lookedUp, cause = securityError)
142-
143131
if (onIssue == null) throw deleteError
144132

145-
val issue = try {
146-
PathActionIssue.InsufficientPermission(
147-
destination = target,
148-
exception = deleteError,
149-
)
150-
} catch (e: Exception) {
151-
PathActionIssue.UnknownError(exception = e)
152-
}
133+
val issue = PathActionIssue.InsufficientPermission(
134+
destination = target,
135+
exception = deleteError,
136+
)
153137

154-
val resolution = onIssue.invoke(issue)
155-
when (issue) {
156-
is PathActionIssue.InsufficientPermission -> {
157-
val permissionResolution = resolution as PathActionIssue.InsufficientPermission.Resolution
158-
when (permissionResolution) {
159-
is PathActionIssue.InsufficientPermission.Resolution.Cancel -> throw CancellationException(
160-
"User cancelled",
161-
deleteError
162-
)
163-
is PathActionIssue.InsufficientPermission.Resolution.Skip -> {
164-
if (permissionResolution.applyToAll) skipAllPermissionIssues = true
165-
break
166-
}
167-
}
168-
}
169-
is PathActionIssue.UnknownError -> {
170-
val unknownResolution = resolution as PathActionIssue.UnknownError.Resolution
171-
when (unknownResolution) {
172-
is PathActionIssue.UnknownError.Resolution.Cancel -> throw CancellationException(
173-
"User cancelled",
174-
deleteError
175-
)
176-
is PathActionIssue.UnknownError.Resolution.Retry -> continue
177-
is PathActionIssue.UnknownError.Resolution.Skip -> break
178-
}
138+
when (val resolution = onIssue.invoke(issue) as PathActionIssue.InsufficientPermission.Resolution) {
139+
is PathActionIssue.InsufficientPermission.Resolution.Cancel -> throw CancellationException(
140+
"User cancelled",
141+
deleteError
142+
)
143+
is PathActionIssue.InsufficientPermission.Resolution.Skip -> {
144+
if (resolution.applyToAll) issueSkippAllPermission = true
145+
break
179146
}
180-
else -> throw IllegalStateException("Unexpected issue type: $issue")
181147
}
182148
} catch (deleteError: Exception) {
183149
log(TAG, ERROR) { "delete(): Failed to delete $target: $deleteError" }
184-
if (onIssue == null) throw deleteError
185150

186-
val issue = try {
187-
PathActionIssue.UnknownError(
188-
destination = target,
189-
exception = deleteError
190-
)
191-
} catch (e: Exception) {
192-
PathActionIssue.UnknownError(exception = e)
151+
if (issueSkippAllUnknown) {
152+
log(TAG, INFO) { "Skipping unknown issue (apply-to-all): $target" }
153+
break
154+
}
155+
156+
if (deleteError is NoSuchFileException) {
157+
log(TAG, WARN) { "delete(): File doesn't exist: $target" }
158+
if (ignoreMissing) break
193159
}
194160

195-
val resolution = onIssue.invoke(issue) as PathActionIssue.UnknownError.Resolution
196-
when (resolution) {
161+
val deleteError = WriteException(path = target.lookedUp, cause = deleteError)
162+
if (onIssue == null) throw deleteError
163+
164+
val issue = PathActionIssue.UnknownError(
165+
destination = target,
166+
exception = deleteError
167+
)
168+
169+
when (val resolution = onIssue.invoke(issue) as PathActionIssue.UnknownError.Resolution) {
197170
is PathActionIssue.UnknownError.Resolution.Cancel -> throw CancellationException(
198171
"User cancelled",
199172
deleteError
200173
)
201174
is PathActionIssue.UnknownError.Resolution.Retry -> continue
202-
is PathActionIssue.UnknownError.Resolution.Skip -> break
175+
is PathActionIssue.UnknownError.Resolution.Skip -> {
176+
if (resolution.applyToAll) issueSkippAllUnknown = true
177+
break
178+
}
203179
}
204180
}
205181
}
206182
}
207183

208-
// Delete files and directories for this target
209184
log(TAG, VERBOSE) { "delete(): Deleting ${files.size} files for target: $currentTopLevel" }
210185
for (localPath in files) tryDelete(localPath)
211186

0 commit comments

Comments
 (0)