Skip to content

Commit

Permalink
feat: add semver dependency and update uninstall command to use Seman…
Browse files Browse the repository at this point in the history
…tic Version pattern
  • Loading branch information
GNURub committed Oct 24, 2024
1 parent 5ee290f commit 71601f2
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 53 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ clap_complete = "4.5.2"
anyhow = "1.0.86"
indicatif = { version = "0.17.8", features = ["improved_unicode"] }
flate2 = "1.0.30"
semver = "1.0.23"

[dev-dependencies]
pretty_assertions = "1.4.0"
Expand Down
2 changes: 1 addition & 1 deletion docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ Options:
# `fnm uninstall`

```
Uninstall a Node.js version
Uninstall a Node.js version. Allow multiple versions using semantic versioning to be uninstalled at once. Example: `fnm uninstall "<v22.0.0"`
> Warning: when providing an alias, it will remove the Node version the alias > is pointing to, along with the other aliases that point to the same version.
Expand Down
97 changes: 45 additions & 52 deletions src/commands/uninstall.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use semver::VersionReq;
use super::command::Command;
use crate::config::FnmConfig;
use crate::fs::remove_symlink_dir;
use crate::installed_versions;
use crate::outln;
use crate::user_version::UserVersion;
use crate::version::Version;
use crate::version_files::get_user_version_for_directory;
use colored::Colorize;
Expand All @@ -12,7 +12,7 @@ use thiserror::Error;

#[derive(clap::Parser, Debug)]
pub struct Uninstall {
version: Option<UserVersion>,
version: Option<String>,
}

impl Command for Uninstall {
Expand All @@ -21,63 +21,58 @@ impl Command for Uninstall {
fn apply(self, config: &FnmConfig) -> Result<(), Self::Error> {
let all_versions = installed_versions::list(config.installations_dir())
.map_err(|source| Error::VersionListingError { source })?;
let requested_version = self
.version
.or_else(|| {
let current_dir = std::env::current_dir().unwrap();
get_user_version_for_directory(current_dir, config)
})
.ok_or(Error::CantInferVersion)?;

if matches!(requested_version, UserVersion::Full(Version::Bypassed)) {
return Err(Error::CantUninstallSystemVersion);
}
let requested_version_str = self.version.or_else(|| {
std::env::current_dir()
.ok()
.and_then(|dir| get_user_version_for_directory(dir, config).map(|v| v.to_string()))
})
.ok_or(Error::CantInferVersion)?;

let available_versions: Vec<&Version> = all_versions
.iter()
.filter(|v| requested_version.matches(v, config))
.collect();
let requested_version = VersionReq::parse(&requested_version_str.replace("v", ""))
.map_err(|_| Error::InvalidVersionFormat { version: requested_version_str.clone() })?;

if available_versions.len() >= 2 {
return Err(Error::PleaseBeMoreSpecificToDelete {
matched_versions: available_versions
.iter()
.map(std::string::ToString::to_string)
.collect(),
});
}
let matching_versions: Vec<&Version> = all_versions.iter().filter_map(|v| {
let ver = v.v_str().trim_start_matches('v').to_string();
semver::Version::parse(&ver)
.ok()
.filter(|parsed_version| requested_version.matches(parsed_version))
.map(|_| v)
}).collect();

let version = requested_version
.to_version(&all_versions, config)
.ok_or(Error::CantFindVersion)?;
if matching_versions.is_empty() {
return Err(Error::CantFindVersion);
}

let matching_aliases = version.find_aliases(config)?;
let root_path = version
.root_path(config)
.ok_or_else(|| Error::RootPathNotFound {
for version in matching_versions {
let matching_aliases = version.find_aliases(config)?;
let root_path = version
.root_path(config)
.ok_or_else(|| Error::RootPathNotFound {
version: version.clone(),
})?;

debug!("Removing Node version from {:?}", root_path);
std::fs::remove_dir_all(root_path)
.map_err(|source| Error::CantDeleteNodeVersion { source })?;
outln!(
config,
Info,
"Node version {} was removed successfully",
version.v_str().cyan()
);

for alias in matching_aliases {
debug!("Removing alias from {:?}", alias.path());
remove_symlink_dir(alias.path())
.map_err(|source| Error::CantDeleteSymlink { source })?;
debug!("Removing Node version from {:?}", root_path);
std::fs::remove_dir_all(root_path)
.map_err(|source| Error::CantDeleteNodeVersion { source })?;
outln!(
config,
Info,
"Alias {} was removed successfully",
alias.name().cyan()
"Node version {} was removed successfully",
version.v_str().cyan()
);

for alias in matching_aliases {
debug!("Removing alias from {:?}", alias.path());
remove_symlink_dir(alias.path())
.map_err(|source| Error::CantDeleteSymlink { source })?;
outln!(
config,
Info,
"Alias {} was removed successfully",
alias.name().cyan()
);
}
}

Ok(())
Expand All @@ -90,11 +85,9 @@ pub enum Error {
VersionListingError { source: installed_versions::Error },
#[error("Can't find version in dotfiles. Please provide a version manually to the command.")]
CantInferVersion,
#[error("Can't uninstall system version")]
CantUninstallSystemVersion,
#[error("Too many versions had matched, please be more specific.\nFound {} matching versions, expected 1:\n{}", matched_versions.len(), matched_versions.iter().map(|v| format!("* {v}")).collect::<Vec<_>>().join("\n"))]
PleaseBeMoreSpecificToDelete { matched_versions: Vec<String> },
#[error("Can't find a matching version")]
#[error("Invalid version format: {}", version)]
InvalidVersionFormat { version: String },
#[error("Can't find any matching versions")]
CantFindVersion,
#[error("Root path not found for version {}", version)]
RootPathNotFound { version: Version },
Expand Down

0 comments on commit 71601f2

Please sign in to comment.