1- use std:: fs;
21use std:: path:: PathBuf ;
32use std:: process:: Command ;
43use std:: sync:: LazyLock ;
54
65use crate :: path:: resolve_project_relative_path;
76
7+ #[ cfg( test) ]
8+ #[ path = "cairo0_compiler_test.rs" ]
9+ pub mod test;
10+
11+ pub const STARKNET_COMPILE_DEPRECATED : & str = "starknet-compile-deprecated" ;
12+ pub const CAIRO0_COMPILE : & str = "cairo-compile" ;
13+ pub const EXPECTED_CAIRO0_VERSION : & str = "0.14.0a1" ;
14+
815/// The local python requirements used to determine the cairo0 compiler version.
9- static PIP_REQUIREMENTS_FILE : LazyLock < PathBuf > =
16+ pub ( crate ) static PIP_REQUIREMENTS_FILE : LazyLock < PathBuf > =
1017 LazyLock :: new ( || resolve_project_relative_path ( "scripts/requirements.txt" ) . unwrap ( ) ) ;
1118
1219static ENTER_VENV_INSTRUCTIONS : LazyLock < String > = LazyLock :: new ( || {
@@ -19,40 +26,67 @@ pip install -r {:#?}"#,
1926 )
2027} ) ;
2128
29+ #[ derive( thiserror:: Error , Debug ) ]
30+ pub enum Cairo0CompilerVersionError {
31+ #[ error(
32+ "{compiler} version is not correct: required {required}, got {existing}. Are you in the \
33+ venv? If not, run the following commands:\n {}", * ENTER_VENV_INSTRUCTIONS
34+ ) ]
35+ IncorrectVersion { compiler : String , existing : String , required : String } ,
36+ #[ error(
37+ "{0}. Are you in the venv? If not, run the following commands:\n {}" ,
38+ * ENTER_VENV_INSTRUCTIONS
39+ ) ]
40+ NotFound ( String ) ,
41+ }
42+
43+ pub fn cairo0_compilers_correct_version ( ) -> Result < ( ) , Cairo0CompilerVersionError > {
44+ for compiler in [ CAIRO0_COMPILE , STARKNET_COMPILE_DEPRECATED ] {
45+ let version = match Command :: new ( compiler) . arg ( "--version" ) . output ( ) {
46+ Ok ( output) => String :: from_utf8_lossy ( & output. stdout ) . to_string ( ) ,
47+ Err ( error) => {
48+ return Err ( Cairo0CompilerVersionError :: NotFound ( format ! (
49+ "Failed to get {compiler} version: {error}."
50+ ) ) ) ;
51+ }
52+ } ;
53+ if version
54+ . trim ( )
55+ . replace ( "==" , " " )
56+ . split ( " " )
57+ . nth ( 1 )
58+ . ok_or ( Cairo0CompilerVersionError :: NotFound ( "No compiler version found." . to_string ( ) ) ) ?
59+ != EXPECTED_CAIRO0_VERSION
60+ {
61+ return Err ( Cairo0CompilerVersionError :: IncorrectVersion {
62+ compiler : compiler. to_string ( ) ,
63+ existing : version,
64+ required : EXPECTED_CAIRO0_VERSION . to_string ( ) ,
65+ } ) ;
66+ }
67+ }
68+
69+ Ok ( ( ) )
70+ }
71+
2272/// Verifies that the required Cairo0 compiler is available; panics if unavailable.
73+ /// For use in tests only. If cairo0 compiler verification is required in business logic, use
74+ /// `crate::cairo0_compiler::cairo0_compilers_correct_version` instead.
75+ #[ cfg( any( test, feature = "testing" ) ) ]
2376pub fn verify_cairo0_compiler_deps ( ) {
24- // Python compiler. Verify correct version.
25- let cairo_lang_version_output =
26- Command :: new ( "sh" ) . arg ( "-c" ) . arg ( "pip freeze | grep cairo-lang" ) . output ( ) . unwrap ( ) . stdout ;
27- let cairo_lang_version_untrimmed = String :: from_utf8 ( cairo_lang_version_output) . unwrap ( ) ;
28- let cairo_lang_version =
29- cairo_lang_version_untrimmed. trim ( ) . split ( "==" ) . nth ( 1 ) . unwrap_or_else ( || {
30- panic ! (
31- "Unexpected cairo-lang version format '{cairo_lang_version_untrimmed}'. Are you \
32- in a venv? If not, run:\n {}",
33- * ENTER_VENV_INSTRUCTIONS
34- )
35- } ) ;
36- let requirements_contents = fs:: read_to_string ( & * PIP_REQUIREMENTS_FILE ) . unwrap ( ) ;
37- let expected_cairo_lang_version = requirements_contents
38- . lines ( )
39- . find ( |line| line. starts_with ( "cairo-lang" ) )
40- . unwrap_or_else ( || panic ! ( "Could not find cairo-lang in {:?}." , * PIP_REQUIREMENTS_FILE ) )
41- . trim ( )
42- . split ( "==" )
43- . nth ( 1 )
44- . unwrap_or_else ( || {
45- panic ! (
46- "Malformed cairo-lang dependency (expected 'cairo-lang==X') in {:?}." ,
47- * PIP_REQUIREMENTS_FILE
48- )
49- } ) ;
50-
51- assert_eq ! (
52- expected_cairo_lang_version, cairo_lang_version,
53- "cairo-lang version {expected_cairo_lang_version} not found (installed version: \
54- {cairo_lang_version}). Run the following commands (enter a python venv and install \
55- dependencies) and retry:\n {}",
77+ let specific_error = match cairo0_compilers_correct_version ( ) {
78+ Ok ( _) => {
79+ return ;
80+ }
81+ Err ( Cairo0CompilerVersionError :: NotFound ( _) ) => "no installed cairo-lang found" . to_string ( ) ,
82+ Err ( Cairo0CompilerVersionError :: IncorrectVersion { existing, .. } ) => {
83+ format ! ( "installed version: {existing}" )
84+ }
85+ } ;
86+
87+ panic ! (
88+ "cairo-lang version {EXPECTED_CAIRO0_VERSION} not found ({specific_error}). Please enter \
89+ a venv and rerun the test:\n {}",
5690 * ENTER_VENV_INSTRUCTIONS
5791 ) ;
5892}
0 commit comments