Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions crates/vite_global_cli/src/commands/global/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,16 @@ pub async fn install(
continue;
};
let mut backup = backup;
let stale_bin_names = match stale_bin_names_for_package(&package_name, &bin_names).await {
Ok(bin_names) => bin_names,
Err(error) => {
let _ = cleanup_failed_install(&package_name, backup.take()).await;
if first_error.is_none() {
first_error = Some(package_error(&package_name, error));
}
continue;
}
};

let mut conflicts = Vec::<(String, String)>::new();
let mut finalize_blocked = false;
Expand Down Expand Up @@ -336,12 +346,35 @@ pub async fn install(
continue;
}

// 4.5 Commit the install by discarding the backup and reporting the installed bins.
// 4.5 Remove shims for binaries the package used to expose but no longer declares.
for bin_name in stale_bin_names {
let result = async {
remove_package_shim(&bin_dir, &bin_name).await?;
BinConfig::delete(&bin_name).await?;
Ok::<(), Error>(())
}
.await;

if let Err(error) = result.map_err(|error| package_error(&package_name, error)) {
let _ = cleanup_failed_install(&package_name, backup.take()).await;
if first_error.is_none() {
first_error = Some(error);
}
finalized = false;
break;
}
}

if !finalized {
continue;
}

// 4.6 Commit the install by discarding the backup and reporting the installed bins.
if let Some(backup) = backup {
backup.discard().await;
}

// 4.6 Print success message
// 4.7 Print success message
output::success(&format!(
"{} {} {}{}",
operation_past,
Expand Down Expand Up @@ -552,6 +585,23 @@ async fn cleanup_installed_package(package_name: &str) -> Result<(), Error> {
Ok(())
}

async fn stale_bin_names_for_package(
package_name: &str,
current_bin_names: &[String],
) -> Result<Vec<String>, Error> {
let current_bin_names: HashSet<_> = current_bin_names.iter().cloned().collect();
let mut previous_bin_names = HashSet::new();

if let Some(metadata) = PackageMetadata::load(package_name).await? {
previous_bin_names.extend(metadata.bins);
}

previous_bin_names.extend(BinConfig::find_by_package(package_name).await?);
previous_bin_names.retain(|bin_name| !current_bin_names.contains(bin_name));

Ok(previous_bin_names.into_iter().collect())
}

/// Uninstall a global package.
///
/// Uses two-phase uninstall:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const fs = require('fs');
const path = require('path');

const shimSuffix = process.platform === 'win32' ? '.exe' : '';
const shim = path.join(process.env.VP_HOME, 'bin', 'env-install-stale-drop' + shimSuffix);
const config = path.join(process.env.VP_HOME, 'bins/env-install-stale-drop.json');

console.log(fs.existsSync(shim) ? 'stale shim exists' : 'stale shim removed');
console.log(fs.existsSync(config) ? 'stale config exists' : 'stale config removed');
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
console.log('env-install-stale-drop ok');
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
console.log('env-install-stale-keep ok');
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "env-install-stale-bin-pkg",
"version": "1.0.0",
"bin": {
"env-install-stale-drop": "./cli-drop.js",
"env-install-stale-keep": "./cli-keep.js"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
console.log('env-install-stale-keep ok');
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "env-install-stale-bin-pkg",
"version": "2.0.0",
"bin": {
"env-install-stale-keep": "./cli-keep.js"
}
}
20 changes: 20 additions & 0 deletions packages/cli/snap-tests-global/env-install-stale-bin/snap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
> vp install -g ./env-install-stale-bin-pkg-v1 # Install package with two binaries
info: Installing 1 global package with Node.js <semver>
✓ Installed env-install-stale-bin-pkg <semver>
Bins: env-install-stale-drop, env-install-stale-keep

> env-install-stale-keep && env-install-stale-drop # Both binaries should be callable
env-install-stale-keep ok
env-install-stale-drop ok

> vp install -g ./env-install-stale-bin-pkg-v2 # Reinstall package version that removed one binary
info: Installing 1 global package with Node.js <semver>
✓ Installed env-install-stale-bin-pkg <semver>
Bins: env-install-stale-keep

> env-install-stale-keep # Remaining binary should still be callable
env-install-stale-keep ok

> node check-stale-binary.js
stale shim removed
stale config removed
11 changes: 11 additions & 0 deletions packages/cli/snap-tests-global/env-install-stale-bin/steps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"env": {},
"commands": [
"vp install -g ./env-install-stale-bin-pkg-v1 # Install package with two binaries",
"env-install-stale-keep && env-install-stale-drop # Both binaries should be callable",
"vp install -g ./env-install-stale-bin-pkg-v2 # Reinstall package version that removed one binary",
"env-install-stale-keep # Remaining binary should still be callable",
"node check-stale-binary.js"
],
"after": ["vp remove -g env-install-stale-bin-pkg"]
}
Loading