feat(version): single-source semver, ext-state stamp, show-version action
Version "0.9.01" sourced once from CMake via configure_file'd header; pure app_version module (parse/compare/classify) with CTest. Stamp rides the persist save seam under "reasampler"/"version"; absent stamp reads as pre-versioning. On-demand "show version" action, no startup print.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
// app_version — the REAPER-free version-identity core (Phase V, V1). The single
|
||||
// source of truth for the version STRING lives in CMake (a `REASAMPLER_VERSION`
|
||||
// variable threaded in via configure_file -> version_generated.h); this module
|
||||
// re-exports it as the canonical constant and owns every pure operation on it: the
|
||||
// exact-string render, the parse/compare arithmetic a within-channel forward
|
||||
// migration will lean on, and the "which version wrote this project" result that
|
||||
// persist reads back from ext state (absent stamp = pre-versioning, never an error).
|
||||
//
|
||||
// PURE MODULE: NO REAPER types, NO SWELL, NO vendor/ includes. Standard library
|
||||
// only. Builds and unit-tests without REAPER (mirror of bank_model / tail_control).
|
||||
//
|
||||
// Leading-zero fidelity (V1, Daniel-fixed): the displayed/stamped string is EXACTLY
|
||||
// "0.9.01" — two-digit zero-padded patch. That exactness is why the version STRING is
|
||||
// the authoritative artifact (sourced verbatim from the one CMake variable), not a
|
||||
// reconstruction from numeric components — CMake's `project(VERSION)` may normalize a
|
||||
// numeric patch field, so we never round-trip the string through integers to render it.
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
// The canonical version string — EXACTLY the value of the CMake `REASAMPLER_VERSION`
|
||||
// variable (see version_generated.h, produced by configure_file). One edit point:
|
||||
// changing that variable changes this constant, the ext-state stamp, and the
|
||||
// show-version action output with no other edits. Leading zero preserved verbatim.
|
||||
const std::string& appVersion();
|
||||
|
||||
// A parsed semver triple. Kept minimal — major.minor.patch as integers, for ORDERING
|
||||
// only. It deliberately does NOT round-trip back to the display string (the leading
|
||||
// zero is a rendering concern owned by the authoritative string, not reconstructable
|
||||
// from the integer patch). parseVersion returns nullopt on malformed input.
|
||||
struct Version {
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
int patch = 0;
|
||||
};
|
||||
|
||||
// Parse "x.y.z" (each component a non-negative integer, leading zeros allowed) into a
|
||||
// Version. Returns nullopt on anything malformed: wrong component count, non-digits, a
|
||||
// leading `-`, empty components, or trailing garbage. Used for ordering two stamps and
|
||||
// for validating a stored stamp before comparing.
|
||||
std::optional<Version> parseVersion(const std::string& s);
|
||||
|
||||
// Numeric ordering by (major, minor, patch). a < b iff a precedes b. So
|
||||
// 0.9.01 < 0.9.02 < 0.10.01 (numeric compare, NOT lexicographic — 10 > 9).
|
||||
bool versionLess(const Version& a, const Version& b);
|
||||
|
||||
// The writing-version a project was last saved with, recovered from its ext-state
|
||||
// stamp. A project saved before this feature shipped has NO stamp — that is the
|
||||
// explicit `preVersioning` case (kind), not an error and not a warning. A present-but-
|
||||
// malformed value is `unknown` (also silent — a corrupt stamp is ignored, never
|
||||
// throws). A well-formed value is `stamped` and carries the exact stored string plus
|
||||
// its parsed triple for comparison.
|
||||
struct WritingVersion {
|
||||
enum class Kind {
|
||||
PreVersioning, // no stamp stored — a project written before versioning shipped
|
||||
Unknown, // a stamp was stored but is not parseable — ignored, not an error
|
||||
Stamped, // a well-formed stamp
|
||||
};
|
||||
Kind kind = Kind::PreVersioning;
|
||||
std::string raw; // the exact stored string (empty for PreVersioning)
|
||||
Version parsed; // meaningful only when kind == Stamped
|
||||
};
|
||||
|
||||
// Classify a raw stored stamp value (exactly what GetProjExtState returned for the
|
||||
// version key). Empty -> PreVersioning; non-empty but unparseable -> Unknown; parseable
|
||||
// -> Stamped. Pure so the three-way classification is test-pinned; persist calls this
|
||||
// with the raw ext-state read and never has to reason about the cases itself.
|
||||
WritingVersion classifyWritingVersion(const std::string& rawStamp);
|
||||
|
||||
} // namespace reasampler
|
||||
Reference in New Issue
Block a user