feat: add export / file packing

This commit is contained in:
2026-10-30 15:42:08 +01:00
parent de7e489cc0
commit 0fbc023018
28 changed files with 782 additions and 157 deletions
+49 -3
View File
@@ -9,6 +9,8 @@
#include <nlohmann/json.hpp>
#include <destrum/Assets/PackFile.h>
#include "TestUtils.h"
using namespace test;
@@ -51,11 +53,10 @@ namespace {
}
}
int runChef(const CookDirs& dirs, const std::string& flags = {})
int runChefArgs(const CookDirs& dirs, const std::string& args)
{
const fs::path log = dirs.root / "chef.log";
std::string command = "\"" + std::string(DESTRUM_THECHEF_PATH) + "\" --input \"" + dirs.input.string() +
"\" --output \"" + dirs.output.string() + "\" " + flags + " > \"" + log.string() +
std::string command = "\"" + std::string(DESTRUM_THECHEF_PATH) + "\" " + args + " > \"" + log.string() +
"\" 2>&1";
#ifdef _WIN32
// cmd.exe strips the outer quotes, the inner ones keep paths with spaces intact
@@ -64,6 +65,11 @@ namespace {
return std::system(command.c_str());
}
int runChef(const CookDirs& dirs, const std::string& flags = {})
{
return runChefArgs(dirs, "--input \"" + dirs.input.string() + "\" --output \"" + dirs.output.string() + "\" " + flags);
}
void expectChef(const CookDirs& dirs, const std::string& flags, bool succeeds, const char* message)
{
if ((runChef(dirs, flags) == 0) != succeeds) {
@@ -307,6 +313,45 @@ namespace {
}
}
namespace {
void testPackBundlesCookedOutputs()
{
const CookDirs dirs = makeDirs("destrum_cooker_pack");
writeShaders(dirs);
writeText(dirs.input / "notes.txt", "hello");
expectChef(dirs, "", true, "the first cook must succeed");
writeText(dirs.output / "stray.txt", "not cooked");
const fs::path pack = dirs.root / "assets.dpak";
const std::string packArgs = "--pack \"" + pack.string() + "\" --mount \"game=" + dirs.output.string() + "\"";
if (runChefArgs(dirs, packArgs) != 0) {
std::cerr << readFile(dirs.root / "chef.log") << '\n';
check(false, "packing a cooked folder must succeed");
return;
}
const PackFile::Reader reader{pack};
check(reader.Find("game/manifest.json") && reader.Find("game/shaders/plain.frag.spv") &&
reader.Find("game/notes.txt"),
"packs must hold the manifest and every cooked output");
check(!reader.Find("game/stray.txt") && !reader.Find("game/shaders/include/common.glsl"),
"packs must only hold what the manifest lists as outputs");
const auto notes = reader.Read(*reader.Find("game/notes.txt"));
check(std::string(notes.begin(), notes.end()) == "hello", "packed files must keep their contents");
check(runChefArgs(dirs, "--list \"" + pack.string() + "\" --top 0") == 0 &&
readFile(dirs.root / "chef.log").find("game/notes.txt") != std::string::npos,
"listing a pack must show its files");
check(runChefArgs(dirs, "--list \"" + dirs.output.string() + "\"") == 0 &&
readFile(dirs.root / "chef.log").find("Not in the manifest, won't be packed: 1 files") != std::string::npos,
"listing a cooked folder must point out files that won't be packed");
fs::remove(dirs.output / "notes.txt");
check(runChefArgs(dirs, packArgs) != 0, "packing must fail when a listed output is missing");
check(!fs::exists(pack.string() + ".tmp"), "a failed pack must not leave a temp file");
}
}
void RunCookerTests()
{
testCookRecordsEveryOutput();
@@ -317,4 +362,5 @@ void RunCookerTests()
testFailedCookKeepsLastGoodOutput();
testFallbacksAndStrictMode();
testValidateFindsMissingOutputs();
testPackBundlesCookedOutputs();
}