flags.rs 9.8 KB
Newer Older
R
Ryan Dahl 已提交
1
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
2
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
3
use deno::v8_set_flags;
R
Ryan Dahl 已提交
4 5 6 7 8 9 10

// Creates vector of strings, Vec<String>
#[cfg(test)]
macro_rules! svec {
    ($($x:expr),*) => (vec![$($x.to_string()),*]);
}

11
#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
R
Ryan Dahl 已提交
12
#[derive(Clone, Debug, PartialEq, Default)]
R
Ryan Dahl 已提交
13 14 15 16
pub struct DenoFlags {
  pub log_debug: bool,
  pub version: bool,
  pub reload: bool,
D
Dmitry Sharshakov 已提交
17
  pub allow_read: bool,
R
Ryan Dahl 已提交
18 19
  pub allow_write: bool,
  pub allow_net: bool,
20
  pub allow_env: bool,
21
  pub allow_run: bool,
22
  pub allow_high_precision: bool,
23
  pub no_prompts: bool,
24
  pub types: bool,
25
  pub prefetch: bool,
26
  pub info: bool,
R
Ryan Dahl 已提交
27
  pub fmt: bool,
28
  pub eval: bool,
R
Ryan Dahl 已提交
29 30
}

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
impl<'a> From<ArgMatches<'a>> for DenoFlags {
  fn from(matches: ArgMatches) -> DenoFlags {
    let mut flags = DenoFlags::default();

    if matches.is_present("log-debug") {
      flags.log_debug = true;
    }
    if matches.is_present("version") {
      flags.version = true;
    }
    if matches.is_present("reload") {
      flags.reload = true;
    }
    if matches.is_present("allow-read") {
      flags.allow_read = true;
    }
    if matches.is_present("allow-write") {
      flags.allow_write = true;
    }
    if matches.is_present("allow-net") {
      flags.allow_net = true;
    }
    if matches.is_present("allow-env") {
      flags.allow_env = true;
    }
    if matches.is_present("allow-run") {
      flags.allow_run = true;
    }
59 60 61
    if matches.is_present("allow-high-precision") {
      flags.allow_high_precision = true;
    }
62 63 64 65 66 67 68
    if matches.is_present("allow-all") {
      flags.allow_read = true;
      flags.allow_env = true;
      flags.allow_net = true;
      flags.allow_run = true;
      flags.allow_read = true;
      flags.allow_write = true;
69
      flags.allow_high_precision = true;
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    }
    if matches.is_present("no-prompt") {
      flags.no_prompts = true;
    }
    if matches.is_present("types") {
      flags.types = true;
    }
    if matches.is_present("prefetch") {
      flags.prefetch = true;
    }
    if matches.is_present("info") {
      flags.info = true;
    }
    if matches.is_present("fmt") {
      flags.fmt = true;
    }
86 87 88
    if matches.is_present("eval") {
      flags.eval = true;
    }
89 90

    flags
B
Bartek Iwańczuk 已提交
91 92 93
  }
}

94
static ENV_VARIABLES_HELP: &str = "ENVIRONMENT VARIABLES:
95 96
    DENO_DIR        Set deno's base directory
    NO_COLOR        Set to disable color";
97

