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
4 changes: 1 addition & 3 deletions crates/vite_global_cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,9 +816,7 @@ async fn managed_update(
}

async fn get_current_node_version() -> Result<String, Error> {
let cwd = vite_path::current_dir().map_err(|error| {
Error::ConfigError(format!("Cannot get current directory: {error}").into())
})?;
let cwd = vite_path::current_dir()?;
Ok(resolve_version(&cwd).await?.version)
}

Expand Down
3 changes: 1 addition & 2 deletions crates/vite_global_cli/src/commands/env/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ fn compare_versions(a: &str, b: &str) -> Ordering {

/// Execute the list command (local installed versions).
pub async fn execute(cwd: AbsolutePathBuf, json_output: bool) -> Result<ExitStatus, Error> {
let home_dir =
vite_shared::get_vp_home().map_err(|e| Error::ConfigError(format!("{e}").into()))?;
let home_dir = vite_shared::get_vp_home()?;
let node_dir = home_dir.join("js_runtime").join("node");

let versions = list_installed_versions(node_dir.as_path());
Expand Down
5 changes: 2 additions & 3 deletions crates/vite_global_cli/src/commands/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,14 @@ pub async fn execute(cwd: AbsolutePathBuf, args: EnvArgs) -> Result<ExitStatus,
crate::cli::EnvSubcommands::Uninstall { version } => {
let provider = vite_js_runtime::NodeProvider::new();
let resolved = config::resolve_version_alias(&version, &provider).await?;
let home_dir = vite_shared::get_vp_home()
.map_err(|e| crate::error::Error::ConfigError(format!("{e}").into()))?;
let home_dir = vite_shared::get_vp_home()?;
let version_dir = home_dir.join("js_runtime").join("node").join(&resolved);
if !version_dir.as_path().exists() {
eprintln!("Node.js v{} is not installed", resolved);
return Ok(exit_status(1));
}
tokio::fs::remove_dir_all(version_dir.as_path()).await.map_err(|e| {
crate::error::Error::ConfigError(
crate::error::Error::Other(
format!("Failed to remove Node.js v{}: {}", resolved, e).into(),
)
})?;
Expand Down
8 changes: 2 additions & 6 deletions crates/vite_global_cli/src/commands/env/package_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,7 @@ impl PackageMetadata {
return Ok(None);
}
let content = tokio::fs::read_to_string(&path).await?;
let metadata: Self = serde_json::from_str(&content).map_err(|e| {
Error::ConfigError(format!("Failed to parse package metadata: {e}").into())
})?;
let metadata: Self = serde_json::from_str(&content).map_err(Error::JsonError)?;
Ok(Some(metadata))
}

Expand All @@ -100,9 +98,7 @@ impl PackageMetadata {
tokio::fs::create_dir_all(parent).await?;
}

let content = serde_json::to_string_pretty(self).map_err(|e| {
Error::ConfigError(format!("Failed to serialize package metadata: {e}").into())
})?;
let content = serde_json::to_string_pretty(self).map_err(Error::JsonError)?;
tokio::fs::write(&path, content).await?;
Ok(())
}
Expand Down
6 changes: 3 additions & 3 deletions crates/vite_global_cli/src/commands/env/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ async fn do_pin(
}
PinTarget::DevEngines => {
if !package_json_exists {
return Err(Error::ConfigError(
return Err(Error::Other(
format!(
"cannot pin to devEngines: no {} in {}",
PACKAGE_JSON_FILE,
Expand Down Expand Up @@ -398,7 +398,7 @@ async fn write_dev_engines_node_version(cwd: &AbsolutePathBuf, version: &str) ->
let updated = vite_shared::edit_json_object(&content, |obj| {
set_dev_engines_runtime_node(obj, version);
})
.map_err(|e| Error::ConfigError(format!("failed to update package.json: {e}").into()))?;
.map_err(|e| Error::Other(format!("failed to update package.json: {e}").into()))?;
tokio::fs::write(&package_json_path, updated).await?;
Ok(())
}
Expand Down Expand Up @@ -493,7 +493,7 @@ async fn remove_dev_engines_runtime_node(cwd: &AbsolutePathBuf) -> Result<bool,
obj.remove("devEngines");
}
})
.map_err(|e| Error::ConfigError(format!("failed to update package.json: {e}").into()))?;
.map_err(|e| Error::Other(format!("failed to update package.json: {e}").into()))?;

if removed {
tokio::fs::write(&package_json_path, updated).await?;
Expand Down
16 changes: 7 additions & 9 deletions crates/vite_global_cli/src/commands/env/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ pub async fn execute(refresh: bool, env_only: bool) -> Result<ExitStatus, Error>
tokio::fs::create_dir_all(&bin_dir).await?;

// Get the current executable path (for shims)
let current_exe = std::env::current_exe()
.map_err(|e| Error::ConfigError(format!("Cannot find current executable: {e}").into()))?;
let current_exe = std::env::current_exe()?;

// Create wrapper script in bin/
setup_vp_wrapper(&current_exe, &bin_dir, refresh).await?;
Expand Down Expand Up @@ -328,7 +327,7 @@ async fn create_unix_shim(
tool: &str,
) -> Result<(), Error> {
let bin_dir = shim_path.parent().ok_or_else(|| {
Error::ConfigError(format!("Cannot find parent directory for {tool} shim").into())
Error::Other(format!("Cannot find parent directory for {tool} shim").into())
})?;
let target = resolve_unix_vp_shim_target(source, bin_dir).await?;
tokio::fs::symlink(&target, shim_path).await?;
Expand Down Expand Up @@ -414,19 +413,18 @@ pub(crate) fn get_trampoline_path() -> Result<vite_path::AbsolutePathBuf, Error>
let path = std::path::PathBuf::from(override_path);
if path.exists() {
return vite_path::AbsolutePathBuf::new(path)
.ok_or_else(|| Error::ConfigError("Invalid trampoline override path".into()));
.ok_or_else(|| Error::Other("Invalid trampoline override path".into()));
}
}

let current_exe = std::env::current_exe()
.map_err(|e| Error::ConfigError(format!("Cannot find current executable: {e}").into()))?;
let current_exe = std::env::current_exe()?;
let bin_dir = current_exe
.parent()
.ok_or_else(|| Error::ConfigError("Cannot find parent directory of vp.exe".into()))?;
.ok_or_else(|| Error::Other("Cannot find parent directory of vp.exe".into()))?;
let trampoline = bin_dir.join("vp-shim.exe");

if !trampoline.exists() {
return Err(Error::ConfigError(
return Err(Error::Other(
format!(
"Trampoline binary not found at {}. Re-install vite-plus to fix this.",
trampoline.display()
Expand All @@ -436,7 +434,7 @@ pub(crate) fn get_trampoline_path() -> Result<vite_path::AbsolutePathBuf, Error>
}

vite_path::AbsolutePathBuf::new(trampoline)
.ok_or_else(|| Error::ConfigError("Invalid trampoline path".into()))
.ok_or_else(|| Error::Other("Invalid trampoline path".into()))
}

/// Try to delete an `.exe` file; if deletion fails (e.g., file is locked by a
Expand Down
7 changes: 2 additions & 5 deletions crates/vite_global_cli/src/commands/env/use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,8 @@ pub async fn execute(

// Ensure version is installed (unless --no-install)
if !no_install {
let home_dir = vite_shared::get_vp_home()
.map_err(|e| Error::ConfigError(format!("{e}").into()))?
.join("js_runtime")
.join("node")
.join(&resolved_version);
let home_dir =
vite_shared::get_vp_home()?.join("js_runtime").join("node").join(&resolved_version);

#[cfg(windows)]
let binary_path = home_dir.join("node.exe");
Expand Down
10 changes: 5 additions & 5 deletions crates/vite_global_cli/src/commands/env/which.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,13 @@ fn locate_package_binary(package_name: &str, binary_name: &str) -> Result<Absolu
let package_json_path = node_modules_dir.join("package.json");

if !package_json_path.as_path().exists() {
return Err(Error::ConfigError(format!("Package {} not found", package_name).into()));
return Err(Error::Other(format!("Package {} not found", package_name).into()));
}

// Read package.json to find the binary path
let content = std::fs::read_to_string(package_json_path.as_path())?;
let package_json: serde_json::Value = serde_json::from_str(&content)
.map_err(|e| Error::ConfigError(format!("Failed to parse package.json: {e}").into()))?;
.map_err(|e| Error::Other(format!("Failed to parse package.json: {e}").into()))?;

let binary_path = match package_json.get("bin") {
Some(serde_json::Value::String(path)) => {
Expand All @@ -245,7 +245,7 @@ fn locate_package_binary(package_name: &str, binary_name: &str) -> Result<Absolu
if expected_name == binary_name {
node_modules_dir.join(path)
} else {
return Err(Error::ConfigError(
return Err(Error::Other(
format!("Binary {} not found in package", binary_name).into(),
));
}
Expand All @@ -255,13 +255,13 @@ fn locate_package_binary(package_name: &str, binary_name: &str) -> Result<Absolu
if let Some(serde_json::Value::String(path)) = map.get(binary_name) {
node_modules_dir.join(path)
} else {
return Err(Error::ConfigError(
return Err(Error::Other(
format!("Binary {} not found in package", binary_name).into(),
));
}
}
_ => {
return Err(Error::ConfigError(
return Err(Error::Other(
format!("No bin field in package.json for {}", package_name).into(),
));
}
Expand Down
22 changes: 7 additions & 15 deletions crates/vite_global_cli/src/commands/global/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,7 @@ pub async fn install(
// Resolve from current directory
let cwd = match current_dir() {
Ok(cwd) => cwd,
Err(error) => {
let error =
Error::ConfigError(format!("Cannot get current directory: {}", error).into());
return Err((None, error));
}
Err(error) => return Err((None, error.into())),
};
let resolution = match resolve_version(&cwd).await {
Ok(resolution) => resolution,
Expand Down Expand Up @@ -535,7 +531,7 @@ async fn install_one(
}
let _ = std::io::stderr().write_all(&output.stderr);
cleanup_failed_install(package_name, backup).await?;
return Err(Error::ConfigError(
return Err(Error::Other(
format!("npm install failed with exit code: {:?}", output.status.code()).into(),
));
}
Expand All @@ -545,7 +541,7 @@ async fn install_one(

if !tokio::fs::try_exists(&package_json_path).await.unwrap_or(false) {
cleanup_failed_install(package_name, backup).await?;
return Err(Error::ConfigError(
return Err(Error::Other(
format!(
"Package was not installed correctly, package.json not found at {}",
package_json_path.as_path().display()
Expand All @@ -565,9 +561,7 @@ async fn install_one(
Ok(package_json) => package_json,
Err(error) => {
cleanup_failed_install(package_name, backup).await?;
return Err(Error::ConfigError(
format!("Failed to parse package.json: {error}").into(),
));
return Err(Error::Other(format!("Failed to parse package.json: {error}").into()));
}
};

Expand Down Expand Up @@ -648,7 +642,7 @@ fn unique_backup_dir(package_name: &str) -> Result<AbsolutePathBuf, Error> {
backup_path.set_file_name(backup_name);

AbsolutePathBuf::new(backup_path)
.ok_or_else(|| Error::ConfigError("Invalid global package backup path".into()))
.ok_or_else(|| Error::Other("Invalid global package backup path".into()))
}

async fn cleanup_failed_install(
Expand Down Expand Up @@ -723,7 +717,7 @@ async fn stale_bin_names_for_package(
pub async fn uninstall(package_name: &str, dry_run: bool) -> Result<(), Error> {
if is_local_package_spec(package_name) {
// We can't resolve local packages for uninstall, follow npm's behavior
return Err(Error::ConfigError(
return Err(Error::Other(
format!(
"Local path {} can't be resolved, please enter a package name instead",
package_name
Expand All @@ -741,9 +735,7 @@ pub async fn uninstall(package_name: &str, dry_run: bool) -> Result<(), Error> {
// Phase 2: Fallback - scan BinConfig files for orphaned binaries
let orphan_bins = BinConfig::find_by_package(&package_name).await?;
if orphan_bins.is_empty() {
return Err(Error::ConfigError(
format!("Package {} is not installed", package_name).into(),
));
return Err(Error::Other(format!("Package {} is not installed", package_name).into()));
}
orphan_bins
};
Expand Down
38 changes: 14 additions & 24 deletions crates/vite_global_cli/src/commands/global/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ struct NpmRegistry {

impl NpmRegistry {
async fn resolve() -> Result<Self, Error> {
let cwd = current_dir().map_err(|error| {
Error::ConfigError(format!("Cannot get current directory: {error}").into())
})?;
let cwd = current_dir()?;
let resolution = resolve_version(&cwd).await?;
let runtime = vite_js_runtime::download_runtime(
vite_js_runtime::JsRuntimeType::Node,
Expand Down Expand Up @@ -78,9 +76,7 @@ async fn npm_view(

if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
return Err(Error::ConfigError(
format!("npm view failed for {package_spec}: {stderr}").into(),
));
return Err(Error::Other(format!("npm view failed for {package_spec}: {stderr}").into()));
}

Ok(output.stdout)
Expand Down Expand Up @@ -159,7 +155,7 @@ pub(crate) fn parse_package_spec(spec: &str) -> Result<(String, Option<String>),
if is_local_package_spec(spec) {
let package_json = read_local_package_json(spec)?;
let Some(package_name) = package_json.get("name").and_then(|name| name.as_str()) else {
return Err(Error::ConfigError(
return Err(Error::Other(
format!("Local package {spec} must have a string name in package.json").into(),
));
};
Expand Down Expand Up @@ -187,13 +183,9 @@ fn resolve_local_package_path(spec: &str) -> Result<AbsolutePathBuf, Error> {
let path = std::path::Path::new(path_spec);
if path.is_absolute() {
AbsolutePathBuf::new(path.to_path_buf())
.ok_or_else(|| Error::ConfigError(format!("Invalid local package path {spec}").into()))
.ok_or_else(|| Error::Other(format!("Invalid local package path {spec}").into()))
} else {
Ok(current_dir()
.map_err(|error| {
Error::ConfigError(format!("Cannot get current directory: {error}").into())
})?
.join(path))
Ok(current_dir()?.join(path))
}
}

Expand All @@ -206,7 +198,7 @@ fn read_local_package_json(spec: &str) -> Result<serde_json::Value, Error> {
let package_json_path = package_path.join("package.json");
let package_json_content =
std::fs::read_to_string(package_json_path.as_path()).map_err(|error| {
Error::ConfigError(
Error::Other(
format!(
"Failed to read package.json for local package {spec} at {}: {error}",
package_json_path.as_path().display()
Expand All @@ -227,7 +219,7 @@ fn read_package_json_from_tarball(
package_path: &AbsolutePathBuf,
) -> Result<serde_json::Value, Error> {
let file = File::open(package_path.as_path()).map_err(|error| {
Error::ConfigError(
Error::Other(
format!(
"Failed to read package tarball {spec} at {}: {error}",
package_path.as_path().display()
Expand All @@ -239,44 +231,42 @@ fn read_package_json_from_tarball(
let mut archive = Archive::new(decoder);

for entry in archive.entries().map_err(|error| {
Error::ConfigError(format!("Failed to read package tarball {spec}: {error}").into())
Error::Other(format!("Failed to read package tarball {spec}: {error}").into())
})? {
let mut entry = entry.map_err(|error| {
Error::ConfigError(format!("Failed to read package tarball {spec}: {error}").into())
Error::Other(format!("Failed to read package tarball {spec}: {error}").into())
})?;
let path = entry.path().map_err(|error| {
Error::ConfigError(format!("Failed to read package tarball {spec}: {error}").into())
Error::Other(format!("Failed to read package tarball {spec}: {error}").into())
})?;
if path.as_ref() != std::path::Path::new("package/package.json") {
continue;
}

let mut package_json_content = String::new();
entry.read_to_string(&mut package_json_content).map_err(|error| {
Error::ConfigError(
Error::Other(
format!("Failed to read package.json from package tarball {spec}: {error}").into(),
)
})?;
return serde_json::from_str(&package_json_content).map_err(Error::JsonError);
}

Err(Error::ConfigError(
format!("Package tarball {spec} must contain package/package.json").into(),
))
Err(Error::Other(format!("Package tarball {spec} must contain package/package.json").into()))
}

fn parse_npm_view_version(stdout: &[u8]) -> Result<String, Error> {
let raw = String::from_utf8_lossy(stdout);
let trimmed = raw.trim();
if trimmed.is_empty() {
return Err(Error::ConfigError("npm view returned an empty version".into()));
return Err(Error::Other("npm view returned an empty version".into()));
}

match serde_json::from_str::<serde_json::Value>(trimmed) {
Ok(serde_json::Value::String(version)) => Ok(version),
Ok(serde_json::Value::Array(versions)) => {
let Some(version) = versions.iter().rev().find_map(|version| version.as_str()) else {
return Err(Error::ConfigError("npm view returned an empty version list".into()));
return Err(Error::Other("npm view returned an empty version list".into()));
};
Ok(version.to_string())
}
Expand Down
3 changes: 1 addition & 2 deletions crates/vite_global_cli/src/commands/global/packages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ pub async fn execute(json: bool, pattern: Option<&str>) -> Result<ExitStatus, Er
}

if json {
let json_output = serde_json::to_string_pretty(&packages)
.map_err(|e| Error::ConfigError(format!("Failed to serialize: {e}").into()))?;
let json_output = serde_json::to_string_pretty(&packages).map_err(Error::JsonError)?;
println!("{json_output}");
} else {
let col_pkg = "Package";
Expand Down
Loading
Loading