aboutsummaryrefslogtreecommitdiff
path: root/bin/main.ml
diff options
context:
space:
mode:
Diffstat (limited to 'bin/main.ml')
-rw-r--r--bin/main.ml62
1 files changed, 56 insertions, 6 deletions
diff --git a/bin/main.ml b/bin/main.ml
index 01cdbf8..ca89a12 100644
--- a/bin/main.ml
+++ b/bin/main.ml
@@ -74,12 +74,62 @@ let temporal_report y =
_build/default/bin/main.exe up two directories and back down into data/
always finds both files, regardless of the caller's own cwd.
- Known limitation, not yet exercised by this project: a `dune install`-
- style deployment (executable copied to a prefix with no adjacent _build/
- default/data/) would need a different resolution strategy; there is no
- install story yet (README.md: `dune exec` only), so this is not a
- regression against anything this project currently supports. *)
-let data_dir () = Filename.dirname (Filename.dirname Sys.executable_name) ^ "/data/ef"
+ RESOLVED: the "known limitation" this comment used to end on -- that a
+ `dune install`-style deployment (executable copied to a prefix with no
+ adjacent _build/default/data/) had no resolution strategy, and would exit 2
+ unable to find sanctoral.sexp -- is now handled by probing candidates in
+ order rather than computing one path and hoping. data/dune installs the
+ four runtime files into <prefix>/share/colitur/ef/.
+
+ Two layouts are probed, and one override short-circuits both:
+
+ [COLITUR_DATA_DIR], when set and non-blank -- an explicit override. It
+ NEVER falls through: if it is set and does not contain the data, that is
+ an error naming the directory, not a reason to quietly use different
+ data. A packager or operator who names a directory has stated an
+ intent, and silently calendaring off some other copy because theirs was
+ wrong is precisely the silent substitution this project refuses
+ everywhere else (CLAUDE.md's first binding decision: divergence is
+ flagged LOUDLY, never silently swallowed). Getting this wrong is not
+ hypothetical -- the first version of this function did fall through, and
+ a deliberately bogus COLITUR_DATA_DIR produced a full, plausible,
+ entirely un-flagged year off the build tree's data.
+
+ Otherwise, in order:
+ 1. <exedir>/../share/colitur/ef -- the INSTALLED layout, from an opam or
+ `dune install` prefix where the binary sits at <prefix>/bin/colitur.
+ data/dune puts the four runtime files there.
+ 2. <exedir>/../data/ef -- the BUILD TREE, which is what `dune exec` and
+ the cram tests use.
+
+ A candidate is accepted only if sanctoral.sexp is actually readable inside
+ it, not merely because the directory exists: an empty or half-populated
+ share/colitur/ef (a failed install, a partially removed package) falls
+ through to a working build tree rather than shadowing it and then failing
+ at load time with a confusing per-file error. Verified by simulation, not
+ assumed.
+
+ Environment reads are fine HERE and only here: this is bin/, not the
+ kernel, whose contract forbids them (CLAUDE.md, "Kernel is total &
+ deterministic: no wall-clock, randomness, or environment reads"). Nothing
+ below the CLI ever learns where the data came from -- the loaders take a
+ path. *)
+let data_dir () =
+ let has_data d = Sys.file_exists (Filename.concat d "sanctoral.sexp") in
+ let prefix = Filename.dirname (Filename.dirname Sys.executable_name) in
+ let installed = List.fold_left Filename.concat prefix [ "share"; "colitur"; "ef" ] in
+ let build_tree = Filename.concat prefix (Filename.concat "data" "ef") in
+ match Sys.getenv_opt "COLITUR_DATA_DIR" with
+ | Some d when String.trim d <> "" ->
+ if has_data d then d
+ else begin
+ Printf.eprintf
+ "colitur: COLITUR_DATA_DIR is set to %s, which contains no sanctoral.sexp\n\
+ colitur: refusing to fall back to another data directory -- unset it, or point it at one\n"
+ d;
+ exit 2
+ end
+ | _ -> if has_data installed then installed else build_tree
(* Loads the universal sanctoral layer and applies the one hand-authored
overlay over it (data/ef/adjustments.sexp -- see that file's own header):