[#683] Zip log files into one (#692)

- files stored temporarily and then zipped
- the dependency API changed so it handles the temporary files and folders and returns the final logs.zip URL
- test fixed
This commit is contained in:
Lukas Korba 2023-03-22 14:38:10 +01:00 committed by GitHub
parent 4a3be9ac0b
commit 8294415a69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 61 additions and 42 deletions

View File

@ -3278,7 +3278,7 @@
CURRENT_PROJECT_VERSION = 49;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "\"secant/Preview Content\"";
DEVELOPMENT_TEAM = E7Q54GRN4K;
DEVELOPMENT_TEAM = RLPRR8CPQG;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = "secant/secant-testnet-Info.plist";
@ -3306,7 +3306,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 49;
DEVELOPMENT_ASSET_PATHS = "\"secant/Preview Content\"";
DEVELOPMENT_TEAM = E7Q54GRN4K;
DEVELOPMENT_TEAM = RLPRR8CPQG;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = "secant/secant-testnet-Info.plist";

View File

@ -15,5 +15,5 @@ extension DependencyValues {
}
}
struct LogsHandlerClient {
let exportAndStoreLogs: (URL, URL, URL) async throws -> Void
let exportAndStoreLogs: () async throws -> URL?
}

View File

@ -10,16 +10,56 @@ import ComposableArchitecture
extension LogsHandlerClient: DependencyKey {
static let liveValue = LogsHandlerClient(
exportAndStoreLogs: { tempSDKDir, tempTCADir, tempWalletDir in
async let sdkLogs = LogsHandlerClient.exportAndStoreLogsFor(key: LoggerConstants.sdkLogs, atURL: tempSDKDir)
async let tcaLogs = LogsHandlerClient.exportAndStoreLogsFor(key: LoggerConstants.tcaLogs, atURL: tempTCADir)
async let walletLogs = LogsHandlerClient.exportAndStoreLogsFor(key: LoggerConstants.walletLogs, atURL: tempWalletDir)
exportAndStoreLogs: {
// create a directory
let logsURL = FileManager.default.temporaryDirectory.appendingPathComponent("logs")
try FileManager.default.createDirectory(atPath: logsURL.path, withIntermediateDirectories: true)
// export the logs
async let sdkLogs = LogsHandlerClient.exportAndStoreLogsFor(
key: LoggerConstants.sdkLogs,
atURL: logsURL.appendingPathComponent("sdkLogs.txt")
)
async let tcaLogs = LogsHandlerClient.exportAndStoreLogsFor(
key: LoggerConstants.tcaLogs,
atURL: logsURL.appendingPathComponent("tcaLogs.txt")
)
async let walletLogs = LogsHandlerClient.exportAndStoreLogsFor(
key: LoggerConstants.walletLogs,
atURL: logsURL.appendingPathComponent("walletLogs.txt")
)
let logs = try await [sdkLogs, tcaLogs, walletLogs]
// store the log files into the logs folder
try logs.forEach { logsHandler in
try logsHandler.result.write(to: logsHandler.dir, atomically: true, encoding: String.Encoding.utf8)
}
// zip the logs folder
let coordinator = NSFileCoordinator()
var zipError: NSError?
var archiveURL: URL?
archiveURL = await withCheckedContinuation { continuation in
coordinator.coordinate(readingItemAt: logsURL, options: [.forUploading], error: &zipError) { zipURL in
do {
let tmpURL = try FileManager.default.url(
for: .itemReplacementDirectory,
in: .userDomainMask,
appropriateFor: zipURL,
create: true
)
.appendingPathComponent("logs.zip")
try FileManager.default.moveItem(at: zipURL, to: tmpURL)
continuation.resume(returning: tmpURL)
} catch {
continuation.resume(returning: nil)
}
}
}
return archiveURL
}
)
}

View File

@ -10,6 +10,6 @@ import XCTestDynamicOverlay
extension LogsHandlerClient: TestDependencyKey {
static let testValue = Self(
exportAndStoreLogs: XCTUnimplemented("\(Self.self).exportAndStoreLogs")
exportAndStoreLogs: XCTUnimplemented("\(Self.self).exportAndStoreLogs", placeholder: nil)
)
}

View File

@ -18,30 +18,14 @@ struct ExportLogsReducer: ReducerProtocol {
@BindingState var alert: AlertState<ExportLogsReducer.Action>?
var exportLogsDisabled = false
var isSharingLogs = false
var tempSDKDir: URL {
let tempDir = FileManager.default.temporaryDirectory
let sdkFileName = "sdkLogs.txt"
return tempDir.appendingPathComponent(sdkFileName)
}
var tempTCADir: URL {
let tempDir = FileManager.default.temporaryDirectory
let sdkFileName = "tcaLogs.txt"
return tempDir.appendingPathComponent(sdkFileName)
}
var tempWalletDir: URL {
let tempDir = FileManager.default.temporaryDirectory
let sdkFileName = "walletLogs.txt"
return tempDir.appendingPathComponent(sdkFileName)
}
var zippedLogsURLs: [URL] = []
}
indirect enum Action: Equatable, BindableAction {
case binding(BindingAction<ExportLogsReducer.State>)
case dismissAlert
case start
case finished
case finished(URL?)
case failed(String)
case shareFinished
}
@ -64,16 +48,19 @@ struct ExportLogsReducer: ReducerProtocol {
case .start:
state.exportLogsDisabled = true
return .run { [state] send in
return .run { send in
do {
try await logsHandler.exportAndStoreLogs(state.tempSDKDir, state.tempTCADir, state.tempWalletDir)
await send(.finished)
let zippedLogsURL = try await logsHandler.exportAndStoreLogs()
await send(.finished(zippedLogsURL))
} catch {
await send(.failed(error.localizedDescription))
}
}
case .finished:
case .finished(let zippedLogsURL):
if let zippedLogsURL {
state.zippedLogsURLs = [zippedLogsURL]
}
state.exportLogsDisabled = false
state.isSharingLogs = true
return .none

View File

@ -114,11 +114,7 @@ private extension RootView {
@ViewBuilder func shareLogsView(_ viewStore: RootViewStore) -> some View {
if viewStore.exportLogsState.isSharingLogs {
UIShareDialogView(
activityItems: [
viewStore.exportLogsState.tempSDKDir,
viewStore.exportLogsState.tempWalletDir,
viewStore.exportLogsState.tempTCADir
]
activityItems: viewStore.exportLogsState.zippedLogsURLs
) {
viewStore.send(.exportLogs(.shareFinished))
}

View File

@ -99,11 +99,7 @@ struct SettingsView: View {
@ViewBuilder func shareLogsView(_ viewStore: SettingsViewStore) -> some View {
if viewStore.exportLogsState.isSharingLogs {
UIShareDialogView(
activityItems: [
viewStore.exportLogsState.tempSDKDir,
viewStore.exportLogsState.tempWalletDir,
viewStore.exportLogsState.tempTCADir
]
activityItems: viewStore.exportLogsState.zippedLogsURLs
) {
viewStore.send(.exportLogs(.shareFinished))
}

View File

@ -92,13 +92,13 @@ class SettingsTests: XCTestCase {
reducer: SettingsReducer()
)
store.dependencies.logsHandler = LogsHandlerClient(exportAndStoreLogs: { _, _, _ in })
store.dependencies.logsHandler = LogsHandlerClient(exportAndStoreLogs: { nil })
await store.send(.exportLogs(.start)) { state in
state.exportLogsState.exportLogsDisabled = true
}
await store.receive(.exportLogs(.finished)) { state in
await store.receive(.exportLogs(.finished(nil))) { state in
state.exportLogsState.exportLogsDisabled = false
state.exportLogsState.isSharingLogs = true
}