feat(persist): owned-file manifest seam — capture records created files (B-cap)
Pure OwnedFileManifest (relative paths, dedup, JSON round-trip) persisted under sibling owned_files ext-state key; both capture commit paths record; joins the R-B undo-reload set. Phase R prune consumes it later.
This commit is contained in:
@@ -217,6 +217,15 @@ bool ReaSamplerSession::saveToActiveProject() {
|
||||
SetProjExtState(static_cast<ReaProject*>(proj), kProjExtNamespace,
|
||||
kProjExtTailKey, tailJson.c_str());
|
||||
|
||||
// Additive: the owned-file manifest (Phase B B-cap) rides alongside in its own
|
||||
// `owned_files` key. Independent write — does not disturb the blobs above. Written
|
||||
// on EVERY save so a capture's manifest record survives Save / Save-As / reopen,
|
||||
// and so the manifest and the bank stay in lockstep on disk (both persisted by the
|
||||
// same saveToActiveProject the capture add-path calls).
|
||||
const std::string ownedJson = owned_.serialize();
|
||||
SetProjExtState(static_cast<ReaProject*>(proj), kProjExtNamespace,
|
||||
kProjExtOwnedKey, ownedJson.c_str());
|
||||
|
||||
MarkProjectDirty(static_cast<ReaProject*>(proj));
|
||||
return true;
|
||||
}
|
||||
@@ -259,6 +268,25 @@ TailSetting loadTailSetting(ReaProject* proj) {
|
||||
return *loaded;
|
||||
}
|
||||
|
||||
// Load the owned-file manifest from a project's owned_files key, or return an empty
|
||||
// manifest. An absent/empty key (older / never-captured project) yields an empty
|
||||
// manifest — graceful, never a crash. Malformed JSON is warned and also falls back to
|
||||
// empty, mirroring the bank's / view's / tail's malformed handling. Phase R prune then
|
||||
// sees an empty ownership record and (safely) attributes nothing until the next capture
|
||||
// rebuilds it — losing the record degrades safety, never correctness.
|
||||
OwnedFileManifest loadOwnedManifest(ReaProject* proj) {
|
||||
if (!proj) return OwnedFileManifest{};
|
||||
const std::string ownedJson =
|
||||
getProjExtStateString(proj, kProjExtNamespace, kProjExtOwnedKey);
|
||||
if (ownedJson.empty()) return OwnedFileManifest{}; // no stored manifest -> empty
|
||||
std::optional<OwnedFileManifest> loaded = OwnedFileManifest::deserialize(ownedJson);
|
||||
if (!loaded) {
|
||||
ShowConsoleMsg("ReaSampler: stored owned-file manifest is malformed — ignoring.\n");
|
||||
return OwnedFileManifest{};
|
||||
}
|
||||
return std::move(*loaded);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ReaSamplerSession::loadFromProject(void* proj, const std::string& projectDir) {
|
||||
@@ -281,6 +309,12 @@ void ReaSamplerSession::loadFromProject(void* proj, const std::string& projectDi
|
||||
// the previous project's choice (this REPLACES the old session-carry behavior).
|
||||
tail_ = loadTailSetting(static_cast<ReaProject*>(proj));
|
||||
|
||||
// The owned-file manifest is restored on EVERY load path too (peer-symmetry with the
|
||||
// bank/view/tail resets): switching to a project with no stored manifest must reset
|
||||
// to empty, not inherit the previous project's ownership record; an undo/redo reload
|
||||
// (R-B) must re-read the restored manifest so it matches the rolled-back bank state.
|
||||
owned_ = loadOwnedManifest(static_cast<ReaProject*>(proj));
|
||||
|
||||
if (!proj) {
|
||||
book_ = BankBook{};
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user