Skip to content

Commit cbe1e2b

Browse files
committed
fix: await warnings in FileOpsEngine+DirSizeCalc
1 parent b6a1007 commit cbe1e2b

File tree

5 files changed

+82
-115
lines changed

5 files changed

+82
-115
lines changed

GUI/Resources/curr_version.asc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2026.03.11 00:02:15 at Host: NEVA
1+
2026.03.11 09:57:31 at Host: NEVA

GUI/Sources/Services/FileOps/DirSizeCalculator.swift

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -31,52 +31,62 @@ enum DirSizeCalculator {
3131
/// Scan a list of items (files and/or directories) and produce a flat manifest.
3232
/// Runs on a background thread — safe to call from MainActor.
3333
static func scan(_ items: [URL], fm: FileManager = .default) async -> DirScanResult {
34-
await Task.detached(priority: .userInitiated) {
35-
var totalBytes: Int64 = 0
36-
var fileCount = 0
37-
var maxDepth = 0
38-
var maxFileSize: Int64 = 0
39-
var flatList: [DirScanResult.FileEntry] = []
40-
41-
for item in items {
42-
var isDir: ObjCBool = false
43-
guard fm.fileExists(atPath: item.path, isDirectory: &isDir) else { continue }
44-
45-
if isDir.boolValue {
46-
scanDirectory(
47-
at: item,
48-
baseURL: item.deletingLastPathComponent(),
49-
depth: 0,
50-
fm: fm,
51-
totalBytes: &totalBytes,
52-
fileCount: &fileCount,
53-
maxDepth: &maxDepth,
54-
maxFileSize: &maxFileSize,
55-
flatList: &flatList
56-
)
57-
} else {
58-
let size = fileSize(at: item, fm: fm)
59-
totalBytes += size
60-
fileCount += 1
61-
maxFileSize = max(maxFileSize, size)
62-
flatList.append(.init(
34+
let itemsCopy = items
35+
return
36+
await Task.detached(priority: .userInitiated) {
37+
performScan(itemsCopy)
38+
}
39+
.value
40+
}
41+
42+
/// Pure synchronous scan — no captured mutable state, safe for Sendable closure.
43+
private static func performScan(_ items: [URL]) -> DirScanResult {
44+
let fm = FileManager.default
45+
var totalBytes: Int64 = 0
46+
var fileCount = 0
47+
var maxDepth = 0
48+
var maxFileSize: Int64 = 0
49+
var flatList: [DirScanResult.FileEntry] = []
50+
51+
for item in items {
52+
var isDir: ObjCBool = false
53+
guard fm.fileExists(atPath: item.path, isDirectory: &isDir) else { continue }
54+
55+
if isDir.boolValue {
56+
scanDirectory(
57+
at: item,
58+
baseURL: item.deletingLastPathComponent(),
59+
depth: 0,
60+
fm: fm,
61+
totalBytes: &totalBytes,
62+
fileCount: &fileCount,
63+
maxDepth: &maxDepth,
64+
maxFileSize: &maxFileSize,
65+
flatList: &flatList
66+
)
67+
} else {
68+
let size = fileSize(at: item, fm: fm)
69+
totalBytes += size
70+
fileCount += 1
71+
maxFileSize = max(maxFileSize, size)
72+
flatList.append(
73+
.init(
6374
url: item,
6475
relativePath: item.lastPathComponent,
6576
size: size,
6677
isDirectory: false
6778
))
68-
}
6979
}
80+
}
7081

71-
log.debug("[DirScanCalc] \(fileCount) files, \(totalBytes) bytes, depth=\(maxDepth), maxFile=\(maxFileSize)")
72-
return DirScanResult(
73-
totalBytes: totalBytes,
74-
fileCount: fileCount,
75-
maxDepth: maxDepth,
76-
maxFileSize: maxFileSize,
77-
flatList: flatList
78-
)
79-
}.value
82+
log.debug("[DirScanCalc] \(fileCount) files, \(totalBytes) bytes, depth=\(maxDepth), maxFile=\(maxFileSize)")
83+
return DirScanResult(
84+
totalBytes: totalBytes,
85+
fileCount: fileCount,
86+
maxDepth: maxDepth,
87+
maxFileSize: maxFileSize,
88+
flatList: flatList
89+
)
8090
}
8191

8292
// MARK: - Private
@@ -94,11 +104,13 @@ enum DirSizeCalculator {
94104
) {
95105
maxDepth = max(maxDepth, depth)
96106

97-
guard let enumerator = fm.enumerator(
98-
at: dirURL,
99-
includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey],
100-
options: []
101-
) else {
107+
guard
108+
let enumerator = fm.enumerator(
109+
at: dirURL,
110+
includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey],
111+
options: []
112+
)
113+
else {
102114
log.warning("[DirScanCalc] can't enumerate: \(dirURL.path)")
103115
return
104116
}
@@ -108,7 +120,6 @@ enum DirSizeCalculator {
108120
let vals = try fileURL.resourceValues(forKeys: [.fileSizeKey, .isDirectoryKey])
109121
let isDir = vals.isDirectory ?? false
110122

111-
// Track directory entries for creating structure at destination
112123
if isDir {
113124
let relPath = relativePath(of: fileURL, base: baseURL)
114125
flatList.append(.init(url: fileURL, relativePath: relPath, size: 0, isDirectory: true))

GUI/Sources/Services/FileOps/FileOpsEngine.swift

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ final class FileOpsEngine {
1616

1717
private let panel = FileOpProgressPanel.shared
1818
private let maxConcurrency = 5
19-
private let chunkSize = 256 * 1024 // 256 KB
19+
private let chunkSize = 256 * 1024 // 256 KB
2020

2121
private init() {
2222
log.debug("[FileOpsEngine] init")
@@ -55,7 +55,7 @@ final class FileOpsEngine {
5555
let progress = FileOpProgress(
5656
totalFiles: items.count,
5757
totalBytes: totalSize,
58-
type: .copy, // reuse for display
58+
type: .copy, // reuse for display
5959
destination: nil
6060
)
6161

@@ -117,12 +117,12 @@ final class FileOpsEngine {
117117
}
118118

119119
switch plan.strategy {
120-
case .simple:
121-
try await executeSimple(plan: plan, operation: operation, progress: progress)
122-
case .manySmall:
123-
try await executeManySmall(plan: plan, operation: operation, progress: progress)
124-
case .fewLarge:
125-
try await executeFewLarge(plan: plan, operation: operation, progress: progress)
120+
case .simple:
121+
try await executeSimple(plan: plan, operation: operation, progress: progress)
122+
case .manySmall:
123+
try await executeManySmall(plan: plan, operation: operation, progress: progress)
124+
case .fewLarge:
125+
try await executeFewLarge(plan: plan, operation: operation, progress: progress)
126126
}
127127

128128
return progress
@@ -140,10 +140,10 @@ final class FileOpsEngine {
140140
let target = UniqueNameGen.resolve(name: item.lastPathComponent, in: plan.destination)
141141
do {
142142
switch operation {
143-
case .copy:
144-
try fm.copyItem(at: item, to: target)
145-
case .move:
146-
try fm.moveItem(at: item, to: target)
143+
case .copy:
144+
try fm.copyItem(at: item, to: target)
145+
case .move:
146+
try fm.moveItem(at: item, to: target)
147147
}
148148
let size = (try? item.resourceValues(forKeys: [.fileSizeKey]).fileSize).map(Int64.init) ?? 0
149149
progress.fileCompleted(name: item.lastPathComponent, success: true)
@@ -196,10 +196,10 @@ final class FileOpsEngine {
196196

197197
do {
198198
switch operation {
199-
case .copy:
200-
try fm.copyItem(at: entry.url, to: targetURL)
201-
case .move:
202-
try fm.moveItem(at: entry.url, to: targetURL)
199+
case .copy:
200+
try fm.copyItem(at: entry.url, to: targetURL)
201+
case .move:
202+
try fm.moveItem(at: entry.url, to: targetURL)
203203
}
204204
progress.fileCompleted(name: entry.url.lastPathComponent, success: true)
205205
progress.add(bytes: entry.size)
@@ -239,7 +239,7 @@ final class FileOpsEngine {
239239

240240
for entry in fileEntries {
241241
guard !progress.isCancelled else { break }
242-
await progress.setCurrentFile(entry.url.lastPathComponent)
242+
progress.setCurrentFile(entry.url.lastPathComponent)
243243

244244
let targetURL = UniqueNameGen.resolve(
245245
name: entry.relativePath,
@@ -292,7 +292,7 @@ final class FileOpsEngine {
292292

293293
// MARK: - Stream Copy (256KB chunks)
294294

295-
private nonisolated func streamCopy(
295+
private func streamCopy(
296296
from source: URL,
297297
to destination: URL,
298298
progress: FileOpProgress
@@ -306,28 +306,29 @@ final class FileOpsEngine {
306306

307307
input.open()
308308
output.open()
309-
defer { input.close(); output.close() }
309+
defer {
310+
input.close()
311+
output.close()
312+
}
310313

311314
let bufSize = 256 * 1024
312315
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufSize)
313316
defer { buffer.deallocate() }
314317

315318
while true {
316-
let cancelled = await progress.isCancelled
317-
if cancelled { break }
319+
if progress.isCancelled { break }
318320

319321
let bytesRead = input.read(buffer, maxLength: bufSize)
320322
if bytesRead < 0 {
321323
throw FileOpError.readFailed(source.path)
322324
}
323-
if bytesRead == 0 { break } // EOF
325+
if bytesRead == 0 { break } // EOF
324326

325327
let written = output.write(buffer, maxLength: bytesRead)
326328
if written < 0 {
327329
throw FileOpError.writeFailed(destination.path)
328330
}
329-
330-
await progress.add(bytes: Int64(written))
331+
progress.add(bytes: Int64(written))
331332
}
332333
}
333334

apply_refactor_phase2.zsh

Lines changed: 0 additions & 45 deletions
This file was deleted.

refactor_phase2.tar.gz

-24.6 KB
Binary file not shown.

0 commit comments

Comments
 (0)