Skip to content

Commit 79f5c8b

Browse files
committed
Json Progress File
1 parent 06bc674 commit 79f5c8b

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import Foundation
2+
import SwiftlyCore
3+
import SystemPackage
4+
import TSCUtility
5+
6+
enum ProgressInfo: Codable {
7+
case step(timestamp: Date, percent: Int, text: String)
8+
case complete(success: Bool)
9+
}
10+
11+
struct JsonFileProgressReporter: ProgressAnimationProtocol {
12+
let filePath: FilePath
13+
private let encoder: JSONEncoder
14+
15+
init(filePath: FilePath, encoder: JSONEncoder = JSONEncoder()) {
16+
self.filePath = filePath
17+
self.encoder = encoder
18+
}
19+
20+
private func writeProgress(_ progress: ProgressInfo) {
21+
let jsonData = try? self.encoder.encode(progress)
22+
guard let jsonData = jsonData, let jsonString = String(data: jsonData, encoding: .utf8)
23+
else {
24+
print("Failed to encode progress entry to JSON")
25+
return
26+
}
27+
28+
let jsonLine = jsonString + "\n"
29+
30+
do {
31+
try jsonLine.append(to: self.filePath)
32+
} catch {
33+
print("Failed to write progress entry to \(self.filePath): \(error)")
34+
}
35+
}
36+
37+
func update(step: Int, total: Int, text: String) {
38+
assert(step <= total)
39+
self.writeProgress(
40+
ProgressInfo.step(
41+
timestamp: Date(),
42+
percent: Int(Double(step) / Double(total) * 100),
43+
text: text
44+
))
45+
}
46+
47+
func complete(success: Bool) {
48+
self.writeProgress(ProgressInfo.complete(success: success))
49+
}
50+
51+
func clear() {
52+
do {
53+
try FileManager.default.removeItem(atPath: self.filePath.string)
54+
} catch {
55+
print("Failed to clear progress file at \(self.filePath): \(error)")
56+
}
57+
}
58+
}

Sources/SwiftlyCore/FileManager+FilePath.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,22 @@ extension String {
190190
try self.write(to: URL(fileURLWithPath: path.string), atomically: atomically, encoding: enc)
191191
}
192192

193+
public func append(to path: FilePath, encoding enc: String.Encoding = .utf8) throws {
194+
if !FileManager.default.fileExists(atPath: path.string) {
195+
try self.write(to: path, atomically: true, encoding: enc)
196+
return
197+
}
198+
199+
let fileHandle = try FileHandle(forWritingTo: URL(fileURLWithPath: path.string))
200+
defer { fileHandle.closeFile() }
201+
fileHandle.seekToEndOfFile()
202+
if let data = self.data(using: enc) {
203+
fileHandle.write(data)
204+
} else {
205+
throw SwiftlyError(message: "Failed to convert string to data with encoding \(enc)")
206+
}
207+
}
208+
193209
public init(contentsOf path: FilePath, encoding enc: String.Encoding = .utf8) throws {
194210
try self.init(contentsOf: URL(fileURLWithPath: path.string), encoding: enc)
195211
}

Tests/SwiftlyTests/JsonFileProgressReporterTests.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import Foundation
2+
@testable import Swiftly
3+
@testable import SwiftlyCore
24
import SystemPackage
35
import Testing
46

@@ -100,6 +102,20 @@ import Testing
100102
try FileManager.default.removeItem(atPath: tempFile.string)
101103
}
102104

105+
@Test("Test clear method removes file")
106+
func testClearRemovesFile() throws {
107+
let tempFile = fs.mktemp(ext: ".json")
108+
let reporter = JsonFileProgressReporter(filePath: tempFile)
109+
110+
reporter.update(step: 1, total: 2, text: "Test")
111+
112+
#expect(FileManager.default.fileExists(atPath: tempFile.string))
113+
114+
reporter.clear()
115+
116+
#expect(!FileManager.default.fileExists(atPath: tempFile.string))
117+
}
118+
103119
@Test("Test multiple progress updates create multiple lines")
104120
func testMultipleUpdatesCreateMultipleLines() async throws {
105121
let tempFile = fs.mktemp(ext: ".json")

0 commit comments

Comments
 (0)