mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-07 17:43:51 +00:00
feat(editor): add --remove-zone for safe zone deletion
Counterpart to --scaffold-zone / --copy-zone / --rename-zone — completes
the zone-lifecycle CRUD. Defense-in-depth against accidental
destruction:
wowee_editor --remove-zone custom_zones/Doomed
remove-zone: custom_zones/Doomed ('Doomed')
would delete: 6 file(s), 174.9 KB
re-run with --confirm to actually delete
wowee_editor --remove-zone custom_zones/Doomed --confirm
Removed custom_zones/Doomed ('Doomed')
deleted: 7 filesystem entries, 174.9 KB freed
Two-step safety:
1. Without --confirm: dry-run that lists what would be deleted
(file count + total bytes + zone display name from manifest).
2. With --confirm: actually wipes the directory.
Belt-and-suspenders refusal: even with --confirm, refuses to delete
anything that doesn't have a zone.json at the top level. Catches
typos like '--remove-zone .' that would otherwise nuke an entire
project.
Why not just 'rm -rf'? --remove-zone gives:
- Per-zone display name in the confirmation
- Byte-count audit before deletion
- The non-zone-dir guard (rm doesn't know what a zone is)
- Symmetric with the rest of the zone-lifecycle CLI
Verified: dry-run lists 6 files / 175 KB; '. --confirm' correctly
refused (no zone.json at top level); zone-dir --confirm wiped 7
fs entries with byte tally.
This commit is contained in:
parent
bc9033eb43
commit
8d9690a57a
1 changed files with 64 additions and 1 deletions
|
|
@ -571,6 +571,8 @@ static void printUsage(const char* argv0) {
|
|||
std::printf(" Duplicate a zone to custom_zones/<slug>/ with renamed slug-prefixed files\n");
|
||||
std::printf(" --rename-zone <srcDir> <newName>\n");
|
||||
std::printf(" In-place rename (zone.json + slug-prefixed files + dir); no copy\n");
|
||||
std::printf(" --remove-zone <zoneDir> [--confirm]\n");
|
||||
std::printf(" Delete a zone directory entirely (requires --confirm to actually delete)\n");
|
||||
std::printf(" --clear-zone-content <zoneDir> [--creatures] [--objects] [--quests] [--all]\n");
|
||||
std::printf(" Wipe one or more content files (terrain + manifest preserved)\n");
|
||||
std::printf(" --strip-zone <zoneDir> [--dry-run]\n");
|
||||
|
|
@ -857,7 +859,8 @@ int main(int argc, char* argv[]) {
|
|||
"--remove-quest-objective", "--clone-quest", "--clone-creature",
|
||||
"--clone-object",
|
||||
"--remove-creature", "--remove-object", "--remove-quest",
|
||||
"--copy-zone", "--rename-zone", "--clear-zone-content", "--strip-zone",
|
||||
"--copy-zone", "--rename-zone", "--remove-zone",
|
||||
"--clear-zone-content", "--strip-zone",
|
||||
"--repair-zone", "--gen-makefile", "--gen-project-makefile",
|
||||
"--build-woc", "--regen-collision", "--fix-zone",
|
||||
"--export-png", "--export-obj", "--import-obj",
|
||||
|
|
@ -11786,6 +11789,66 @@ int main(int argc, char* argv[]) {
|
|||
std::printf(" mapName : %s -> %s\n", oldSlug.c_str(), newSlug.c_str());
|
||||
std::printf(" renamed : %d slug-prefixed file(s)\n", renamed);
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--remove-zone") == 0 && i + 1 < argc) {
|
||||
// Delete a zone directory entirely. Requires --confirm to
|
||||
// actually delete (defense against accidental destruction
|
||||
// and against shell glob mishaps). Without --confirm,
|
||||
// just lists what would be deleted.
|
||||
std::string zoneDir = argv[++i];
|
||||
bool confirm = false;
|
||||
if (i + 1 < argc && std::strcmp(argv[i + 1], "--confirm") == 0) {
|
||||
confirm = true; i++;
|
||||
}
|
||||
namespace fs = std::filesystem;
|
||||
if (!fs::exists(zoneDir)) {
|
||||
std::fprintf(stderr,
|
||||
"remove-zone: %s does not exist\n", zoneDir.c_str());
|
||||
return 1;
|
||||
}
|
||||
if (!fs::exists(zoneDir + "/zone.json")) {
|
||||
// Belt-and-suspenders: refuse to wipe anything that doesn't
|
||||
// look like a zone dir, even with --confirm. Catches typos
|
||||
// like '--remove-zone .' that would nuke the whole project.
|
||||
std::fprintf(stderr,
|
||||
"remove-zone: %s has no zone.json — refusing to delete (not a zone dir)\n",
|
||||
zoneDir.c_str());
|
||||
return 1;
|
||||
}
|
||||
// Read manifest for the user-facing name.
|
||||
wowee::editor::ZoneManifest zm;
|
||||
std::string zoneName = zoneDir;
|
||||
if (zm.load(zoneDir + "/zone.json")) {
|
||||
zoneName = zm.displayName.empty() ? zm.mapName : zm.displayName;
|
||||
}
|
||||
// Walk for what would be removed (counts + total bytes).
|
||||
int fileCount = 0;
|
||||
uint64_t totalBytes = 0;
|
||||
std::error_code ec;
|
||||
for (const auto& e : fs::recursive_directory_iterator(zoneDir, ec)) {
|
||||
if (!e.is_regular_file()) continue;
|
||||
fileCount++;
|
||||
totalBytes += e.file_size(ec);
|
||||
}
|
||||
if (!confirm) {
|
||||
std::printf("remove-zone: %s ('%s')\n",
|
||||
zoneDir.c_str(), zoneName.c_str());
|
||||
std::printf(" would delete: %d file(s), %.1f KB\n",
|
||||
fileCount, totalBytes / 1024.0);
|
||||
std::printf(" re-run with --confirm to actually delete\n");
|
||||
return 0;
|
||||
}
|
||||
// Confirmed — wipe it.
|
||||
uintmax_t removed = fs::remove_all(zoneDir, ec);
|
||||
if (ec) {
|
||||
std::fprintf(stderr,
|
||||
"remove-zone: failed to remove %s (%s)\n",
|
||||
zoneDir.c_str(), ec.message().c_str());
|
||||
return 1;
|
||||
}
|
||||
std::printf("Removed %s ('%s')\n", zoneDir.c_str(), zoneName.c_str());
|
||||
std::printf(" deleted: %ju filesystem entries, %.1f KB freed\n",
|
||||
static_cast<uintmax_t>(removed), totalBytes / 1024.0);
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--clear-zone-content") == 0 && i + 1 < argc) {
|
||||
// Wipe content files (creatures.json / objects.json /
|
||||
// quests.json) from a zone while keeping terrain + manifest
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue