builder: enforce target, source sync, and timeout contracts
This commit is contained in:
+34
-11
@@ -59,6 +59,25 @@ impl Builder {
|
||||
.contains(&action),
|
||||
"unsupported Cargo command"
|
||||
);
|
||||
let compiles = ["build", "check", "clippy", "test", "run"].contains(&action);
|
||||
let mut args = request.argv.iter().take_while(|arg| arg.as_str() != "--");
|
||||
while let Some(arg) = args.next() {
|
||||
ensure!(
|
||||
arg != "--target-dir" && !arg.starts_with("--target-dir="),
|
||||
"the builder controls the target directory"
|
||||
);
|
||||
let target = if arg == "--target" {
|
||||
args.next().map(String::as_str)
|
||||
} else {
|
||||
arg.strip_prefix("--target=")
|
||||
};
|
||||
if compiles && let Some(target) = target {
|
||||
ensure!(
|
||||
target == "wasm32-wasip2",
|
||||
"the build target is always wasm32-wasip2"
|
||||
);
|
||||
}
|
||||
}
|
||||
let seconds = request.timeout_secs.unwrap_or(1800);
|
||||
ensure!(seconds > 0, "timeout must be positive");
|
||||
let deadline = Instant::now()
|
||||
@@ -81,7 +100,7 @@ impl Builder {
|
||||
if source.exists() {
|
||||
std::fs::remove_dir_all(&source)?;
|
||||
}
|
||||
files::copy_out(self.root.as_ref(), &workspace, &source).await?;
|
||||
let before = files::copy_out(self.root.as_ref(), &workspace, &source).await?;
|
||||
for path in [&target, ®istry, &cache, &target.join("tmp")] {
|
||||
std::fs::create_dir_all(path)?;
|
||||
}
|
||||
@@ -147,7 +166,7 @@ impl Builder {
|
||||
startup.arg(tools.join("build.nu"));
|
||||
let (startup_code, _) = run(startup, tx, deadline).await?;
|
||||
if startup_code != 0 {
|
||||
files::copy_back(self.root.as_ref(), &source, &workspace, false).await?;
|
||||
files::copy_back(self.root.as_ref(), &source, &workspace, Some(&before)).await?;
|
||||
self.evict(20 * 1024 * 1024 * 1024)?;
|
||||
tx.send(Event::Exit {
|
||||
code: startup_code,
|
||||
@@ -238,7 +257,7 @@ impl Builder {
|
||||
}
|
||||
let split = args.iter().position(|a| a == "--").unwrap_or(args.len());
|
||||
cmd.args(&args[..split]);
|
||||
if ["build", "check", "clippy", "test", "run"].contains(&action) {
|
||||
if compiles {
|
||||
cmd.args([
|
||||
"--target",
|
||||
"wasm32-wasip2",
|
||||
@@ -257,7 +276,7 @@ impl Builder {
|
||||
self.root.as_ref(),
|
||||
&artifacts,
|
||||
&format!("{world_target}/wasm32-wasip2"),
|
||||
true,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
@@ -284,7 +303,7 @@ impl Builder {
|
||||
executables.dedup();
|
||||
}
|
||||
}
|
||||
files::copy_back(self.root.as_ref(), &source, &workspace, false).await?;
|
||||
files::copy_back(self.root.as_ref(), &source, &workspace, Some(&before)).await?;
|
||||
self.evict(20 * 1024 * 1024 * 1024)?;
|
||||
tx.send(Event::Exit { code, executables }).await?;
|
||||
Ok(())
|
||||
@@ -410,14 +429,18 @@ async fn run(
|
||||
)?;
|
||||
Ok::<_, anyhow::Error>((status.code().unwrap_or(1), out))
|
||||
};
|
||||
let result = tokio::select! {
|
||||
result = collect => result,
|
||||
let (result, timed_out) = tokio::select! {
|
||||
result = collect => (result, false),
|
||||
_ = tx.closed() => anyhow::bail!("caller exited"),
|
||||
_ = tokio::time::sleep_until(deadline) => {
|
||||
tx.send(Event::Stderr { bytes: b"cargo: command timed out\n".to_vec() }).await?;
|
||||
Ok((124, Vec::new()))
|
||||
}
|
||||
_ = tokio::time::sleep_until(deadline) => (Ok((124, Vec::new())), true),
|
||||
};
|
||||
// Kill the command before a full output channel can delay its timeout message.
|
||||
drop(group);
|
||||
if timed_out {
|
||||
tx.send(Event::Stderr {
|
||||
bytes: b"cargo: command timed out\n".to_vec(),
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user