Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/NXLibrary/ViewModels/AppViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2745,7 +2745,7 @@ public final class AppViewModel: ObservableObject {
} else {
let reason = PortingFailureClassifier.classify(
log: buildLogTail(result.logURL),
keysPath: keyStore.keyURL.path,
keysPath: SourceSelection.requiresKeys(game.sources) ? keyStore.keyURL.path : "",
sourcePaths: game.sources.map(\.url.path)
)
let message = reason.what(game: game.name)
Expand Down
13 changes: 11 additions & 2 deletions Sources/NXLibraryCore/Models/PortingFailureReason.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ public enum PortingFailureClassifier {
("games.noTitleID", .noTitleID, "no (NSP with a readable title ID|game package with a readable content meta) in ",
"no game package with a readable content meta in "),
("disk.low", .diskFull, "less than [0-9]+ GB free on the volume of", "GB free on the volume of"),
("disk.app", .diskFull, #"the app needs [0-9.]+ GB on the volume of"#, "the app needs "),
("disk.full", .diskFull, "No space left on device", nil),
("icloud.detritus", .cloudFolder, "resource fork, Finder information, or similar detritus not allowed", nil),
]
Expand Down Expand Up @@ -247,8 +248,16 @@ public enum PortingFailureClassifier {
options: .regularExpression) else { return nil }
return String(message[range].dropFirst(prefix.count))
case .diskFull:
guard let r = log.range(of: "less than [0-9]+ GB free", options: .regularExpression) else { return nil }
return log[r].split(separator: " ").dropFirst(2).first.map(String.init)
if let r = log.range(of: "less than [0-9]+ GB free", options: .regularExpression) {
return log[r].split(separator: " ").dropFirst(2).first.map(String.init)
}
if let r = log.range(of: #"the app needs [0-9.]+ GB on the volume of"#, options: .regularExpression) {
let parts = log[r].split(separator: " ")
if parts.count >= 4, let num = Double(parts[3]) {
return String(Int(ceil(num + 1.0)))
}
}
return nil
case .noTitleID:
guard let r = log.range(of: #"no (NSP with a readable title ID|game package with a readable content meta) in [^"\n]+"#,
options: .regularExpression),
Expand Down
21 changes: 20 additions & 1 deletion Tests/NXLibraryCoreTests/PortingFailureReasonTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ final class PortingFailureReasonTests: XCTestCase {
("games.several", .severalGames, "[RED] more than one game in the folder, keep one game per folder: 0100000000010000, 0100000000020000"),
("games.noTitleID", .noTitleID, "[RED] no game package with a readable content meta in /Users/x/Games/Foo"),
("disk.low", .diskFull, "[RED] less than 40 GB free on the volume of /Users/x/work"),
("disk.app", .diskFull, "the app needs 12.4 GB on the volume of /Users/x/Temp (no APFS clones from the build there) and 13.1 GB are free"),
("disk.full", .diskFull, "OSError: [Errno 28] No space left on device"),
("icloud.detritus", .cloudFolder, "x.app: resource fork, Finder information, or similar detritus not allowed"),
]
Expand Down Expand Up @@ -103,6 +104,24 @@ final class PortingFailureReasonTests: XCTestCase {
XCTAssertEqual(classify("[RED] less than 40 GB free on the volume of /x").detail, "40")
}

func testPackAppDiskFullDetailIsRoundedGB() {
let log = """
the app needs 12.4 GB on the volume of /Users/x/Temp (no APFS clones from the build there) and 13.1 GB are free
[RED] pack_app.py exit code 1
"""
let reason = classify(log, keys: "/unreadable/prod.keys", readable: false)
XCTAssertEqual(reason.kind, .diskFull)
XCTAssertEqual(reason.detail, "14")
XCTAssertEqual(reason.what(game: "Ocarina of Time"), "The porting needs at least 14 GB free on the work volume.")
XCTAssertEqual(reason.action, .openStorage)
}

func testSourcesWithoutKeysDoNotFallBackToKeysOnUnrecognizedFailure() {
let log = "some unknown crash or error"
let reason = classify(log, keys: "")
XCTAssertEqual(reason.kind, .unknown)
}

func testNoTitleIDDetailIsFolder() {
XCTAssertEqual(classify("[RED] no game package with a readable content meta in /Users/x/Foo").detail, "/Users/x/Foo")
// Engines before nxnative 5c4dc18f said it this way.
Expand Down Expand Up @@ -248,7 +267,7 @@ final class PortingFailureEngineTests: XCTestCase {
private func gitGrep(_ fragment: String, at commit: String, in repo: URL) -> Bool {
let p = Process()
p.executableURL = URL(fileURLWithPath: "/usr/bin/git")
p.arguments = ["-C", repo.path, "grep", "-q", "-F", fragment, commit, "--", "scripts", "dm/gfx/tools", "dm/tools"]
p.arguments = ["-C", repo.path, "grep", "-q", "-F", fragment, commit, "--", "scripts", "dm/gfx/tools", "dm/tools", "dm/mac"]
p.standardOutput = FileHandle.nullDevice
p.standardError = FileHandle.nullDevice
do { try p.run() } catch { return false }
Expand Down