diff options
Diffstat (limited to 'cli/args')
-rw-r--r-- | cli/args/flags.rs | 70 | ||||
-rw-r--r-- | cli/args/mod.rs | 7 |
2 files changed, 73 insertions, 4 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 0e4621d67..b3fe61abd 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -395,6 +395,7 @@ pub struct Flags { pub ext: Option<String>, pub ignore: Vec<PathBuf>, pub import_map_path: Option<String>, + pub env_file: Option<String>, pub inspect_brk: Option<SocketAddr>, pub inspect_wait: Option<SocketAddr>, pub inspect: Option<SocketAddr>, @@ -1030,6 +1031,7 @@ glob {*_,*.,}bench.{js,mjs,ts,mts,jsx,tsx}: .arg(watch_arg(false)) .arg(no_clear_screen_arg()) .arg(script_arg().last(true)) + .arg(env_file_arg()) }) } @@ -1191,6 +1193,7 @@ supported in canary. .action(ArgAction::SetTrue), ) .arg(executable_ext_arg()) + .arg(env_file_arg()) .arg(script_arg().required(true).trailing_var_arg(true)) }) } @@ -1434,6 +1437,7 @@ This command has implicit access to all permissions (--allow-all).", .value_name("CODE_ARG") .required(true), ) + .arg(env_file_arg()) }) } @@ -1667,6 +1671,7 @@ These must be added to the path manually if required.") .help("Forcefully overwrite existing installation") .action(ArgAction::SetTrue)) ) + .arg(env_file_arg()) } fn jupyter_subcommand() -> Command { @@ -1868,6 +1873,7 @@ fn repl_subcommand() -> Command { .help("Evaluates the provided code when the REPL starts.") .value_name("code"), )) + .arg(env_file_arg()) } fn run_subcommand() -> Command { @@ -1882,6 +1888,7 @@ fn run_subcommand() -> Command { .required_unless_present("v8-flags") .trailing_var_arg(true), ) + .arg(env_file_arg()) .about("Run a JavaScript or TypeScript program") .long_about( "Run a JavaScript or TypeScript program @@ -2063,6 +2070,7 @@ Directory arguments are expanded to all contained files matching the glob .help("Select reporter to use. Default to 'pretty'.") .value_parser(["pretty", "dot", "junit", "tap"]) ) + .arg(env_file_arg()) ) } @@ -2643,6 +2651,18 @@ fn import_map_arg() -> Arg { .value_hint(ValueHint::FilePath) } +fn env_file_arg() -> Arg { + Arg::new("env") + .long("env") + .value_name("FILE") + .help("Load .env file") + .long_help("UNSTABLE: Load environment variables from local file. Only the first environment variable with a given key is used. Existing process environment variables are not overwritten.") + .value_hint(ValueHint::FilePath) + .default_missing_value(".env") + .require_equals(true) + .num_args(0..=1) +} + fn reload_arg() -> Arg { Arg::new("reload") .short('r') @@ -3708,6 +3728,7 @@ fn runtime_args_parse( v8_flags_arg_parse(flags, matches); seed_arg_parse(flags, matches); enable_testing_features_arg_parse(flags, matches); + env_file_arg_parse(flags, matches); } fn inspect_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { @@ -3745,6 +3766,10 @@ fn import_map_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.import_map_path = matches.remove_one::<String>("import-map"); } +fn env_file_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + flags.env_file = matches.remove_one::<String>("env"); +} + fn reload_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { if let Some(cache_bl) = matches.remove_many::<String>("reload") { let raw_cache_blocklist: Vec<String> = cache_bl.collect(); @@ -5175,7 +5200,7 @@ mod tests { #[test] fn eval_with_flags() { #[rustfmt::skip] - let r = flags_from_vec(svec!["deno", "eval", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "42"]); + let r = flags_from_vec(svec!["deno", "eval", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--env=.example.env", "42"]); assert_eq!( r.unwrap(), Flags { @@ -5204,6 +5229,7 @@ mod tests { allow_write: Some(vec![]), allow_ffi: Some(vec![]), allow_hrtime: true, + env_file: Some(".example.env".to_owned()), ..Flags::default() } ); @@ -5273,7 +5299,7 @@ mod tests { #[test] fn repl_with_flags() { #[rustfmt::skip] - let r = flags_from_vec(svec!["deno", "repl", "-A", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--unsafely-ignore-certificate-errors"]); + let r = flags_from_vec(svec!["deno", "repl", "-A", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--unsafely-ignore-certificate-errors", "--env=.example.env"]); assert_eq!( r.unwrap(), Flags { @@ -5304,6 +5330,7 @@ mod tests { allow_write: Some(vec![]), allow_ffi: Some(vec![]), allow_hrtime: true, + env_file: Some(".example.env".to_owned()), unsafely_ignore_certificate_errors: Some(vec![]), ..Flags::default() } @@ -6068,6 +6095,39 @@ mod tests { } #[test] + fn run_env_file_default() { + let r = flags_from_vec(svec!["deno", "run", "--env", "script.ts"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + script: "script.ts".to_string(), + watch: Default::default(), + }), + env_file: Some(".env".to_owned()), + ..Flags::default() + } + ); + } + + #[test] + fn run_env_file_defined() { + let r = + flags_from_vec(svec!["deno", "run", "--env=.another_env", "script.ts"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + script: "script.ts".to_string(), + watch: Default::default(), + }), + env_file: Some(".another_env".to_owned()), + ..Flags::default() + } + ); + } + + #[test] fn cache_multiple() { let r = flags_from_vec(svec!["deno", "cache", "script.ts", "script_two.ts"]); @@ -6148,7 +6208,7 @@ mod tests { #[test] fn install_with_flags() { #[rustfmt::skip] - let r = flags_from_vec(svec!["deno", "install", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--unsafely-ignore-certificate-errors", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--name", "file_server", "--root", "/foo", "--force", "https://deno.land/std/http/file_server.ts", "foo", "bar"]); + let r = flags_from_vec(svec!["deno", "install", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--unsafely-ignore-certificate-errors", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--name", "file_server", "--root", "/foo", "--force", "--env=.example.env", "https://deno.land/std/http/file_server.ts", "foo", "bar"]); assert_eq!( r.unwrap(), Flags { @@ -6174,6 +6234,7 @@ mod tests { allow_net: Some(vec![]), unsafely_ignore_certificate_errors: Some(vec![]), allow_read: Some(vec![]), + env_file: Some(".example.env".to_owned()), ..Flags::default() } ); @@ -7557,7 +7618,7 @@ mod tests { #[test] fn compile_with_flags() { #[rustfmt::skip] - let r = flags_from_vec(svec!["deno", "compile", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--unsafely-ignore-certificate-errors", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--no-terminal", "--output", "colors", "https://deno.land/std/examples/colors.ts", "foo", "bar", "-p", "8080"]); + let r = flags_from_vec(svec!["deno", "compile", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--unsafely-ignore-certificate-errors", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--no-terminal", "--output", "colors", "--env=.example.env", "https://deno.land/std/examples/colors.ts", "foo", "bar", "-p", "8080"]); assert_eq!( r.unwrap(), Flags { @@ -7584,6 +7645,7 @@ mod tests { allow_net: Some(vec![]), v8_flags: svec!["--help", "--random-seed=1"], seed: Some(1), + env_file: Some(".example.env".to_owned()), ..Flags::default() } ); diff --git a/cli/args/mod.rs b/cli/args/mod.rs index 94eaf2a3e..b8b0a81f5 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -52,6 +52,7 @@ use deno_runtime::deno_tls::rustls_pemfile; use deno_runtime::deno_tls::webpki_roots; use deno_runtime::inspector_server::InspectorServer; use deno_runtime::permissions::PermissionsOptions; +use dotenvy::from_filename; use once_cell::sync::Lazy; use once_cell::sync::OnceCell; use serde::Deserialize; @@ -651,6 +652,12 @@ impl CliOptions { let maybe_vendor_folder = resolve_vendor_folder(&initial_cwd, &flags, maybe_config_file.as_ref()); + if let Some(env_file_name) = &flags.env_file { + if (from_filename(env_file_name)).is_err() { + bail!("Unable to load '{env_file_name}' environment variable file") + } + } + Ok(Self { flags, initial_cwd, |