Skip to content

Commit c163a0d

Browse files
feat(apollo_infra_utils): better cairo0 compiler checks
1 parent e099557 commit c163a0d

File tree

5 files changed

+82
-27
lines changed

5 files changed

+82
-27
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/apollo_infra_utils/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@ colored = { workspace = true, optional = true }
1919
serde = { workspace = true, features = ["derive"] }
2020
serde_json.workspace = true
2121
socket2 = { workspace = true, optional = true }
22+
thiserror.workspace = true
2223
tokio = { workspace = true, features = ["process", "rt", "time"] }
2324
toml = { workspace = true, optional = true }
2425
tracing.workspace = true
2526

2627
[dev-dependencies]
28+
assert-json-diff.workspace = true
2729
cached.workspace = true
30+
colored.workspace = true
2831
nix.workspace = true
2932
pretty_assertions.workspace = true
3033
rstest.workspace = true
Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,74 @@
1-
use std::fs;
1+
#[cfg(any(test, feature = "testing"))]
22
use std::path::PathBuf;
33
use std::process::Command;
4+
#[cfg(any(test, feature = "testing"))]
45
use std::sync::LazyLock;
56

7+
#[cfg(any(test, feature = "testing"))]
68
use crate::path::resolve_project_relative_path;
79

10+
#[cfg(test)]
11+
#[path = "cairo0_compiler_test.rs"]
12+
pub mod test;
13+
14+
pub const STARKNET_COMPILE_DEPRECATED: &str = "starknet-compile-deprecated";
15+
pub const CAIRO0_COMPILE: &str = "cairo-compile";
16+
pub const EXPECTED_CAIRO0_VERSION: &str = "0.13.5";
17+
818
/// The local python requirements used to determine the cairo0 compiler version.
9-
static PIP_REQUIREMENTS_FILE: LazyLock<PathBuf> =
19+
#[cfg(any(test, feature = "testing"))]
20+
pub(crate) static PIP_REQUIREMENTS_FILE: LazyLock<PathBuf> =
1021
LazyLock::new(|| resolve_project_relative_path("scripts/requirements.txt").unwrap());
1122

