summaryrefslogtreecommitdiff
path: root/cli/task_runner.rs
diff options
context:
space:
mode:
authorNathan Whitaker <17734409+nathanwhit@users.noreply.github.com>2024-10-12 12:14:32 -0700
committerGitHub <noreply@github.com>2024-10-12 12:14:32 -0700
commit7a990d9d42b633ca70eca235df0f9ba09f876720 (patch)
tree8c7db663923f478b77cea37a8cae77d59eb27479 /cli/task_runner.rs
parent8b2c6fc2d22f0a62ceefa71ff739f81796142699 (diff)
feat(npm): support `--allow-scripts` on `deno run` (and `deno add`, `deno test`, etc) (#26075)
Fixes https://github.com/denoland/deno/issues/25533. Fixes https://github.com/denoland/deno/issues/25396. Previously we only supported it on `deno install` and `deno cache`, which is annoying if you're using `nodeModulesDir: auto`. Also changes from printing output of lifecycle scripts directly to capturing the output and only printing it on error.
Diffstat (limited to 'cli/task_runner.rs')
-rw-r--r--cli/task_runner.rs93
1 files changed, 85 insertions, 8 deletions
diff --git a/cli/task_runner.rs b/cli/task_runner.rs
index ab7163bc9..418043b23 100644
--- a/cli/task_runner.rs
+++ b/cli/task_runner.rs
@@ -16,8 +16,11 @@ use deno_task_shell::ExecutableCommand;
use deno_task_shell::ExecuteResult;
use deno_task_shell::ShellCommand;
use deno_task_shell::ShellCommandContext;
+use deno_task_shell::ShellPipeReader;
+use deno_task_shell::ShellPipeWriter;
use lazy_regex::Lazy;
use regex::Regex;
+use tokio::task::JoinHandle;
use tokio::task::LocalSet;
use crate::npm::CliNpmResolver;
@@ -36,6 +39,35 @@ pub fn get_script_with_args(script: &str, argv: &[String]) -> String {
script.trim().to_owned()
}
+pub struct TaskStdio(Option<ShellPipeReader>, ShellPipeWriter);
+
+impl TaskStdio {
+ pub fn stdout() -> Self {
+ Self(None, ShellPipeWriter::stdout())
+ }
+ pub fn stderr() -> Self {
+ Self(None, ShellPipeWriter::stderr())
+ }
+ pub fn piped() -> Self {
+ let (r, w) = deno_task_shell::pipe();
+ Self(Some(r), w)
+ }
+}
+
+pub struct TaskIo {
+ pub stdout: TaskStdio,
+ pub stderr: TaskStdio,
+}
+
+impl Default for TaskIo {
+ fn default() -> Self {
+ Self {
+ stderr: TaskStdio::stderr(),
+ stdout: TaskStdio::stdout(),
+ }
+ }
+}
+
pub struct RunTaskOptions<'a> {
pub task_name: &'a str,
pub script: &'a str,
@@ -45,24 +77,69 @@ pub struct RunTaskOptions<'a> {
pub argv: &'a [String],
pub custom_commands: HashMap<String, Rc<dyn ShellCommand>>,
pub root_node_modules_dir: Option<&'a Path>,
+ pub stdio: Option<TaskIo>,
}
pub type TaskCustomCommands = HashMap<String, Rc<dyn ShellCommand>>;
-pub async fn run_task(opts: RunTaskOptions<'_>) -> Result<i32, AnyError> {
+pub struct TaskResult {
+ pub exit_code: i32,
+ pub stdout: Option<Vec<u8>>,
+ pub stderr: Option<Vec<u8>>,
+}
+
+pub async fn run_task(
+ opts: RunTaskOptions<'_>,
+) -> Result<TaskResult, AnyError> {
let script = get_script_with_args(opts.script, opts.argv);
let seq_list = deno_task_shell::parser::parse(&script)
.with_context(|| format!("Error parsing script '{}'.", opts.task_name))?;
let env_vars =
prepare_env_vars(opts.env_vars, opts.init_cwd, opts.root_node_modules_dir);
+ let state =
+ deno_task_shell::ShellState::new(env_vars, opts.cwd, opts.custom_commands);
+ let stdio = opts.stdio.unwrap_or_default();
+ let (
+ TaskStdio(stdout_read, stdout_write),
+ TaskStdio(stderr_read, stderr_write),
+ ) = (stdio.stdout, stdio.stderr);
+
+ fn read(reader: ShellPipeReader) -> JoinHandle<Result<Vec<u8>, AnyError>> {
+ tokio::task::spawn_blocking(move || {
+ let mut buf = Vec::new();
+ reader.pipe_to(&mut buf)?;
+ Ok(buf)
+ })
+ }
+
+ let stdout = stdout_read.map(read);
+ let stderr = stderr_read.map(read);
+
let local = LocalSet::new();
- let future = deno_task_shell::execute(
- seq_list,
- env_vars,
- opts.cwd,
- opts.custom_commands,
- );
- Ok(local.run_until(future).await)
+ let future = async move {
+ let exit_code = deno_task_shell::execute_with_pipes(
+ seq_list,
+ state,
+ ShellPipeReader::stdin(),
+ stdout_write,
+ stderr_write,
+ )
+ .await;
+ Ok::<_, AnyError>(TaskResult {
+ exit_code,
+ stdout: if let Some(stdout) = stdout {
+ Some(stdout.await??)
+ } else {
+ None
+ },
+ stderr: if let Some(stderr) = stderr {
+ Some(stderr.await??)
+ } else {
+ None
+ },
+ })
+ };
+ local.run_until(future).await
}
fn prepare_env_vars(