Skip to content

Commit eafb17c

Browse files
committed
perf: avoid removing all files on prepare; prune the unused queries and add or update when needed
1 parent b180eba commit eafb17c

1 file changed

Lines changed: 55 additions & 1 deletion

File tree

sqlx-cli/src/prepare.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ async fn prepare(ctx: &PrepareCtx<'_>) -> anyhow::Result<()> {
7474
}
7575

7676
let prepare_dir = ctx.prepare_dir()?;
77-
run_prepare_step(ctx, &prepare_dir)?;
77+
let cache_dir = ctx.metadata.target_directory().join("sqlx-prepare");
78+
run_prepare_step(ctx, &cache_dir)?;
79+
sync_query_data(&cache_dir, &prepare_dir)?;
7880

7981
// Warn if no queries were generated. Glob since the directory may contain unrelated files.
8082
if glob_query_files(prepare_dir)?.is_empty() {
@@ -204,6 +206,58 @@ fn run_prepare_step(ctx: &PrepareCtx, cache_dir: &Path) -> anyhow::Result<()> {
204206
Ok(())
205207
}
206208

209+
fn sync_query_data(cache_dir: &Path, prepare_dir: &Path) -> anyhow::Result<()> {
210+
fs::create_dir_all(prepare_dir).context(format!(
211+
"Failed to create query cache directory: {:?}",
212+
prepare_dir
213+
))?;
214+
215+
let prepare_filenames: HashSet<String> = glob_query_files(prepare_dir)?
216+
.into_iter()
217+
.filter_map(|path| path.file_name().map(|f| f.to_string_lossy().into_owned()))
218+
.collect();
219+
let cache_filenames: HashSet<String> = glob_query_files(cache_dir)?
220+
.into_iter()
221+
.filter_map(|path| path.file_name().map(|f| f.to_string_lossy().into_owned()))
222+
.collect();
223+
224+
for stale_filename in prepare_filenames.difference(&cache_filenames) {
225+
let stale_file = prepare_dir.join(stale_filename);
226+
fs::remove_file(&stale_file)
227+
.with_context(|| format!("Failed to delete query file: {}", stale_file.display()))?;
228+
}
229+
230+
for filename in cache_filenames {
231+
let cache_file = cache_dir.join(&filename);
232+
let prepare_file = prepare_dir.join(&filename);
233+
234+
let should_copy = match fs::read(&prepare_file) {
235+
Ok(prepare_bytes) => {
236+
let cache_json = load_json_file(&cache_file)?;
237+
let prepare_json: serde_json::Value = serde_json::from_slice(&prepare_bytes)?;
238+
prepare_json != cache_json
239+
}
240+
Err(err) if err.kind() == std::io::ErrorKind::NotFound => true,
241+
Err(err) => {
242+
return Err(err)
243+
.with_context(|| format!("failed to load file: {}", prepare_file.display()))
244+
}
245+
};
246+
247+
if should_copy {
248+
fs::copy(&cache_file, &prepare_file).with_context(|| {
249+
format!(
250+
"Failed to copy query file from {} to {}",
251+
cache_file.display(),
252+
prepare_file.display()
253+
)
254+
})?;
255+
}
256+
}
257+
258+
Ok(())
259+
}
260+
207261
#[derive(Debug, PartialEq)]
208262
struct ProjectRecompileAction {
209263
// The names of the packages

0 commit comments

Comments
 (0)