23+
#[derive(thiserror::Error, Debug)]
24+
pub enum Cairo0CompilerVersionError {
25+
#[error("{compiler} version is not correct: required {required}, got {existing}.")]
26+
IncorrectVersion { compiler: String, existing: String, required: String },
27+
#[error("{0} not found.")]
28+
NotFound(String),
29+
}
30+
31+
pub fn cairo0_compilers_correct_version() -> Result<(), Cairo0CompilerVersionError> {
32+
for compiler in [CAIRO0_COMPILE, STARKNET_COMPILE_DEPRECATED] {
33+
let version = match Command::new(compiler).arg("--version").output() {
34+
Ok(output) => String::from_utf8_lossy(&output.stdout).to_string(),
35+
Err(error) => {
36+
return Err(Cairo0CompilerVersionError::NotFound(format!(
37+
"Failed to get {compiler} version: {error}."
38+
)));
39+
}
40+
};
41+
if !version.trim().ends_with(EXPECTED_CAIRO0_VERSION) {
42+
return Err(Cairo0CompilerVersionError::IncorrectVersion {
43+
compiler: compiler.to_string(),
44+
existing: version,
45+
required: EXPECTED_CAIRO0_VERSION.to_string(),
46+
});
47+
}
48+
}
49+
50+
Ok(())
51+
}
52+
1253
/// Verifies that the required Cairo0 compiler is available; panics if unavailable.
54+
/// For use in tests only. If cairo0 compiler verification is required in business logic, use
55+
/// `crate::cairo0_compiler::cairo0_compilers_correct_version` instead.
56+
#[cfg(any(test, feature = "testing"))]
1357
pub fn verify_cairo0_compiler_deps() {
14-
// Python compiler. Verify correct version.
15-
let cairo_lang_version_output =
16-
Command::new("sh").arg("-c").arg("pip freeze | grep cairo-lang").output().unwrap().stdout;
17-
let cairo_lang_version_untrimmed = String::from_utf8(cairo_lang_version_output).unwrap();
18-
let cairo_lang_version = cairo_lang_version_untrimmed.trim();
19-
let requirements_contents = fs::read_to_string(&*PIP_REQUIREMENTS_FILE).unwrap();
20-
let expected_cairo_lang_version = requirements_contents
21-
.lines()
22-
.find(|line| line.starts_with("cairo-lang"))
23-
.unwrap_or_else(|| panic!("Could not find cairo-lang in {:?}.", *PIP_REQUIREMENTS_FILE))
24-
.trim();
25-
26-
assert!(
27-
expected_cairo_lang_version.ends_with(cairo_lang_version),
28-
"cairo-lang version {expected_cairo_lang_version} not found ({}). Run the following \
29-
commands (enter a python venv and install dependencies) and retry:\npython -m venv \
30-
sequencer_venv\n. sequencer_venv/bin/activate\npip install -r {:?}",
31-
if cairo_lang_version.is_empty() {
32-
String::from("no installed cairo-lang found")
33-
} else {
34-
format!("installed version: {cairo_lang_version}")
35-
},
36-
*PIP_REQUIREMENTS_FILE
58+
let specific_error = match cairo0_compilers_correct_version() {
59+
Ok(_) => {
60+
return;
61+
}
62+
Err(Cairo0CompilerVersionError::NotFound(_)) => "no installed cairo-lang found".to_string(),
63+
Err(Cairo0CompilerVersionError::IncorrectVersion { existing, .. }) => {
64+
format!("installed version: {existing}")
65+
}
66+
};
67+
68+
panic!(
69+
"cairo-lang version {EXPECTED_CAIRO0_VERSION} not found ({specific_error}). Run the \
70+
following commands (enter a python venv and install dependencies) and retry:\npython -m \
71+
venv sequencer_venv\n. sequencer_venv/bin/activate\npip install -r {:?}",
72+
PIP_REQUIREMENTS_FILE.to_str().expect("Path to requirements.txt is valid unicode.")
3773
);
3874
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use crate::cairo0_compiler::{EXPECTED_CAIRO0_VERSION, PIP_REQUIREMENTS_FILE};
2+
3+
#[test]
4+
fn test_cairo0_version_pip_requirements() {
5+
let requirements_contents = std::fs::read_to_string(&*PIP_REQUIREMENTS_FILE).unwrap();
6+
let pip_cairo_lang_version = requirements_contents
7+
.lines()
8+
.find(|line| line.starts_with("cairo-lang"))
9+
.unwrap_or_else(|| panic!("Could not find cairo-lang in {:?}.", *PIP_REQUIREMENTS_FILE))
10+
.trim();
11+
assert_eq!(pip_cairo_lang_version, format!("cairo-lang=={EXPECTED_CAIRO0_VERSION}"));
12+
}

crates/blockifier_test_utils/src/cairo_compile.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use std::io::Write;
33
use std::path::{Path, PathBuf};
44
use std::process::{Command, Output};
55

6-
use apollo_infra_utils::cairo0_compiler::verify_cairo0_compiler_deps;
6+
use apollo_infra_utils::cairo0_compiler::{
7+
verify_cairo0_compiler_deps,
8+
STARKNET_COMPILE_DEPRECATED,
9+
};
710
use apollo_infra_utils::cairo_compiler_version::cairo1_compiler_version;
811
use apollo_infra_utils::compile_time_cargo_manifest_dir;
912
use tempfile::NamedTempFile;
@@ -53,7 +56,7 @@ pub fn cairo0_compile(
5356
debug_info: bool,
5457
) -> CompilationArtifacts {
5558
verify_cairo0_compiler_deps();
56-
let mut command = Command::new("starknet-compile-deprecated");
59+
let mut command = Command::new(STARKNET_COMPILE_DEPRECATED);
5760
command.arg(&path);
5861
if let Some(extra_arg) = extra_arg {
5962
command.arg(extra_arg);

0 commit comments

Comments
 (0)