diff options
Diffstat (limited to 'cli/args')
-rw-r--r-- | cli/args/flags.rs | 65 | ||||
-rw-r--r-- | cli/args/lockfile.rs | 55 |
2 files changed, 104 insertions, 16 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 1743d58c6..5f58911c2 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -498,6 +498,7 @@ pub struct Flags { pub argv: Vec<String>, pub subcommand: DenoSubcommand, + pub frozen_lockfile: bool, pub ca_stores: Option<Vec<String>>, pub ca_data: Option<CaData>, pub cache_blocklist: Vec<String>, @@ -1487,12 +1488,15 @@ Future runs of this module will trigger no downloads or compilation unless --reload is specified.", ) .defer(|cmd| { - compile_args(cmd).arg(check_arg(false)).arg( - Arg::new("file") - .num_args(1..) - .required(true) - .value_hint(ValueHint::FilePath), - ) + compile_args(cmd) + .arg(check_arg(false)) + .arg( + Arg::new("file") + .num_args(1..) + .required(true) + .value_hint(ValueHint::FilePath), + ) + .arg(frozen_lockfile_arg()) }) } @@ -3271,6 +3275,7 @@ fn runtime_args( app }; app + .arg(frozen_lockfile_arg()) .arg(cached_only_arg()) .arg(location_arg()) .arg(v8_flags_arg()) @@ -3384,6 +3389,17 @@ fn cached_only_arg() -> Arg { .help("Require that remote dependencies are already cached") } +fn frozen_lockfile_arg() -> Arg { + Arg::new("frozen") + .long("frozen") + .alias("frozen-lockfile") + .value_parser(value_parser!(bool)) + .num_args(0..=1) + .require_equals(true) + .default_missing_value("true") + .help("Error out if lockfile is out of date") +} + /// Used for subcommands that operate on executable scripts only. /// `deno fmt` has its own `--ext` arg because its possible values differ. /// If --ext is not provided and the script doesn't have a file extension, @@ -3774,6 +3790,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); let files = matches.remove_many::<String>("file").unwrap().collect(); flags.subcommand = DenoSubcommand::Cache(CacheFlags { files }); } @@ -4576,6 +4593,7 @@ fn runtime_args_parse( ) { compile_args_parse(flags, matches); cached_only_arg_parse(flags, matches); + frozen_lockfile_arg_parse(flags, matches); if include_perms { permission_args_parse(flags, matches); } @@ -4667,6 +4685,12 @@ fn cached_only_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { } } +fn frozen_lockfile_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + if let Some(&v) = matches.get_one::<bool>("frozen") { + flags.frozen_lockfile = v; + } +} + fn ext_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.ext = matches.remove_one::<String>("ext"); } @@ -9845,4 +9869,33 @@ mod tests { } ); } + + #[test] + fn run_with_frozen_lockfile() { + let cases = [ + (Some("--frozen"), true), + (Some("--frozen=true"), true), + (Some("--frozen=false"), false), + (None, false), + ]; + for (flag, frozen) in cases { + let mut args = svec!["deno", "run"]; + if let Some(f) = flag { + args.push(f.into()); + } + args.push("script.ts".into()); + let r = flags_from_vec(args); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags::new_default( + "script.ts".to_string(), + )), + frozen_lockfile: frozen, + code_cache_enabled: true, + ..Flags::default() + } + ); + } + } } diff --git a/cli/args/lockfile.rs b/cli/args/lockfile.rs index 555261336..d18c871aa 100644 --- a/cli/args/lockfile.rs +++ b/cli/args/lockfile.rs @@ -23,6 +23,7 @@ use deno_lockfile::Lockfile; pub struct CliLockfile { lockfile: Mutex<Lockfile>, pub filename: PathBuf, + pub frozen: bool, } pub struct Guard<'a, T> { @@ -44,11 +45,12 @@ impl<'a, T> std::ops::DerefMut for Guard<'a, T> { } impl CliLockfile { - pub fn new(lockfile: Lockfile) -> Self { + pub fn new(lockfile: Lockfile, frozen: bool) -> Self { let filename = lockfile.filename.clone(); Self { lockfile: Mutex::new(lockfile), filename, + frozen, } } @@ -71,6 +73,7 @@ impl CliLockfile { } pub fn write_if_changed(&self) -> Result<(), AnyError> { + self.error_if_changed()?; let mut lockfile = self.lockfile.lock(); let Some(bytes) = lockfile.resolve_write_bytes() else { return Ok(()); // nothing to do @@ -127,23 +130,55 @@ impl CliLockfile { }; let lockfile = if flags.lock_write { - CliLockfile::new(Lockfile::new_empty(filename, true)) + CliLockfile::new( + Lockfile::new_empty(filename, true), + flags.frozen_lockfile, + ) } else { - Self::read_from_path(filename)? + Self::read_from_path(filename, flags.frozen_lockfile)? }; Ok(Some(lockfile)) } - pub fn read_from_path(filename: PathBuf) -> Result<CliLockfile, AnyError> { + pub fn read_from_path( + filename: PathBuf, + frozen: bool, + ) -> Result<CliLockfile, AnyError> { match std::fs::read_to_string(&filename) { - Ok(text) => Ok(CliLockfile::new(Lockfile::with_lockfile_content( - filename, &text, false, - )?)), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => { - Ok(CliLockfile::new(Lockfile::new_empty(filename, false))) - } + Ok(text) => Ok(CliLockfile::new( + Lockfile::with_lockfile_content(filename, &text, false)?, + frozen, + )), + Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok( + CliLockfile::new(Lockfile::new_empty(filename, false), frozen), + ), Err(err) => Err(err).with_context(|| { format!("Failed reading lockfile '{}'", filename.display()) }), } } + pub fn error_if_changed(&self) -> Result<(), AnyError> { + if !self.frozen { + return Ok(()); + } + let lockfile = self.lockfile.lock(); + if lockfile.has_content_changed { + let suggested = if *super::DENO_FUTURE { + "`deno cache --frozen=false`, `deno install --frozen=false`," + } else { + "`deno cache --frozen=false`" + }; + + let contents = + std::fs::read_to_string(&lockfile.filename).unwrap_or_default(); + let new_contents = lockfile.as_json_string(); + let diff = crate::util::diff::diff(&contents, &new_contents); + // has an extra newline at the end + let diff = diff.trim_end(); + Err(deno_core::anyhow::anyhow!( + "The lockfile is out of date. Run {suggested} or rerun with `--frozen=false` to update it.\nchanges:\n{diff}" + )) + } else { + Ok(()) + } + } } |