Skip to content

Commit 7a7b8d6

Browse files
fix(install): regenerate lockfile with --force on global install (denoland#33970)
## Summary Fixes denoland#33934. When `deno install --global --force` (or `--reload`) was used, the auto-generated lockfile at `<bin>/.<name>/deno.lock` still pinned the old version, so version resolution returned the previously locked version instead of the latest. This change removes the stale lockfile before re-running resolution in `setup_config_dir` when `--force` or `--reload` is specified. The user is explicitly asking for a fresh install in those cases, so honoring a stale auto-generated lockfile is a footgun. ## Test plan - [x] Added `install_force_regenerates_lockfile` unit test - [x] Added `install_reload_regenerates_lockfile` unit test - [x] `cargo build --bin deno` passes - [x] `./tools/format.js` + `./tools/lint.js` clean --------- Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
1 parent 05e01ff commit 7a7b8d6

1 file changed

Lines changed: 63 additions & 0 deletions

File tree

cli/tools/installer/global.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ pub async fn install_global(
185185
&flags,
186186
&installation_dir,
187187
Some(&jsr_lockfile_fetcher),
188+
install_flags_global.force,
188189
)
189190
.await?;
190191

@@ -421,6 +422,7 @@ async fn setup_config_dir(
421422
flags: &Flags,
422423
installation_dir: &Path,
423424
jsr_lockfile_fetcher: Option<&JsrLockfileFetcher<'_>>,
425+
force: bool,
424426
) -> Result<(), AnyError> {
425427
fn resolve_implicit_node_modules_dir(
426428
flags: &Flags,
@@ -443,6 +445,18 @@ async fn setup_config_dir(
443445
fs::create_dir_all(&dir)
444446
.with_context(|| format!("failed creating '{}'", dir.display()))?;
445447

448+
// When --force is specified, the user is explicitly asking for a fresh
449+
// install. Remove the stale auto-generated lockfile so dependency resolution
450+
// isn't constrained to previously pinned versions.
451+
if force {
452+
let lockfile_path = dir.join("deno.lock");
453+
if lockfile_path.exists() {
454+
fs::remove_file(&lockfile_path).with_context(|| {
455+
format!("failed removing '{}'", lockfile_path.display())
456+
})?;
457+
}
458+
}
459+
446460
let config_text = if let ConfigFlag::Path(config_path) = &flags.config_flag {
447461
fs::read_to_string(config_path)
448462
.with_context(|| format!("error reading {config_path}"))?
@@ -1220,6 +1234,7 @@ mod tests {
12201234
flags,
12211235
&installation_dir,
12221236
None,
1237+
install_flags_global.force,
12231238
)
12241239
.await
12251240
.unwrap();
@@ -1797,6 +1812,54 @@ mod tests {
17971812
assert!(file_content_2.contains("cat.ts"));
17981813
}
17991814

1815+
#[tokio::test]
1816+
async fn install_force_regenerates_lockfile() {
1817+
let temp_dir = TempDir::new();
1818+
let bin_dir = temp_dir.path().join("bin");
1819+
std::fs::create_dir(&bin_dir).unwrap();
1820+
1821+
// initial install creates the config dir
1822+
create_install_shim(
1823+
&Flags::default(),
1824+
InstallFlagsGlobal {
1825+
module_urls: vec!["http://localhost:4545/echo.ts".to_string()],
1826+
args: vec![],
1827+
name: Some("echo_test".to_string()),
1828+
root: Some(temp_dir.path().to_string()),
1829+
force: false,
1830+
compile: false,
1831+
},
1832+
)
1833+
.await
1834+
.unwrap();
1835+
1836+
// simulate a stale auto-generated lockfile from a prior install
1837+
let config_dir = bin_dir.join(".echo_test");
1838+
let lockfile_path = config_dir.join("deno.lock");
1839+
let stale_lockfile =
1840+
r#"{"version":"5","specifiers":{"npm:cowsay@*":"1.0.0"}}"#;
1841+
fs::write(&lockfile_path, stale_lockfile).unwrap();
1842+
assert!(lockfile_path.exists());
1843+
1844+
// reinstall with --force; stale lockfile should be removed
1845+
create_install_shim(
1846+
&Flags::default(),
1847+
InstallFlagsGlobal {
1848+
module_urls: vec!["http://localhost:4545/echo.ts".to_string()],
1849+
args: vec![],
1850+
name: Some("echo_test".to_string()),
1851+
root: Some(temp_dir.path().to_string()),
1852+
force: true,
1853+
compile: false,
1854+
},
1855+
)
1856+
.await
1857+
.unwrap();
1858+
1859+
let post_force_content = fs::read_to_string(&lockfile_path).ok();
1860+
assert_ne!(post_force_content.as_deref(), Some(stale_lockfile));
1861+
}
1862+
18001863
#[tokio::test]
18011864
async fn install_with_config() {
18021865
let temp_dir = TempDir::new();

0 commit comments

Comments
 (0)