Skip to content
Open
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
141 changes: 54 additions & 87 deletions crates/vite_global_cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ use vite_pm_cli::PackageManagerCommand;
use vite_shared::output;

use crate::{
commands::{
self,
env::{global_install, package_metadata::PackageMetadata},
},
commands::{self, env::package_metadata::PackageMetadata, global},
error::Error,
help,
};

const DEFAULT_GLOBAL_INSTALL_CONCURRENCY: usize = 5;
const DEFAULT_GLOBAL_VIEW_CONCURRENCY: usize = 3 * DEFAULT_GLOBAL_INSTALL_CONCURRENCY;

#[derive(Clone, Copy, Debug)]
pub struct RenderOptions {
Expand Down Expand Up @@ -533,7 +531,7 @@ fn run_tasks_completions(current: &OsStr) -> Vec<clap_complete::CompletionCandid
/// Handle a parsed package-manager command.
///
/// `Install`/`Add`/`Update`/`Remove` invoked with `-g`/`--global` are routed
/// through the vite-plus-managed Node.js install store (`commands::env`).
/// through the vite-plus-managed Node.js install store (`commands::global`).
/// Everything else is forwarded to `vite_pm_cli::dispatch`, which executes
/// the underlying package manager (pnpm/npm/yarn/bun).
async fn run_package_manager_command(
Expand Down Expand Up @@ -562,13 +560,30 @@ async fn run_package_manager_command(
managed_update(packages, concurrency).await
}

PackageManagerCommand::Outdated {
global: true,
ref packages,
long,
format,
concurrency,
..
} => {
global::outdated::execute(
packages,
long,
format,
concurrency.unwrap_or(DEFAULT_GLOBAL_VIEW_CONCURRENCY),
Comment thread
liangmiQwQ marked this conversation as resolved.
)
.await
}

// `pm list -g` lists vite-plus-managed globals, not the underlying PM's.
PackageManagerCommand::Pm(vite_pm_cli::cli::PmCommands::List {
global: true,
json,
ref pattern,
..
}) => crate::commands::env::packages::execute(json, pattern.as_deref()).await,
}) => global::packages::execute(json, pattern.as_deref()).await,

