Skip to content

Commit 5f13540

Browse files
committed
Add dv clean
1 parent 08bca51 commit 5f13540

File tree

2 files changed

+211
-6
lines changed

2 files changed

+211
-6
lines changed

src/main.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ enum Commands {
4343
)]
4444
Compile(CompileArgs),
4545

46+
#[command(
47+
name = "clean",
48+
about = "Clean build artefacts produced by `cargo dv compile`",
49+
alias = "cl"
50+
)]
51+
Clean(CleanArgs),
52+
4653
#[command(
4754
name = "fingerprint",
4855
about = "Print the fingerprint of the verification targets",
@@ -268,6 +275,24 @@ struct CompileArgs {
268275
count_line: bool,
269276
}
270277

278+
#[derive(Parser, Debug)]
279+
struct CleanArgs {
280+
#[arg(
281+
short = 't',
282+
long = "targets",
283+
value_parser = verus::find_target,
284+
help = "The targets to clean",
285+
num_args = 0..,
286+
action = ArgAction::Append)]
287+
targets: Vec<VerusTarget>,
288+
#[arg(
289+
long = "all",
290+
help = "Clean verification artifacts for all workspace targets",
291+
default_value = "false",
292+
action = ArgAction::SetTrue)]
293+
all: bool,
294+
}
295+
271296
#[derive(Parser, Debug)]
272297
struct FingerprintArgs {
273298
#[arg(
@@ -440,6 +465,16 @@ fn fingerprint(args: &FingerprintArgs) -> Result<(), DynError> {
440465
Ok(())
441466
}
442467

468+
fn clean(args: &CleanArgs) -> Result<(), DynError> {
469+
let targets = args.targets.clone();
470+
// if --all provided, pass empty targets with all=true to verus
471+
if args.all {
472+
verus::exec_clean(&[], true)
473+
} else {
474+
verus::exec_clean(&targets, false)
475+
}
476+
}
477+
443478
fn list_targets(_args: &ListTargetsArgs) -> Result<(), DynError> {
444479
let targets = verus::verus_targets();
445480
let width = targets.keys().map(|s| s.len()).max().unwrap_or(0).min(70) + 1;
@@ -506,6 +541,7 @@ fn main() {
506541
Commands::NewTarget(args) => new_target(args),
507542
Commands::ShowItem(args) => show_item(args),
508543
Commands::Format(args) => format(args),
544+
Commands::Clean(args) => clean(args),
509545
} {
510546
error!("Error when executing command `{:?}`: {}", cli.command, e);
511547
}

src/verus.rs

Lines changed: 175 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,35 @@ impl VerusTarget {
271271
if !ts.exists() {
272272
return false;
273273
}
274+
275+
// Check if our own verification file exists
276+
if !self.library_proof().exists() {
277+
return false;
278+
}
279+
280+
// Get our own timestamp
281+
let self_timestamp = match std::fs::metadata(&self.library_proof()) {
282+
Ok(metadata) => metadata.modified().unwrap_or(std::time::UNIX_EPOCH),
283+
Err(_) => return false,
284+
};
285+
286+
// Check if all recursive dependencies have their verification files and are not newer than us
287+
let deps = get_local_dependency_recursive(self);
288+
for dep in deps.values() {
289+
if !dep.library_proof().exists() {
290+
return false;
291+
}
292+
293+
// Check if dependency is newer than us
294+
if let Ok(dep_metadata) = std::fs::metadata(&dep.library_proof()) {
295+
if let Ok(dep_timestamp) = dep_metadata.modified() {
296+
if dep_timestamp > self_timestamp {
297+
return false; // Dependency is newer, we need to rebuild
298+
}
299+
}
300+
}
301+
}
302+
274303
let ts_hash = self.load_library_proof_timestamp();
275304
let cur_hash = self.fingerprint_recursive(all_targets);
276305
if cur_hash == ts_hash {
@@ -537,8 +566,44 @@ pub fn get_local_dependency(target: &VerusTarget) -> IndexMap<String, VerusTarge
537566
deps
538567
}
539568

569+
pub fn get_local_dependency_recursive(target: &VerusTarget) -> IndexMap<String, VerusTarget> {
570+
let mut result = IndexMap::new();
571+
let mut visited = std::collections::HashSet::new();
572+
573+
fn collect_deps_recursive(
574+
target: &VerusTarget,
575+
result: &mut IndexMap<String, VerusTarget>,
576+
visited: &mut std::collections::HashSet<String>,
577+
_is_root: bool,
578+
) {
579+
let target_name = target.name.replace('-', "_");
580+
581+
// Prevent infinite recursion
582+
if visited.contains(&target_name) {
583+
return;
584+
}
585+
visited.insert(target_name.clone());
586+
587+
// Get direct dependencies
588+
let direct_deps = get_local_dependency(target);
589+
590+
// Add direct dependencies to result (unless it's the root target)
591+
for (dep_name, dep_target) in direct_deps.iter() {
592+
let dep_key = dep_name.replace('-', "_");
593+
if !result.contains_key(&dep_key) {
594+
result.insert(dep_key, dep_target.clone());
595+
}
596+
// Recursively collect dependencies of this dependency
597+
collect_deps_recursive(dep_target, result, visited, false);
598+
}
599+
}
600+
601+
collect_deps_recursive(target, &mut result, &mut visited, true);
602+
result
603+
}
604+
540605
pub fn get_dependent_targets(target: &VerusTarget, release: bool) -> IndexMap<String, VerusTarget> {
541-
let mut deps = get_local_dependency(target);
606+
let mut deps = get_local_dependency_recursive(target);
542607
let order = resolve_deps_cached(target, release).full_externs;
543608
deps.sort_by(|a, _, b, _| {
544609
let x = order.get_index_of(a).unwrap_or(usize::MAX);
@@ -554,7 +619,7 @@ pub fn get_dependent_targets_batch(
554619
) -> IndexMap<String, VerusTarget> {
555620
let mut deps = IndexMap::new();
556621
for target in targets.iter() {
557-
deps.extend(get_local_dependency(target));
622+
deps.extend(get_local_dependency_recursive(target));
558623
}
559624
let order = resolve_deps_cached(targets.first().unwrap(), release).full_externs;
560625
deps.sort_by(|a, _, b, _| {
@@ -622,6 +687,49 @@ pub fn check_import(imports: &[&VerusTarget]) -> Result<(), DynError> {
622687
Ok(())
623688
}
624689

690+
pub fn check_import_with_auto_compile(
691+
imports: &[&VerusTarget],
692+
options: &ExtraOptions,
693+
) -> Result<(), DynError> {
694+
let mut missing_targets = Vec::new();
695+
696+
for imp in imports.iter() {
697+
if !imp.library_proof().exists() || !imp.library_path().exists() {
698+
missing_targets.push((*imp).clone());
699+
}
700+
}
701+
702+
if !missing_targets.is_empty() {
703+
info!(
704+
"Missing verification files for dependencies: {:?}",
705+
missing_targets.iter().map(|t| &t.name).collect::<Vec<_>>()
706+
);
707+
info!("Automatically compiling missing dependencies...");
708+
709+
// Get all dependencies of missing targets to ensure proper compilation order
710+
let extended_targets = get_dependent_targets_batch(&missing_targets, options.release);
711+
for target in extended_targets.values() {
712+
if !target.library_proof().exists() {
713+
compile_target(target, &vec![], options).map_err(|e| {
714+
format!("Failed to auto-compile dependency `{}`: {}", target.name, e)
715+
})?;
716+
}
717+
}
718+
719+
// Compile the missing targets themselves
720+
for target in &missing_targets {
721+
if !target.library_proof().exists() {
722+
compile_target(target, &vec![], options).map_err(|e| {
723+
format!("Failed to auto-compile dependency `{}`: {}", target.name, e)
724+
})?;
725+
}
726+
}
727+
}
728+
729+
// Final check
730+
check_import(imports)
731+
}
732+
625733
pub fn check_externs(externs: &IndexMap<String, String>) -> Result<(), DynError> {
626734
for (name, path) in externs.iter() {
627735
if !Path::new(path).exists() {
@@ -757,7 +865,7 @@ pub fn compile_target(
757865

758866
prepare(target, options.release);
759867

760-
let mut deps = get_local_dependency(target);
868+
let mut deps = get_local_dependency_recursive(target);
761869
let dep_rebuilt = deps.values().into_iter().any(|t| t.rebuilt == true);
762870

763871
if !dep_rebuilt && target.is_fresh(&verus_targets()) {
@@ -791,7 +899,7 @@ pub fn compile_target(
791899
// imported dependencies
792900
deps.extend(extra_imports.clone());
793901
let all_imports = deps.values().collect::<Vec<_>>();
794-
check_import(all_imports.as_slice()).unwrap_or_else(|e| {
902+
check_import_with_auto_compile(all_imports.as_slice(), options).unwrap_or_else(|e| {
795903
error!("Error during verification: {}", e);
796904
});
797905
cmd_push_import(cmd, all_imports.as_slice());
@@ -935,11 +1043,11 @@ pub fn exec_verify(
9351043
}
9361044

9371045
// imported dependencies
938-
let deps = &mut get_local_dependency(target);
1046+
let deps = &mut get_local_dependency_recursive(target);
9391047
deps.extend(extra_imports.clone());
9401048
let all_imports = deps.values().collect::<Vec<_>>();
9411049

942-
check_import(all_imports.as_slice()).unwrap_or_else(|e| {
1050+
check_import_with_auto_compile(all_imports.as_slice(), options).unwrap_or_else(|e| {
9431051
error!("Error during verification: {}", e);
9441052
});
9451053
cmd_push_import(cmd, all_imports.as_slice());
@@ -1088,6 +1196,67 @@ pub fn exec_compile(
10881196
Ok(())
10891197
}
10901198

1199+
/// Clean build artefacts produced by `exec_compile`.
1200+
pub fn exec_clean(targets: &[VerusTarget], all: bool) -> Result<(), DynError> {
1201+
let out_dir = get_target_dir();
1202+
1203+
let to_clean: Vec<VerusTarget> = if all || targets.is_empty() {
1204+
// clean all known targets
1205+
verus_targets().values().cloned().collect()
1206+
} else {
1207+
targets.iter().cloned().collect()
1208+
};
1209+
1210+
for target in to_clean.iter() {
1211+
// remove .verusdata
1212+
let proof = target.library_proof();
1213+
if proof.exists() {
1214+
info!("Removing {}", proof.display());
1215+
std::fs::remove_file(&proof).unwrap_or_else(|e| {
1216+
warn!("Failed to remove {}: {}", proof.display(), e);
1217+
});
1218+
}
1219+
1220+
// remove .verusdata.timestamp
1221+
let proof_ts = target.library_proof_timestamp();
1222+
if proof_ts.exists() {
1223+
info!("Removing {}", proof_ts.display());
1224+
std::fs::remove_file(&proof_ts).unwrap_or_else(|e| {
1225+
warn!("Failed to remove {}: {}", proof_ts.display(), e);
1226+
});
1227+
}
1228+
1229+
// remove lib{name}.rlib
1230+
let lib = target.library_path();
1231+
if lib.exists() {
1232+
info!("Removing {}", lib.display());
1233+
std::fs::remove_file(&lib).unwrap_or_else(|e| {
1234+
warn!("Failed to remove {}: {}", lib.display(), e);
1235+
});
1236+
}
1237+
1238+
// remove generated extern_crates
1239+
let extern_crates_path = out_dir.join(format!("{}.extern_crates.rs", target.name));
1240+
if extern_crates_path.exists() {
1241+
info!("Removing {}", extern_crates_path.display());
1242+
std::fs::remove_file(&extern_crates_path).unwrap_or_else(|e| {
1243+
warn!("Failed to remove {}: {}", extern_crates_path.display(), e);
1244+
});
1245+
}
1246+
1247+
// remove deps.toml
1248+
let deps_toml_path = out_dir.join(format!("{}.deps.toml", target.name));
1249+
if deps_toml_path.exists() {
1250+
info!("Removing {}", deps_toml_path.display());
1251+
std::fs::remove_file(&deps_toml_path).unwrap_or_else(|e| {
1252+
warn!("Failed to remove {}: {}", deps_toml_path.display(), e);
1253+
});
1254+
}
1255+
}
1256+
1257+
Ok(())
1258+
}
1259+
10911260
pub mod install {
10921261
use super::*;
10931262
use crate::toolchain;

0 commit comments

Comments
 (0)