1+ use crate :: helpers;
2+
13use super :: build_types:: { BuildState , CompilerInfo } ;
24use super :: clean;
35use super :: packages;
@@ -12,23 +14,23 @@ use std::io::Write;
1214// If something is not there, that is fine, we will treat it as a mismatch
1315#[ derive( Serialize , Deserialize ) ]
1416struct CompilerInfoFile {
15- #[ serde( skip_serializing_if = "Option::is_none" ) ]
16- version : Option < String > ,
17- #[ serde( skip_serializing_if = "Option::is_none" ) ]
18- bsc_path : Option < String > ,
19- #[ serde( skip_serializing_if = "Option::is_none" ) ]
20- bsc_hash : Option < String > ,
21- #[ serde( skip_serializing_if = "Option::is_none" ) ]
22- runtime_path : Option < String > ,
23- #[ serde( skip_serializing_if = "Option::is_none" ) ]
24- generated_at : Option < String > ,
17+ version : String ,
18+ bsc_path : String ,
19+ bsc_hash : String ,
20+ rescript_config_hash : String ,
21+ runtime_path : String ,
22+ generated_at : String ,
2523}
2624
2725pub enum CompilerCheckResult {
2826 SameCompilerAsLastRun ,
2927 CleanedPackagesDueToCompiler ,
3028}
3129
30+ fn get_rescript_config_hash ( package : & packages:: Package ) -> Option < String > {
31+ helpers:: compute_file_hash ( & package. config . path ) . map ( |hash| hash. to_hex ( ) . to_string ( ) )
32+ }
33+
3234pub fn verify_compiler_info (
3335 packages : & AHashMap < String , packages:: Package > ,
3436 compiler : & CompilerInfo ,
@@ -51,35 +53,48 @@ pub fn verify_compiler_info(
5153 let current_bsc_path_str = compiler. bsc_path . to_string_lossy ( ) ;
5254 let current_bsc_hash_hex = compiler. bsc_hash . to_hex ( ) . to_string ( ) ;
5355 let current_runtime_path_str = compiler. runtime_path . to_string_lossy ( ) ;
56+ let current_rescript_config_hash = match get_rescript_config_hash ( package) {
57+ Some ( hash) => hash,
58+ None => return true , // can't compute hash -> treat as mismatch
59+ } ;
5460
5561 let mut mismatch = false ;
56- if parsed. bsc_path . as_deref ( ) != Some ( & current_bsc_path_str) {
62+ if parsed. bsc_path != current_bsc_path_str {
5763 log:: debug!(
5864 "compiler-info mismatch for {}: bsc_path changed (stored='{}', current='{}')" ,
5965 package. name,
60- parsed. bsc_path. as_deref ( ) . unwrap_or ( "<missing>" ) ,
66+ parsed. bsc_path,
6167 current_bsc_path_str
6268 ) ;
6369 mismatch = true ;
6470 }
65- if parsed. bsc_hash . as_deref ( ) != Some ( & current_bsc_hash_hex) {
71+ if parsed. bsc_hash != current_bsc_hash_hex {
6672 log:: debug!(
6773 "compiler-info mismatch for {}: bsc_hash changed (stored='{}', current='{}')" ,
6874 package. name,
69- parsed. bsc_hash. as_deref ( ) . unwrap_or ( "<missing>" ) ,
75+ parsed. bsc_hash,
7076 current_bsc_hash_hex
7177 ) ;
7278 mismatch = true ;
7379 }
74- if parsed. runtime_path . as_deref ( ) != Some ( & current_runtime_path_str) {
80+ if parsed. runtime_path != current_runtime_path_str {
7581 log:: debug!(
7682 "compiler-info mismatch for {}: runtime_path changed (stored='{}', current='{}')" ,
7783 package. name,
78- parsed. runtime_path. as_deref ( ) . unwrap_or ( "<missing>" ) ,
84+ parsed. runtime_path,
7985 current_runtime_path_str
8086 ) ;
8187 mismatch = true ;
8288 }
89+ if parsed. rescript_config_hash != current_rescript_config_hash {
90+ log:: debug!(
91+ "compiler-info mismatch for {}: rescript_config_hash changed (stored='{}', current='{}')" ,
92+ package. name,
93+ parsed. rescript_config_hash,
94+ current_rescript_config_hash
95+ ) ;
96+ mismatch = true ;
97+ }
8398
8499 mismatch
85100 } )
@@ -98,46 +113,58 @@ pub fn verify_compiler_info(
98113}
99114
100115pub fn write_compiler_info ( build_state : & BuildState ) {
101- let bsc_path_str = build_state. compiler_info . bsc_path . to_string_lossy ( ) . to_string ( ) ;
102- let bsc_hash_hex = build_state. compiler_info . bsc_hash . to_hex ( ) . to_string ( ) ;
103- let runtime_path_str = build_state
116+ let bsc_path = build_state. compiler_info . bsc_path . to_string_lossy ( ) . to_string ( ) ;
117+ let bsc_hash = build_state. compiler_info . bsc_hash . to_hex ( ) . to_string ( ) ;
118+ let runtime_path = build_state
104119 . compiler_info
105120 . runtime_path
106121 . to_string_lossy ( )
107122 . to_string ( ) ;
108-
109123 // derive version from the crate version
110124 let version = env ! ( "CARGO_PKG_VERSION" ) . to_string ( ) ;
111125 let generated_at = crate :: helpers:: get_system_time ( ) . to_string ( ) ;
112126
113- let out = CompilerInfoFile {
114- version : Some ( version) ,
115- bsc_path : Some ( bsc_path_str) ,
116- bsc_hash : Some ( bsc_hash_hex) ,
117- runtime_path : Some ( runtime_path_str) ,
118- generated_at : Some ( generated_at) ,
119- } ;
120- let contents = serde_json:: to_string_pretty ( & out) . unwrap_or_else ( |_| String :: new ( ) ) ;
127+ // Borrowing serializer to avoid cloning the constant fields for every package
128+ #[ derive( Serialize ) ]
129+ struct CompilerInfoFileRef < ' a > {
130+ version : & ' a str ,
131+ bsc_path : & ' a str ,
132+ bsc_hash : & ' a str ,
133+ rescript_config_hash : String ,
134+ runtime_path : & ' a str ,
135+ generated_at : & ' a str ,
136+ }
121137
122138 build_state. packages . values ( ) . par_bridge ( ) . for_each ( |package| {
123- let info_path = package. get_compiler_info_path ( ) ;
124- let should_write = match std:: fs:: read_to_string ( & info_path) {
125- Ok ( existing) => existing != contents,
126- Err ( _) => true ,
127- } ;
139+ if let Some ( rescript_config_hash) = helpers:: compute_file_hash ( & package. config . path ) {
140+ let out = CompilerInfoFileRef {
141+ version : & version,
142+ bsc_path : & bsc_path,
143+ bsc_hash : & bsc_hash,
144+ rescript_config_hash : rescript_config_hash. to_hex ( ) . to_string ( ) ,
145+ runtime_path : & runtime_path,
146+ generated_at : & generated_at,
147+ } ;
148+ let contents = serde_json:: to_string_pretty ( & out) . unwrap_or_else ( |_| String :: new ( ) ) ;
149+ let info_path = package. get_compiler_info_path ( ) ;
150+ let should_write = match std:: fs:: read_to_string ( & info_path) {
151+ Ok ( existing) => existing != contents,
152+ Err ( _) => true ,
153+ } ;
128154
129- if should_write {
130- if let Some ( parent) = info_path. parent ( ) {
131- let _ = std:: fs:: create_dir_all ( parent) ;
132- }
133- // We write atomically to avoid leaving a partially written JSON file
134- // (e.g. process interruption) that would be read on the next init as an
135- // invalid/mismatched compiler-info, causing unnecessary cleans. The
136- // rename within the same directory is atomic on common platforms.
137- let tmp = info_path. with_extension ( "json.tmp" ) ;
138- if let Ok ( mut f) = File :: create ( & tmp) {
139- let _ = f. write_all ( contents. as_bytes ( ) ) ;
140- let _ = std:: fs:: rename ( & tmp, & info_path) ;
155+ if should_write {
156+ if let Some ( parent) = info_path. parent ( ) {
157+ let _ = std:: fs:: create_dir_all ( parent) ;
158+ }
159+ // We write atomically to avoid leaving a partially written JSON file
160+ // (e.g. process interruption) that would be read on the next init as an
161+ // invalid/mismatched compiler-info, causing unnecessary cleans. The
162+ // rename within the same directory is atomic on common platforms.
163+ let tmp = info_path. with_extension ( "json.tmp" ) ;
164+ if let Ok ( mut f) = File :: create ( & tmp) {
165+ let _ = f. write_all ( contents. as_bytes ( ) ) ;
166+ let _ = std:: fs:: rename ( & tmp, & info_path) ;
167+ }
141168 }
142169 }
143170 } ) ;
0 commit comments