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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! Reads a Makefile for whether one shell runs a whole recipe, and whether
//! that shell stops at the first failure.
//!
//! Split from `tests/env_access_policy.rs` under the repository's 400-line
//! cap. The parent's recipe guard asks these questions; `shell_flags.rs`
//! drives them against fixture Makefiles in both directions.
/// Assignment operators Make recognises, longest first so `::=` is not read as
/// `:=`, nor `:=` as `=`.
const ASSIGNMENTS: = ;
/// Return the effective value of `.SHELLFLAGS`, or `None` if it is never set.
///
/// Two things a prefix search got wrong, both of which let `.ONESHELL` mask a
/// failing Clippy command while this contract stayed green. `.SHELLFLAGS_NOTE`
/// begins with the variable's name and is an ordinary variable that says
/// nothing about the shell; and Make's later assignment wins, so an earlier
/// `.SHELLFLAGS = -e -c` followed by `.SHELLFLAGS = -c` leaves no `-e` in the
/// shell Make actually runs. The name is therefore matched exactly and the
/// assignments are folded in file order.
///
/// `+=` appends to what is there and `?=` assigns only when unset, as Make
/// defines them. A tab makes a line a recipe line rather than an assignment, so
/// those are skipped; a trailing comment is not part of the value. Line
/// continuations are not joined, which would understate a value split across
/// lines rather than overstate it.
pub
/// Return the operator and argument of a `.SHELLFLAGS` assignment on `line`.
///
/// The name is matched exactly, so `.SHELLFLAGS_NOTE` is an ordinary variable
/// and says nothing about the shell. A tab makes a line a recipe line rather
/// than an assignment, and a trailing comment is not part of the value.
/// Fold one assignment into the value so far, as Make defines the operators.
///
/// `+=` appends to what is there, `?=` assigns only when unset, and the rest
/// replace. Folding in file order is what makes the last assignment the one
/// that counts.
/// Return whether the shell Make runs a recipe in aborts on the first failure.
///
/// Judged on the value Make ends up with. Make's default `.SHELLFLAGS` is
/// `-c`, so an unset variable is not an aborting shell.
///
/// `-e` is not the only spelling. A single-dash bundle carries each of its
/// letters as a separate option, so `-eo pipefail -c` sets `errexit` as surely
/// as `-e -c` does, and that bundle is the form this estate's Makefiles use.
/// `-o errexit` sets it by name. Comparing whole tokens to `-e` called the
/// bundle non-aborting, which would fail a Makefile that is correct: a contract
/// wrong in that direction gets deleted rather than obeyed.
pub
/// Return whether the Makefile's effective `.SHELLFLAGS` abort on failure.
pub
/// Return whether the Makefile declares the `.ONESHELL` special target.
///
/// Make parses `.ONESHELL` as a target, and a target may be separated from its
/// colon by whitespace, so `.ONESHELL :` enables one-shell recipes exactly as
/// `.ONESHELL:` does. The name and the colon are therefore matched separately.
/// A test for the two characters together reads the spaced spelling as an
/// ordinary line, leaves the `.SHELLFLAGS` guard unasked, and lets a failing
/// Clippy command be masked by a later successful one: the whole of what this
/// guard exists to prevent.
///
/// A line that merely begins with the name is not a declaration, so
/// `.ONESHELL_NOTE := ...` reads as the ordinary variable it is.
pub