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.
This commit is contained in:
Kelsi 2026-05-06 11:32:42 -07:00
parent 47f3f6c55b
commit 57b81a2344

View file

@ -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 <dir>\n"
<< " --purge-proprietary <dir> [--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 <N> 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";