1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//! Manifest verification: does the tree a `.alef/` cache entry vouches for still hold?
//!
//! Split out of [`crate::cli::cache`] because it answers a different question from the rest of
//! that module. A cache key ([`crate::cli::cache_identity`]) says *what* was generated and by
//! which alef build; these two predicates say whether the files that generation produced are
//! still on disk and still unmodified. Both must hold before a skip is honest.
//!
//! [`outputs_exist`] alone was the whole check, and existence turned out not to be enough: a
//! consumer appended a line to a generated file, re-ran `alef generate` with `.alef/` intact,
//! and got `Generated 0 files` with the edit still in place — the file existed, so the language
//! stayed a cache hit and was dropped from the generation set before anything read it.
//! [`stamped_outputs_agree_with_disk`] is what makes the hit mean something. ~keep
use fs;
use Path;
/// Check that all files listed in a manifest exist on disk. False if any listed file is missing,
/// if the manifest is empty, or if the manifest could not be read at all.
///
/// Every failure to read is a cache **miss**, never a hit. A manifest is absent for three
/// different reasons -- the stage has never run, the cache predates the manifest format, or the
/// previous run died between `fs::write`ing the hash and writing the manifest
/// (`write_lang_hash` and `write_stage_hash` are two separate writes, so an interrupt leaves
/// exactly a matching hash with no manifest) -- and only the read itself can no longer tell them
/// apart. The callers spend this answer on "may I skip regenerating?", where an unknown costs one
/// regeneration, while a wrong `true` skips the write entirely and leaves the tree permanently
/// short of files the cache insists are present. An empty-but-readable manifest already answered
/// `false`; an unreadable one is strictly less evidence and must not answer better. ~keep
pub
/// Whether every stamped file in `manifest_path` still hashes to its own embedded `alef:hash:`
/// value under `inputs_hash`.
///
/// This is the same comparison `alef verify` runs, so a tree that passes verify passes here.
/// Paths that are absent (already a miss via [`outputs_exist`]), unreadable as UTF-8, or carry no
/// marker return `true`: the question is "was a stamped file modified after alef wrote it", and
/// only a stamped file can be asked. Unstamped outputs -- `generated_header: false`, create-once
/// seeds -- must keep the existence-only rule or a warm run would never hit again. ~keep
pub