98
fn create_cli_app<'a, 'b>() -> App<'a, 'b> {
B
Bert Belder 已提交
99
  App::new("deno")
100
    .bin_name("deno")
101
    .global_settings(&[AppSettings::ColorNever])
102 103 104 105
    .settings(&[
      AppSettings::AllowExternalSubcommands,
      AppSettings::DisableHelpSubcommand,
    ]).after_help(ENV_VARIABLES_HELP)
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
    .arg(
      Arg::with_name("version")
        .short("v")
        .long("version")
        .help("Print the version"),
    ).arg(
      Arg::with_name("allow-read")
        .long("allow-read")
        .help("Allow file system read access"),
    ).arg(
      Arg::with_name("allow-write")
        .long("allow-write")
        .help("Allow file system write access"),
    ).arg(
      Arg::with_name("allow-net")
        .long("allow-net")
        .help("Allow network access"),
    ).arg(
      Arg::with_name("allow-env")
        .long("allow-env")
        .help("Allow environment access"),
    ).arg(
      Arg::with_name("allow-run")
        .long("allow-run")
        .help("Allow running subprocesses"),
131 132 133 134
    ).arg(
      Arg::with_name("allow-high-precision")
        .long("allow-high-precision")
        .help("Allow high precision time measurement"),
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
    ).arg(
      Arg::with_name("allow-all")
        .short("A")
        .long("allow-all")
        .help("Allow all permissions"),
    ).arg(
      Arg::with_name("no-prompt")
        .long("no-prompt")
        .help("Do not use prompts"),
    ).arg(
      Arg::with_name("log-debug")
        .short("D")
        .long("log-debug")
        .help("Log debug output"),
    ).arg(
      Arg::with_name("reload")
        .short("r")
        .long("reload")
        .help("Reload source code cache (recompile TypeScript)"),
    ).arg(
      Arg::with_name("v8-options")
        .long("v8-options")
        .help("Print V8 command line options"),
    ).arg(
      Arg::with_name("v8-flags")
        .long("v8-flags")
        .takes_value(true)
        .require_equals(true)
        .help("Set V8 command line options"),
    ).arg(
      Arg::with_name("types")
        .long("types")
        .help("Print runtime TypeScript declarations"),
    ).arg(
      Arg::with_name("prefetch")
        .long("prefetch")
        .help("Prefetch the dependencies"),
    ).subcommand(
      SubCommand::with_name("info")
174
        .setting(AppSettings::DisableVersion)
175 176 177
        .about("Show source file related info")
        .arg(Arg::with_name("file").takes_value(true).required(true)),
    ).subcommand(
178 179 180 181 182 183 184 185 186 187 188 189 190 191
      SubCommand::with_name("eval")
        .setting(AppSettings::DisableVersion)
        .about("Eval script")
        .arg(Arg::with_name("code").takes_value(true).required(true)),
    ).subcommand(
      SubCommand::with_name("fmt")
        .setting(AppSettings::DisableVersion)
        .about("Format files")
        .arg(
          Arg::with_name("files")
            .takes_value(true)
            .multiple(true)
            .required(true),
        ),
192 193 194 195 196
    ).subcommand(
      // this is a fake subcommand - it's used in conjunction with
      // AppSettings:AllowExternalSubcommand to treat it as an
      // entry point script
      SubCommand::with_name("<script>").about("Script to run"),
B
Bert Belder 已提交
197
    )
198
}
199

200 201 202 203 204 205 206
#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
pub fn set_flags(
  args: Vec<String>,
) -> Result<(DenoFlags, Vec<String>), String> {
  let mut rest_argv: Vec<String> = vec!["deno".to_string()];
  let cli_app = create_cli_app();
  let matches = cli_app.get_matches_from(args);
207 208

  match matches.subcommand() {
209 210 211 212
    ("eval", Some(info_match)) => {
      let code: &str = info_match.value_of("code").unwrap();
      rest_argv.extend(vec![code.to_string()]);
    }
213 214
    ("info", Some(info_match)) => {
      let file: &str = info_match.value_of("file").unwrap();
215
      rest_argv.extend(vec![file.to_string()]);
216 217 218 219 220 221 222
    }
    ("fmt", Some(fmt_match)) => {
      let files: Vec<String> = fmt_match
        .values_of("files")
        .unwrap()
        .map(String::from)
        .collect();
223
      rest_argv.extend(files);
224 225
    }
    (script, Some(script_match)) => {
226 227 228
      rest_argv.extend(vec![script.to_string()]);
      // check if there are any extra arguments that should
      // be passed to script
229 230 231 232 233 234
      if script_match.is_present("") {
        let script_args: Vec<String> = script_match
          .values_of("")
          .unwrap()
          .map(String::from)
          .collect();
235
        rest_argv.extend(script_args);
236 237 238 239 240 241 242
      }
    }
    _ => {}
  }

  if matches.is_present("v8-options") {
    // display v8 help and exit
B
Bartek Iwańczuk 已提交
243 244
    // TODO(bartlomieju): this relies on `v8_set_flags` to swap `--v8-options` to help
    v8_set_flags(vec!["deno".to_string(), "--v8-options".to_string()]);
245 246 247 248 249 250 251 252 253 254 255 256 257
  }

  if matches.is_present("v8-flags") {
    let mut v8_flags: Vec<String> = matches
      .values_of("v8-flags")
      .unwrap()
      .map(String::from)
      .collect();

    v8_flags.insert(1, "deno".to_string());
    v8_set_flags(v8_flags);
  }

258
  let flags = DenoFlags::from(matches);
259
  Ok((flags, rest_argv))
R
Ryan Dahl 已提交
260 261 262 263
}

#[test]
fn test_set_flags_1() {
264
  let (flags, rest) = set_flags(svec!["deno", "--version"]).unwrap();
265
  assert_eq!(rest, svec!["deno"]);
R
Format.  
Ryan Dahl 已提交
266 267 268
  assert_eq!(
    flags,
    DenoFlags {
R
Ryan Dahl 已提交
269
      version: true,
270
      ..DenoFlags::default()
R
Ryan Dahl 已提交
271 272 273 274 275 276
    }
  );
}