cmd => {
commands::prepend_js_runtime_to_path_env(&cwd).await?;
Expand All @@ -583,7 +598,7 @@ async fn managed_install(
force: bool,
concurrency: Option<usize>,
) -> Result<ExitStatus, Error> {
if let Err((package_name, error)) = crate::commands::env::global_install::install(
if let Err((package_name, error)) = global::install::install(
packages,
node,
force,
Expand All @@ -604,106 +619,68 @@ async fn managed_install(

async fn managed_uninstall(packages: &[String], dry_run: bool) -> Result<ExitStatus, Error> {
for package in packages {
if let Err(e) = crate::commands::env::global_install::uninstall(package, dry_run).await {
if let Err(e) = global::install::uninstall(package, dry_run).await {
vite_shared::output::raw_stderr(&format!("Failed to uninstall {package}: {e}"));
return Ok(exit_status(1));
}
}
Ok(ExitStatus::default())
}

fn is_global_package_up_to_date(installed_version: &str, registry_version: &str) -> bool {
installed_version.trim() == registry_version.trim()
}

async fn managed_update(
packages: &[String],
concurrency: Option<usize>,
) -> Result<ExitStatus, Error> {
let all_packages = if packages.is_empty() {
let concurrency = concurrency.unwrap_or(DEFAULT_GLOBAL_INSTALL_CONCURRENCY);
let mut to_update: Vec<String> = Vec::new();

let packages = if packages.is_empty() {
let all = PackageMetadata::list_all().await?;
if all.is_empty() {
vite_shared::output::raw("No global packages installed.");
return Ok(ExitStatus::default());
}
Some(all)
} else {
None
};

let mut to_update: Vec<String> = Vec::new();
let mut skipped = 0usize;

if let Some(all) = all_packages {
for metadata in all {
match global_install::latest_package_version(&metadata.name).await {
Ok(latest_version)
if is_global_package_up_to_date(&metadata.version, &latest_version) =>
{
vite_shared::output::raw(&format!(
"{} is already up to date (v{}).",
metadata.name, metadata.version
));
skipped += 1;
}
Ok(_) => to_update.push(metadata.name.clone()),
Err(e) => {
vite_shared::output::raw_stderr(&format!(
"Could not check latest version for {}: {e}; updating anyway.",
metadata.name
));
to_update.push(metadata.name.clone());
}
}
}
None
} else {
let mut managed_specs = Vec::new();

for package in packages {
if global_install::is_local_package_spec(package) {
// Always update local packages
if global::is_local_package_spec(package) {
to_update.push(package.clone());
continue;
}

let (package_name, _) = global_install::parse_package_spec(package);
if let Some(metadata) = PackageMetadata::load(&package_name).await? {
match global_install::latest_package_version(package).await {
Ok(latest_version)
if is_global_package_up_to_date(&metadata.version, &latest_version) =>
{
vite_shared::output::raw(&format!(
"{} is already up to date (v{}).",
package_name, metadata.version
));
skipped += 1;
continue;
}
Ok(_) => {}
Err(e) => {
vite_shared::output::raw_stderr(&format!(
"Could not check latest version for {package}: {e}; updating anyway."
));
}
}
let (package_name, _) = global::parse_package_spec(package);
if PackageMetadata::load(&package_name).await?.is_some() {
managed_specs.push(package.clone());
} else {
to_update.push(package.clone());
}
to_update.push(package.clone());
}
}

Some(managed_specs)
};
to_update.extend(
global::outdated::get_outdated_packages(
&packages.unwrap_or(Vec::new()),
concurrency * 3,
true,
)
.await?
.into_iter()
.map(|package| package.spec.unwrap_or(package.name)),
);

if to_update.is_empty() {
if skipped > 0 {
vite_shared::output::raw("All global packages are up to date.");
}
vite_shared::output::raw("All global packages are up to date.");
return Ok(ExitStatus::default());
}

// Call reinstall logic
if let Err((package_name, error)) = global_install::install(
&to_update,
None,
false,
concurrency.unwrap_or(DEFAULT_GLOBAL_INSTALL_CONCURRENCY),
true,
)
.await
if let Err((package_name, error)) =
global::install::install(&to_update, None, false, concurrency, true).await
{
output::error(&format!(
"Failed to update {}: {error}",
Expand Down Expand Up @@ -956,20 +933,10 @@ pub fn try_parse_args_from_with_options(
#[cfg(test)]
mod tests {
use super::{
has_flag_before_terminator, is_global_package_up_to_date, should_force_global_delegate,
has_flag_before_terminator, should_force_global_delegate,
should_suppress_header_for_subcommand,
};

#[test]
fn skips_global_update_when_registry_and_node_versions_match() {
assert!(is_global_package_up_to_date("5.9.3", "5.9.3"));
}

#[test]
fn updates_global_package_when_registry_version_differs_from_installed_version() {
assert!(!is_global_package_up_to_date("5.9.2", "5.9.3"));
}

#[test]
fn detects_flag_before_option_terminator() {
assert!(has_flag_before_terminator(
Expand Down
4 changes: 2 additions & 2 deletions crates/vite_global_cli/src/commands/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ mod current;
mod default;
mod doctor;
mod exec;
pub mod global_install;
mod list;
mod list_remote;
mod off;
mod on;
pub mod package_metadata;
pub mod packages;
mod pin;
mod setup;
mod unpin;
Expand All @@ -24,6 +22,8 @@ mod which;

use std::process::ExitStatus;

#[cfg(windows)]
pub(crate) use setup::{cleanup_legacy_windows_shim, get_trampoline_path, remove_or_rename_to_old};
use vite_path::AbsolutePathBuf;

use crate::{
Expand Down
Loading
Loading