From 57b81a2344970fafda4b987c2a443b7f33be10ce Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 11:32:42 -0700 Subject: [PATCH] feat(extract): --purge-proprietary --json for machine-readable purge report Schema: asset_extract --purge-proprietary Data --json { "dir": "Data", "confirmed": false, "candidates": 21570, "removed": 0, "totalBytes": 17175328768 } "candidates" = files where a sidecar exists and is at least as new (would be deleted on --confirm-purge). "removed" reflects the actual delete count when --confirm-purge is set; 0 in dry-run. Lets CI scripts gate on the dry-run candidate count before actually purging: count=$(asset_extract --purge-proprietary Data --json | jq .candidates) [ "$count" -gt 1000 ] && asset_extract --purge-proprietary Data --confirm-purge The asset_extract --json flag now applies to both upgrade and purge modes. --- tools/asset_extract/main.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/asset_extract/main.cpp b/tools/asset_extract/main.cpp index 354374d0..0ae9aaca 100644 --- a/tools/asset_extract/main.cpp +++ b/tools/asset_extract/main.cpp @@ -37,10 +37,12 @@ static void printUsage(const char* prog) { << " Standalone post-extract pass on an existing tree —\n" << " writes open-format sidecars without re-running MPQ extract\n" << " --json emits a structured summary instead of text\n" - << " --purge-proprietary \n" + << " --purge-proprietary [--json]\n" << " Walk tree and dry-run report which proprietary files have\n" << " an open-format sidecar; add --confirm-purge to actually delete\n" << " --confirm-purge Required to actually delete files in --purge-proprietary mode\n" + << " --json Emit machine-readable summary in --upgrade-extract /\n" + << " --purge-proprietary modes\n" << " --verify CRC32 verify all extracted files\n" << " --threads Number of extraction threads (default: auto)\n" << " --verbose Verbose output\n" @@ -143,9 +145,11 @@ int main(int argc, char** argv) { std::cerr << "purge-proprietary: " << purgeDir << " does not exist\n"; return 1; } - std::cout << (confirmPurge ? "Purging" : "Dry-run: would purge") - << " proprietary files under " << purgeDir - << " where open-format sidecar exists...\n"; + if (!jsonOutput) { + std::cout << (confirmPurge ? "Purging" : "Dry-run: would purge") + << " proprietary files under " << purgeDir + << " where open-format sidecar exists...\n"; + } // (proprietary ext, sidecar ext) pairs. .skin pairs with the // matching foo.m2's foo.wom (skin gets purged when WOM exists // because WOM stores merged geometry). Group .wmo (foo_NNN.wmo) @@ -207,6 +211,16 @@ int main(int argc, char** argv) { if (fs::remove(p, rmEc)) removed++; } } + if (jsonOutput) { + nlohmann::json j; + j["dir"] = purgeDir; + j["confirmed"] = confirmPurge; + j["candidates"] = toRemove; + j["removed"] = removed; + j["totalBytes"] = totalBytes; + std::cout << j.dump(2) << "\n"; + return 0; + } std::cout << (confirmPurge ? " removed: " : " would remove: ") << toRemove << " files (" << (totalBytes / (1024.0 * 1024.0)) << " MB)\n";