From 38cf346d5c0f69dfb0919781fb61db7a6597ded1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Sun, 30 Jun 2019 00:32:54 +0200 Subject: [PATCH] feat: parse flags after script name (#2596) --- cli/flags.rs | 109 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 104 insertions(+), 5 deletions(-) diff --git a/cli/flags.rs b/cli/flags.rs index f7444f8d1f..5e15a1e75b 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -434,8 +434,11 @@ fn resolve_paths(paths: Vec) -> Vec { /// Parse ArgMatches into internal DenoFlags structure. /// This method should not make any side effects. -pub fn parse_flags(matches: &ArgMatches) -> DenoFlags { - let mut flags = DenoFlags::default(); +pub fn parse_flags( + matches: &ArgMatches, + maybe_flags: Option, +) -> DenoFlags { + let mut flags = maybe_flags.unwrap_or_default(); if matches.is_present("log-level") { flags.log_level = match matches.value_of("log-level").unwrap() { @@ -552,6 +555,56 @@ fn parse_run_args(mut flags: DenoFlags, matches: &ArgMatches) -> DenoFlags { flags } +/// Parse vector or arguments as DenoFlags. +/// +/// This is very specialized utility that parses arguments passed after script URL. +/// +/// Only dash (eg. `-r`) and double dash (eg. `--reload`) arguments are supported. +/// Arguments recognized as DenoFlags will be eaten. +/// Parsing stops after double dash `--` argument. +/// +/// NOTE: this method ignores `-h/--help` and `-v/--version` flags. +fn parse_script_args( + args: Vec, + mut flags: DenoFlags, +) -> (Vec, DenoFlags) { + let mut argv = vec![]; + let mut seen_double_dash = false; + + // we have to iterate and parse argument one by one because clap returns error on any + // unrecognized argument + for arg in args.iter() { + if seen_double_dash { + argv.push(arg.to_string()); + continue; + } + + if arg == "--" { + seen_double_dash = true; + argv.push(arg.to_string()); + continue; + } + + if !arg.starts_with('-') { + argv.push(arg.to_string()); + continue; + } + + let cli_app = create_cli_app(); + // `get_matches_from_safe` returns error for `-h/-v` flags + let matches = + cli_app.get_matches_from_safe(vec!["deno".to_string(), arg.to_string()]); + + if matches.is_ok() { + flags = parse_flags(&matches.unwrap(), Some(flags)); + } else { + argv.push(arg.to_string()); + } + } + + (argv, flags) +} + /// Used for `deno fmt ...` subcommand const PRETTIER_URL: &str = "https://deno.land/std@v0.7.0/prettier/main.ts"; /// Used for `deno install...` subcommand @@ -603,7 +656,7 @@ pub fn flags_from_vec( let cli_app = create_cli_app(); let matches = cli_app.get_matches_from(args); let mut argv: Vec = vec!["deno".to_string()]; - let mut flags = parse_flags(&matches.clone()); + let mut flags = parse_flags(&matches.clone(), None); let subcommand = match matches.subcommand() { ("bundle", Some(bundle_match)) => { @@ -711,6 +764,9 @@ pub fn flags_from_vec( .unwrap() .map(String::from) .collect(); + + let (script_args, flags_) = parse_script_args(script_args, flags); + flags = flags_; argv.extend(script_args); } DenoSubcommand::Run @@ -746,6 +802,9 @@ pub fn flags_from_vec( .unwrap() .map(String::from) .collect(); + + let (script_args, flags_) = parse_script_args(script_args, flags); + flags = flags_; argv.extend(script_args); } DenoSubcommand::Run @@ -933,7 +992,7 @@ mod tests { #[test] fn test_flags_from_vec_10() { - // notice that flags passed after script name will not + // notice that flags passed after double dash will not // be parsed to DenoFlags but instead forwarded to // script args as Deno.args let (flags, subcommand, argv) = flags_from_vec(svec![ @@ -941,6 +1000,7 @@ mod tests { "run", "--allow-write", "script.ts", + "--", "-D", "--allow-net" ]); @@ -952,7 +1012,7 @@ mod tests { } ); assert_eq!(subcommand, DenoSubcommand::Run); - assert_eq!(argv, svec!["deno", "script.ts", "-D", "--allow-net"]); + assert_eq!(argv, svec!["deno", "script.ts", "--", "-D", "--allow-net"]); } #[test] @@ -1436,4 +1496,43 @@ mod tests { assert_eq!(subcommand, DenoSubcommand::Completions); assert_eq!(argv, svec!["deno"]) } + + #[test] + fn test_flags_from_vec_33() { + let (flags, subcommand, argv) = + flags_from_vec(svec!["deno", "script.ts", "--allow-read", "--allow-net"]); + assert_eq!( + flags, + DenoFlags { + allow_net: true, + allow_read: true, + ..DenoFlags::default() + } + ); + assert_eq!(subcommand, DenoSubcommand::Run); + assert_eq!(argv, svec!["deno", "script.ts"]); + + let (flags, subcommand, argv) = flags_from_vec(svec![ + "deno", + "--allow-read", + "run", + "script.ts", + "--allow-net", + "-r", + "--help", + "--foo", + "bar" + ]); + assert_eq!( + flags, + DenoFlags { + allow_net: true, + allow_read: true, + reload: true, + ..DenoFlags::default() + } + ); + assert_eq!(subcommand, DenoSubcommand::Run); + assert_eq!(argv, svec!["deno", "script.ts", "--help", "--foo", "bar"]); + } }