Skip to content

Commit bbaf9e1

Browse files
committed
Take rescript.json hash into account
1 parent 6d337e0 commit bbaf9e1

File tree

1 file changed

+72
-45
lines changed

1 file changed

+72
-45
lines changed

rewatch/src/build/compiler_info.rs

Lines changed: 72 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::helpers;
2+
13
use super::build_types::{BuildState, CompilerInfo};
24
use super::clean;
35
use 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)]
1416
struct 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

2725
pub 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+
3234
pub 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

100115
pub 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

Comments
 (0)