summaryrefslogtreecommitdiff
path: root/cli/args
diff options
context:
space:
mode:
Diffstat (limited to 'cli/args')
-rw-r--r--cli/args/flags.rs98
-rw-r--r--cli/args/mod.rs14
2 files changed, 111 insertions, 1 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs
index b07f3783a..48cfb9240 100644
--- a/cli/args/flags.rs
+++ b/cli/args/flags.rs
@@ -507,6 +507,30 @@ pub enum CaData {
Bytes(Vec<u8>),
}
+// Info needed to run NPM lifecycle scripts
+#[derive(Clone, Debug, Eq, PartialEq, Default)]
+pub struct LifecycleScriptsConfig {
+ pub allowed: PackagesAllowedScripts,
+ pub initial_cwd: Option<PathBuf>,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, Default)]
+/// The set of npm packages that are allowed to run lifecycle scripts.
+pub enum PackagesAllowedScripts {
+ All,
+ Some(Vec<String>),
+ #[default]
+ None,
+}
+
+fn parse_packages_allowed_scripts(s: &str) -> Result<String, AnyError> {
+ if !s.starts_with("npm:") {
+ bail!("Invalid package for --allow-scripts: '{}'. An 'npm:' specifier is required", s);
+ } else {
+ Ok(s.into())
+ }
+}
+
#[derive(
Clone, Default, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize,
)]
@@ -562,6 +586,7 @@ pub struct Flags {
pub v8_flags: Vec<String>,
pub code_cache_enabled: bool,
pub permissions: PermissionFlags,
+ pub allow_scripts: PackagesAllowedScripts,
}
#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
@@ -1502,6 +1527,7 @@ Future runs of this module will trigger no downloads or compilation unless
.value_hint(ValueHint::FilePath),
)
.arg(frozen_lockfile_arg())
+ .arg(allow_scripts_arg())
})
}
@@ -2213,7 +2239,7 @@ The installation root is determined, in order of precedence:
These must be added to the path manually if required.")
.defer(|cmd| {
- let cmd = runtime_args(cmd, true, true).arg(check_arg(true));
+ let cmd = runtime_args(cmd, true, true).arg(check_arg(true)).arg(allow_scripts_arg());
install_args(cmd, true)
})
}
@@ -3728,6 +3754,28 @@ fn unsafely_ignore_certificate_errors_arg() -> Arg {
.value_parser(flags_net::validator)
}
+fn allow_scripts_arg() -> Arg {
+ Arg::new("allow-scripts")
+ .long("allow-scripts")
+ .num_args(0..)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .value_name("PACKAGE")
+ .value_parser(parse_packages_allowed_scripts)
+ .help("Allow running npm lifecycle scripts for the given packages. Note: Scripts will only be executed when using a node_modules directory (`--node-modules-dir`)")
+}
+
+fn allow_scripts_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
+ let Some(parts) = matches.remove_many::<String>("allow-scripts") else {
+ return;
+ };
+ if parts.len() == 0 {
+ flags.allow_scripts = PackagesAllowedScripts::All;
+ } else {
+ flags.allow_scripts = PackagesAllowedScripts::Some(parts.collect());
+ }
+}
+
fn add_parse(flags: &mut Flags, matches: &mut ArgMatches) {
flags.subcommand = DenoSubcommand::Add(add_parse_inner(matches, None));
}
@@ -3810,6 +3858,7 @@ fn bundle_parse(flags: &mut Flags, matches: &mut ArgMatches) {
fn cache_parse(flags: &mut Flags, matches: &mut ArgMatches) {
compile_args_parse(flags, matches);
frozen_lockfile_arg_parse(flags, matches);
+ allow_scripts_arg_parse(flags, matches);
let files = matches.remove_many::<String>("file").unwrap().collect();
flags.subcommand = DenoSubcommand::Cache(CacheFlags { files });
}
@@ -4096,6 +4145,7 @@ fn install_parse(flags: &mut Flags, matches: &mut ArgMatches) {
let local_flags = matches
.remove_many("cmd")
.map(|packages| add_parse_inner(matches, Some(packages)));
+ allow_scripts_arg_parse(flags, matches);
flags.subcommand = DenoSubcommand::Install(InstallFlags {
global,
kind: InstallKind::Local(local_flags),
@@ -9969,4 +10019,50 @@ mod tests {
);
}
}
+
+ #[test]
+ fn allow_scripts() {
+ let cases = [
+ (Some("--allow-scripts"), Ok(PackagesAllowedScripts::All)),
+ (None, Ok(PackagesAllowedScripts::None)),
+ (
+ Some("--allow-scripts=npm:foo"),
+ Ok(PackagesAllowedScripts::Some(svec!["npm:foo"])),
+ ),
+ (
+ Some("--allow-scripts=npm:foo,npm:bar"),
+ Ok(PackagesAllowedScripts::Some(svec!["npm:foo", "npm:bar"])),
+ ),
+ (Some("--allow-scripts=foo"), Err("Invalid package")),
+ ];
+ for (flag, value) in cases {
+ let mut args = svec!["deno", "cache"];
+ if let Some(flag) = flag {
+ args.push(flag.into());
+ }
+ args.push("script.ts".into());
+ let r = flags_from_vec(args);
+ match value {
+ Ok(value) => {
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Cache(CacheFlags {
+ files: svec!["script.ts"],
+ }),
+ allow_scripts: value,
+ ..Flags::default()
+ }
+ );
+ }
+ Err(e) => {
+ let err = r.unwrap_err();
+ assert!(
+ err.to_string().contains(e),
+ "expected to contain '{e}' got '{err}'"
+ );
+ }
+ }
+ }
+ }
}
diff --git a/cli/args/mod.rs b/cli/args/mod.rs
index 553af51a1..e048b332a 100644
--- a/cli/args/mod.rs
+++ b/cli/args/mod.rs
@@ -1720,6 +1720,20 @@ impl CliOptions {
}
full_paths
}
+
+ pub fn lifecycle_scripts_config(&self) -> LifecycleScriptsConfig {
+ LifecycleScriptsConfig {
+ allowed: self.flags.allow_scripts.clone(),
+ initial_cwd: if matches!(
+ self.flags.allow_scripts,
+ PackagesAllowedScripts::None
+ ) {
+ None
+ } else {
+ Some(self.initial_cwd.clone())
+ },
+ }
+ }
}
/// Resolves the path to use for a local node_modules folder.