diff options
Diffstat (limited to 'cli/flags.rs')
-rw-r--r-- | cli/flags.rs | 146 |
1 files changed, 122 insertions, 24 deletions
diff --git a/cli/flags.rs b/cli/flags.rs index 95e5617ab..da0f8ad0e 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -6,14 +6,20 @@ use clap::Arg; use clap::ArgMatches; use clap::ArgSettings; use clap::SubCommand; +use deno_core::serde::de; +use deno_core::serde::Deserialize; +use deno_core::serde::Deserializer; +use deno_core::serde::Serialize; +use deno_core::serde::Serializer; use deno_runtime::permissions::PermissionsOptions; use log::Level; +use std::fmt; use std::net::SocketAddr; use std::path::PathBuf; use std::str::FromStr; use tempfile::TempDir; -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub enum DenoSubcommand { Bundle { source_file: String, @@ -25,6 +31,7 @@ pub enum DenoSubcommand { Compile { source_file: String, output: Option<PathBuf>, + args: Vec<String>, }, Completions { buf: Box<[u8]>, @@ -92,7 +99,66 @@ impl Default for DenoSubcommand { } } -#[derive(Clone, Debug, PartialEq, Default)] +fn deserialize_maybe_log_level<'de, D>(d: D) -> Result<Option<Level>, D::Error> +where + D: Deserializer<'de>, +{ + struct OptionalLogLevelVisitor; + impl<'de> de::Visitor<'de> for OptionalLogLevelVisitor { + type Value = Option<Level>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "null or a valid log level string") + } + + fn visit_none<E>(self) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(None) + } + + fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error> + where + D: de::Deserializer<'de>, + { + struct LogLevelVisitor; + impl<'de> de::Visitor<'de> for LogLevelVisitor { + type Value = Level; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a valid log level string") + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: de::Error, + { + Level::from_str(s).map_err(|_| { + de::Error::invalid_value(de::Unexpected::Str(s), &self) + }) + } + } + Ok(Some(d.deserialize_str(LogLevelVisitor)?)) + } + } + d.deserialize_option(OptionalLogLevelVisitor) +} + +fn serialize_maybe_log_level<S>( + maybe_level: &Option<Level>, + s: S, +) -> Result<S::Ok, S::Error> +where + S: Serializer, +{ + match maybe_level { + None => s.serialize_none(), + Some(level) => s.serialize_str(&level.to_string()), + } +} + +#[derive(Clone, Debug, PartialEq, Default, Deserialize, Serialize)] pub struct Flags { /// Vector of CLI arguments - these are user script arguments, all Deno /// specific flags are removed. @@ -117,6 +183,8 @@ pub struct Flags { pub inspect_brk: Option<SocketAddr>, pub lock: Option<PathBuf>, pub lock_write: bool, + #[serde(deserialize_with = "deserialize_maybe_log_level")] + #[serde(serialize_with = "serialize_maybe_log_level")] pub log_level: Option<Level>, pub no_check: bool, pub no_prompts: bool, @@ -407,7 +475,7 @@ fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) { } fn install_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, true); + runtime_args_parse(flags, matches, true, true); let root = if matches.is_present("root") { let install_root = matches.value_of("root").unwrap(); @@ -437,14 +505,22 @@ fn install_parse(flags: &mut Flags, matches: &clap::ArgMatches) { } fn compile_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - compile_args_parse(flags, matches); + runtime_args_parse(flags, matches, true, false); - let source_file = matches.value_of("source_file").unwrap().to_string(); + let mut script: Vec<String> = matches + .values_of("script_arg") + .unwrap() + .map(String::from) + .collect(); + assert!(!script.is_empty()); + let args = script.split_off(1); + let source_file = script[0].to_string(); let output = matches.value_of("output").map(PathBuf::from); flags.subcommand = DenoSubcommand::Compile { source_file, output, + args, }; } @@ -483,7 +559,7 @@ fn completions_parse(flags: &mut Flags, matches: &clap::ArgMatches) { } fn repl_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, false); + runtime_args_parse(flags, matches, false, true); flags.repl = true; flags.subcommand = DenoSubcommand::Repl; flags.allow_net = Some(vec![]); @@ -496,7 +572,7 @@ fn repl_parse(flags: &mut Flags, matches: &clap::ArgMatches) { } fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, false); + runtime_args_parse(flags, matches, false, true); flags.allow_net = Some(vec![]); flags.allow_env = true; flags.allow_run = true; @@ -577,13 +653,22 @@ fn compile_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { ca_file_arg_parse(flags, matches); } -fn runtime_args<'a, 'b>(app: App<'a, 'b>, include_perms: bool) -> App<'a, 'b> { - let app = inspect_args(compile_args(app)); +fn runtime_args<'a, 'b>( + app: App<'a, 'b>, + include_perms: bool, + include_inspector: bool, +) -> App<'a, 'b> { + let app = compile_args(app); let app = if include_perms { permission_args(app) } else { app }; + let app = if include_inspector { + inspect_args(app) + } else { + app + }; app .arg(cached_only_arg()) .arg(v8_flags_arg()) @@ -594,19 +679,22 @@ fn runtime_args_parse( flags: &mut Flags, matches: &clap::ArgMatches, include_perms: bool, + include_inspector: bool, ) { compile_args_parse(flags, matches); cached_only_arg_parse(flags, matches); if include_perms { permission_args_parse(flags, matches); } + if include_inspector { + inspect_arg_parse(flags, matches); + } v8_flags_arg_parse(flags, matches); seed_arg_parse(flags, matches); - inspect_arg_parse(flags, matches); } fn run_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, true); + runtime_args_parse(flags, matches, true, true); let mut script: Vec<String> = matches .values_of("script_arg") @@ -625,7 +713,7 @@ fn run_parse(flags: &mut Flags, matches: &clap::ArgMatches) { } fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, true); + runtime_args_parse(flags, matches, true, true); let no_run = matches.is_present("no-run"); let fail_fast = matches.is_present("fail-fast"); @@ -799,12 +887,12 @@ Ignore formatting a file by adding an ignore comment at the top of the file: } fn repl_subcommand<'a, 'b>() -> App<'a, 'b> { - runtime_args(SubCommand::with_name("repl"), false) + runtime_args(SubCommand::with_name("repl"), false, true) .about("Read Eval Print Loop") } fn install_subcommand<'a, 'b>() -> App<'a, 'b> { - runtime_args(SubCommand::with_name("install"), true) + runtime_args(SubCommand::with_name("install"), true, true) .setting(AppSettings::TrailingVarArg) .arg( Arg::with_name("cmd") @@ -859,11 +947,10 @@ These must be added to the path manually if required.") } fn compile_subcommand<'a, 'b>() -> App<'a, 'b> { - compile_args(SubCommand::with_name("compile")) + runtime_args(SubCommand::with_name("compile"), true, false) + .setting(AppSettings::TrailingVarArg) .arg( - Arg::with_name("source_file") - .takes_value(true) - .required(true), + script_arg(), ) .arg( Arg::with_name("output") @@ -878,6 +965,10 @@ fn compile_subcommand<'a, 'b>() -> App<'a, 'b> { deno compile --unstable https://deno.land/std/http/file_server.ts deno compile --unstable --output /usr/local/bin/color_util https://deno.land/std/examples/colors.ts +Any flags passed which affect runtime behavior, such as '--unstable', +'--allow-*', '--v8-flags', etc. are encoded into the output executable and used +at runtime as if they were passed to a similar 'deno run' command. + The executable name is inferred by default: - Attempt to take the file stem of the URL path. The above example would become 'file_server'. @@ -926,7 +1017,7 @@ fn completions_subcommand<'a, 'b>() -> App<'a, 'b> { } fn eval_subcommand<'a, 'b>() -> App<'a, 'b> { - runtime_args(SubCommand::with_name("eval"), false) + runtime_args(SubCommand::with_name("eval"), false, true) .about("Eval script") .long_about( "Evaluate JavaScript from the command line. @@ -1246,7 +1337,7 @@ fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { } fn run_subcommand<'a, 'b>() -> App<'a, 'b> { - runtime_args(SubCommand::with_name("run"), true) + runtime_args(SubCommand::with_name("run"), true, true) .arg( watch_arg() .conflicts_with("inspect") @@ -1280,7 +1371,7 @@ Deno allows specifying the filename '-' to read the file from stdin. } fn test_subcommand<'a, 'b>() -> App<'a, 'b> { - runtime_args(SubCommand::with_name("test"), true) + runtime_args(SubCommand::with_name("test"), true, true) .setting(AppSettings::TrailingVarArg) .arg( Arg::with_name("no-run") @@ -3306,7 +3397,8 @@ mod tests { Flags { subcommand: DenoSubcommand::Compile { source_file: "https://deno.land/std/examples/colors.ts".to_string(), - output: None + output: None, + args: vec![], }, ..Flags::default() } @@ -3316,13 +3408,14 @@ mod tests { #[test] fn compile_with_flags() { #[rustfmt::skip] - let r = flags_from_vec_safe(svec!["deno", "compile", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--output", "colors", "https://deno.land/std/examples/colors.ts"]); + let r = flags_from_vec_safe(svec!["deno", "compile", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--output", "colors", "https://deno.land/std/examples/colors.ts", "foo", "bar"]); assert_eq!( r.unwrap(), Flags { subcommand: DenoSubcommand::Compile { source_file: "https://deno.land/std/examples/colors.ts".to_string(), - output: Some(PathBuf::from("colors")) + output: Some(PathBuf::from("colors")), + args: svec!["foo", "bar"], }, unstable: true, import_map_path: Some("import_map.json".to_string()), @@ -3333,6 +3426,11 @@ mod tests { lock: Some(PathBuf::from("lock.json")), lock_write: true, ca_file: Some("example.crt".to_string()), + cached_only: true, + allow_read: Some(vec![]), + allow_net: Some(vec![]), + v8_flags: svec!["--help", "--random-seed=1"], + seed: Some(1), ..Flags::default() } ); |