Run a script: parse `content` into stanzas, execute each command, and either compare its output to the stanza's expected block or — when `REWRITE` is set and `path` is given — rewrite the file in place with the actual outputs. Returns `Err` if any stanza's output differs from its expected block, so a scripted run exits non-zero on a mismatch (and CI fails). A command that fails renders as `error:
(
driver: Driver,
loc: PersistLocation,
content: &str,
path: Option<&Path>,
)
| 1123 | /// renders as `error: <message>`, so an expected failure is asserted by its |
| 1124 | /// golden block rather than a special command. |
| 1125 | pub async fn run( |
| 1126 | driver: Driver, |
| 1127 | loc: PersistLocation, |
| 1128 | content: &str, |
| 1129 | path: Option<&Path>, |
| 1130 | ) -> anyhow::Result<()> { |
| 1131 | let items = crate::text::parse_file(content)?; |
| 1132 | let mut state = ScriptState::new(driver, loc).await?; |
| 1133 | let rewrite = std::env::var_os("REWRITE").is_some(); |
| 1134 | |
| 1135 | let mut actuals = Vec::new(); |
| 1136 | let mut mismatches = 0usize; |
| 1137 | for item in &items { |
| 1138 | let crate::text::Item::Stanza(stanza) = item else { |
| 1139 | continue; |
| 1140 | }; |
| 1141 | let actual = match state.execute(stanza.command.clone()).await { |
| 1142 | Ok(output) => output, |
| 1143 | Err(e) => format!("error: {e}"), |
| 1144 | }; |
| 1145 | let directive = stanza.input.lines().next().unwrap_or_default(); |
| 1146 | if rewrite { |
| 1147 | println!("{directive} => {actual}"); |
| 1148 | } else if actual == stanza.expected { |
| 1149 | println!("ok: {directive}"); |
| 1150 | } else { |
| 1151 | mismatches += 1; |
| 1152 | println!( |
| 1153 | "MISMATCH: {directive}\n expected: {:?}\n actual: {:?}", |
| 1154 | stanza.expected, actual |
| 1155 | ); |
| 1156 | } |
| 1157 | actuals.push(actual); |
| 1158 | } |
| 1159 | |
| 1160 | if rewrite { |
| 1161 | let path = path.context("REWRITE is set but the script came from stdin")?; |
| 1162 | std::fs::write(path, crate::text::rewrite(&items, &actuals)) |
| 1163 | .with_context(|| format!("rewriting {}", path.display()))?; |
| 1164 | return Ok(()); |
| 1165 | } |
| 1166 | if mismatches > 0 { |
| 1167 | anyhow::bail!("{mismatches} stanza(s) did not match their expected output"); |
| 1168 | } |
| 1169 | Ok(()) |
| 1170 | } |
| 1171 | |
| 1172 | /// Render peeked rows as deterministic golden text: each row's datums joined by |
| 1173 | /// spaces, with the rows sorted so the output is independent of arrangement order. |