diff --git a/src/lib.rs b/src/lib.rs index 74d5418..41ac881 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,7 @@ pub async fn install_version(version: NodeVersion) -> Result<()> { fs::remove_file(&*VERSION_FILE_PATH).await?; let repo = get_repository().await?; - if repo.is_installed(&version).await? { + if repo.is_installed(&version) { if !Confirm::new() .with_prompt("The version {version} is already installed. Reinstall?") .default(false) @@ -38,7 +38,7 @@ pub async fn install_version(version: NodeVersion) -> Result<()> { pub async fn set_default_version(version: NodeVersion) -> Result<()> { let mut mapper = get_mapper().await?; - if !mapper.repository().is_installed(&version).await? + if !mapper.repository().is_installed(&version) && Confirm::new() .with_prompt(format!( "The version {version} is not installed. Do you want to install it?" @@ -56,11 +56,12 @@ pub async fn set_default_version(version: NodeVersion) -> Result<()> { Ok(()) } +#[inline] pub async fn exec(command: String, args: Vec) -> Result { let mapper = get_mapper().await?; let active_version = mapper.active_version(); - if !mapper.repository().is_installed(active_version).await? { + if !mapper.repository().is_installed(active_version) { mapper.repository().install_version(&active_version).await?; } let exit_status = mapper.exec(command, args).await?; diff --git a/src/main.rs b/src/main.rs index 6d10ff7..c4791d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ mod args; async fn main() -> nenv::error::Result<()> { color_eyre::install().unwrap(); let args: Args = Args::parse(); + match args.commmand { args::Command::Version => Ok(print_version()), args::Command::Install(v) => nenv::install_version(v.version).await, diff --git a/src/mapper/mod.rs b/src/mapper/mod.rs index 8c006f8..82eeb16 100644 --- a/src/mapper/mod.rs +++ b/src/mapper/mod.rs @@ -58,11 +58,9 @@ impl Mapper { /// Executes a mapped command with the given node environment pub async fn exec(&self, command: String, args: Vec) -> LibResult { - self.map_active_version().await?; let node_path = self .repo .get_version_path(&self.active_version) - .await? .expect("version not installed"); let executable = node_path.bin().join(command); let exit_status = MappedCommand::new(executable, args) @@ -104,7 +102,6 @@ impl Mapper { let dir = self .repo .get_version_path(&self.active_version) - .await? .expect("missing version"); map_node_bin(dir).await?; diff --git a/src/repository/mod.rs b/src/repository/mod.rs index 9b25053..2fda370 100644 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -90,15 +90,7 @@ impl Repository { pub async fn init(config: Config) -> LibResult { Self::create_folders().await?; let web_api = WebApi::new(&config.dist_base_url); - - let versions = if let Some(v) = Versions::load().await { - v - } else { - let all_versions = web_api.get_versions().await?; - let v = Versions::new(all_versions); - v.save().await?; - v - }; + let versions = load_versions(&web_api).await?; Ok(Self { config, @@ -125,24 +117,15 @@ impl Repository { } /// Returns the path for the given node version - pub async fn get_version_path(&self, version: &NodeVersion) -> LibResult> { + pub fn get_version_path(&self, version: &NodeVersion) -> Option { let info = self.parse_req(&version); - let mut iter = fs::read_dir(&*NODE_VERSIONS_DIR).await?; - let mut path = None; + let path = build_version_path(&info.version); - while let Some(entry) = iter.next_entry().await? { - if let Ok(version) = Version::parse(entry.file_name().to_string_lossy().as_ref()) { - if version == info.version { - path = Some(entry.path()); - } - }; + if path.exists() { + Some(NodePath::new(path)) + } else { + None } - let Some(path) = path else { - return Ok(None); - }; - let path = path.join(format!("node-v{}-{}-{}", info.version, OS, ARCH)); - - Ok(Some(NodePath::new(path))) } /// Returns a list of installed versions @@ -160,10 +143,10 @@ impl Repository { } /// Returns if the given version is installed - pub async fn is_installed(&self, version: &NodeVersion) -> LibResult { + pub fn is_installed(&self, version: &NodeVersion) -> bool { let info = self.parse_req(version); - Ok(self.installed_versions().await?.contains(&info.version)) + build_version_path(&info.version).exists() } /// Installs a specified node version @@ -208,3 +191,22 @@ impl Repository { } } } + +#[inline] +async fn load_versions(web_api: &WebApi) -> Result { + let versions = if let Some(v) = Versions::load().await { + v + } else { + let all_versions = web_api.get_versions().await?; + let v = Versions::new(all_versions); + v.save().await?; + v + }; + Ok(versions) +} + +fn build_version_path(version: &Version) -> PathBuf { + NODE_VERSIONS_DIR + .join(version.to_string()) + .join(format!("node-v{}-{}-{}", version, OS, ARCH)) +} diff --git a/src/repository/versions.rs b/src/repository/versions.rs index 44d067f..c9568a3 100644 --- a/src/repository/versions.rs +++ b/src/repository/versions.rs @@ -10,6 +10,7 @@ use crate::{consts::VERSION_FILE_PATH, error::LibResult, web_api::VersionInfo}; pub struct Versions { lts_versions: HashMap, versions: HashMap, + sorted_versions: Vec, } impl Versions { @@ -35,6 +36,12 @@ impl Versions { )) }) .collect::>(); + let mut sorted_versions = all_versions + .iter() + .map(|v| v.version.to_owned()) + .collect::>(); + sorted_versions.sort(); + let versions = all_versions .into_iter() .map(|v| (v.version.to_owned(), v)) @@ -43,6 +50,7 @@ impl Versions { Self { lts_versions, versions, + sorted_versions, } } @@ -55,11 +63,8 @@ impl Versions { /// Returns the latest known node version pub fn latest(&self) -> &VersionInfo { - let mut versions = self.versions.keys().collect::>(); - versions.sort(); - self.versions - .get(versions.last().expect("No known node versions")) + .get(self.sorted_versions.last().expect("No known node versions")) .unwrap() } @@ -82,13 +87,12 @@ impl Versions { /// Returns any version that fulfills the given requirement pub fn get_fulfilling(&self, req: &VersionReq) -> Option<&VersionInfo> { - let mut versions = self - .versions - .keys() + let fulfilling_versions = self + .sorted_versions + .iter() .filter(|v| req.matches(v)) .collect::>(); - versions.sort(); - self.versions.get(versions.last()?) + self.versions.get(fulfilling_versions.last()?) } } diff --git a/src/web_api/mod.rs b/src/web_api/mod.rs index 5f69d66..dcb2d4e 100644 --- a/src/web_api/mod.rs +++ b/src/web_api/mod.rs @@ -3,7 +3,10 @@ use std::{ fmt::{Debug, Display}, }; -use crate::{consts::NODE_ARCHIVE_SUFFIX, utils::progress_bar}; +use crate::{ + consts::{NODE_ARCHIVE_SUFFIX, NODE_DIST_URL}, + utils::progress_bar, +}; use self::error::{ApiError, ApiResult}; @@ -26,7 +29,7 @@ pub struct WebApi { impl Default for WebApi { fn default() -> Self { - Self::new("https://nodejs.org/dist") + Self::new(NODE_DIST_URL) } }