|
| 1 | +use std::path::Path; |
1 | 2 | use std::process::Command; |
2 | 3 |
|
3 | 4 | use tempfile::TempDir; |
@@ -64,3 +65,45 @@ pub fn install_compiler_binary( |
64 | 65 |
|
65 | 66 | println!("Successfully set executable file: {:?}", binary_path.display()); |
66 | 67 | } |
| 68 | + |
| 69 | +/// Verifies that a compiler binary is installed and has the required version. |
| 70 | +/// Panics with installation instructions if the binary is missing or has the wrong version. |
| 71 | +/// |
| 72 | +/// Expects `--version` output in the form `<binary-name> <version>` (with optional |
| 73 | +/// trailing tokens). The match is anchored to the binary's own file name so that |
| 74 | +/// a misbehaving or substituted binary printing a stray dotted token elsewhere in |
| 75 | +/// its output cannot satisfy the check. |
| 76 | +pub fn verify_compiler_binary(binary_path: &Path, required_version: &str) { |
| 77 | + let binary_name = binary_path.display(); |
| 78 | + let expected_prefix = binary_path |
| 79 | + .file_name() |
| 80 | + .and_then(|name| name.to_str()) |
| 81 | + .unwrap_or_else(|| panic!("{binary_name} has no UTF-8 file name.")); |
| 82 | + let install_instructions = |
| 83 | + "Run 'scripts/install_compiler_binaries.sh' to install the correct version."; |
| 84 | + match Command::new(binary_path).arg("--version").output() { |
| 85 | + Ok(output) => { |
| 86 | + let version_output = String::from_utf8_lossy(&output.stdout); |
| 87 | + // Expect "<binary-name> <version>" on the first non-empty line. Anchoring |
| 88 | + // to <binary-name> avoids both substring false-positives ("1.0.1" vs |
| 89 | + // "1.0.10") and adversarial padding (e.g. a banner that includes the |
| 90 | + // required version elsewhere in stdout). |
| 91 | + let first_line = version_output.lines().find(|line| !line.trim().is_empty()); |
| 92 | + let installed_version = first_line |
| 93 | + .and_then(|line| line.strip_prefix(expected_prefix)) |
| 94 | + .map(|rest| rest.trim_start()) |
| 95 | + .and_then(|rest| rest.split_whitespace().next()) |
| 96 | + .unwrap_or(""); |
| 97 | + if installed_version != required_version { |
| 98 | + panic!( |
| 99 | + "{binary_name} version {required_version} is required, but found: \ |
| 100 | + {installed_version:?} (raw output: {version_output:?}). \ |
| 101 | + {install_instructions}" |
| 102 | + ); |
| 103 | + } |
| 104 | + } |
| 105 | + Err(_) => { |
| 106 | + panic!("{binary_name} not found. {install_instructions}"); |
| 107 | + } |
| 108 | + } |
| 109 | +} |
0 commit comments