#[test]
fn test_set_flags_2() {
277
  let (flags, rest) =
278
    set_flags(svec!["deno", "-r", "-D", "script.ts"]).unwrap();
279
  assert_eq!(rest, svec!["deno", "script.ts"]);
R
Format.  
Ryan Dahl 已提交
280 281 282
  assert_eq!(
    flags,
    DenoFlags {
R
Ryan Dahl 已提交
283 284
      log_debug: true,
      reload: true,
285
      ..DenoFlags::default()
R
Ryan Dahl 已提交
286 287 288 289 290 291
    }
  );
}

#[test]
fn test_set_flags_3() {
292 293
  let (flags, rest) =
    set_flags(svec!["deno", "-r", "--allow-write", "script.ts"]).unwrap();
294
  assert_eq!(rest, svec!["deno", "script.ts"]);
R
Format.  
Ryan Dahl 已提交
295 296 297
  assert_eq!(
    flags,
    DenoFlags {
R
Ryan Dahl 已提交
298 299
      reload: true,
      allow_write: true,
300
      ..DenoFlags::default()
R
Ryan Dahl 已提交
301 302 303 304
    }
  );
}

I
Ian Shehadeh 已提交
305 306
#[test]
fn test_set_flags_4() {
307 308
  let (flags, rest) =
    set_flags(svec!["deno", "-Dr", "--allow-write", "script.ts"]).unwrap();
I
Ian Shehadeh 已提交
309 310 311 312 313 314 315 316 317 318 319 320
  assert_eq!(rest, svec!["deno", "script.ts"]);
  assert_eq!(
    flags,
    DenoFlags {
      log_debug: true,
      reload: true,
      allow_write: true,
      ..DenoFlags::default()
    }
  );
}

K
Kitson Kelly 已提交
321 322
#[test]
fn test_set_flags_5() {
323
  let (flags, rest) = set_flags(svec!["deno", "--types"]).unwrap();
K
Kitson Kelly 已提交
324 325 326 327
  assert_eq!(rest, svec!["deno"]);
  assert_eq!(
    flags,
    DenoFlags {
328
      types: true,
K
Kitson Kelly 已提交
329 330 331 332 333
      ..DenoFlags::default()
    }
  )
}

334
#[test]
B
Bartek Iwańczuk 已提交
335
fn test_set_flags_6() {
336 337
  let (flags, rest) =
    set_flags(svec!["deno", "--allow-net", "gist.ts", "--title", "X"]).unwrap();
B
Bartek Iwańczuk 已提交
338 339 340 341 342 343 344 345
  assert_eq!(rest, svec!["deno", "gist.ts", "--title", "X"]);
  assert_eq!(
    flags,
    DenoFlags {
      allow_net: true,
      ..DenoFlags::default()
    }
  )
346 347
}

R
Ryan Dahl 已提交
348 349
#[test]
fn test_set_flags_7() {
350 351
  let (flags, rest) =
    set_flags(svec!["deno", "--allow-all", "gist.ts"]).unwrap();
R
Ryan Dahl 已提交
352 353 354 355 356 357 358
  assert_eq!(rest, svec!["deno", "gist.ts"]);
  assert_eq!(
    flags,
    DenoFlags {
      allow_net: true,
      allow_env: true,
      allow_run: true,
D
Dmitry Sharshakov 已提交
359
      allow_read: true,
R
Ryan Dahl 已提交
360
      allow_write: true,
361
      allow_high_precision: true,
R
Ryan Dahl 已提交
362 363 364 365 366
      ..DenoFlags::default()
    }
  )
}

D
Dmitry Sharshakov 已提交
367 368
#[test]
fn test_set_flags_8() {
369 370
  let (flags, rest) =
    set_flags(svec!["deno", "--allow-read", "gist.ts"]).unwrap();
D
Dmitry Sharshakov 已提交
371 372 373 374 375 376 377 378 379
  assert_eq!(rest, svec!["deno", "gist.ts"]);
  assert_eq!(
    flags,
    DenoFlags {
      allow_read: true,
      ..DenoFlags::default()
    }
  )
}
380 381 382 383 384 385 386 387 388 389 390 391 392 393

#[test]
fn test_set_flags_9() {
  let (flags, rest) =
    set_flags(svec!["deno", "--allow-high-precision", "script.ts"]).unwrap();
  assert_eq!(rest, svec!["deno", "script.ts"]);
  assert_eq!(
    flags,
    DenoFlags {
      allow_high_precision: true,
      ..DenoFlags::default()
    }
  )
}