From 8d304a7169f6e423bd6f86efe846288b16aacaee Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 21 Jan 2023 18:36:17 +0100 Subject: [PATCH] Add version detection via package.json --- src/lib.rs | 4 +-- src/mapper/mod.rs | 30 +++++++++++++++----- src/mapper/package_info.rs | 56 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 src/mapper/package_info.rs diff --git a/src/lib.rs b/src/lib.rs index 5cf9365..74d5418 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ use std::ffi::OsString; -use consts::{DATA_DIR, VERSION_FILE_PATH}; +use consts::VERSION_FILE_PATH; use crossterm::style::Stylize; use mapper::Mapper; use repository::{config::Config, NodeVersion, Repository}; @@ -80,5 +80,5 @@ async fn get_repository() -> Result { } async fn get_mapper() -> Result { - Ok(Mapper::new(get_repository().await?)) + Ok(Mapper::load(get_repository().await?).await) } diff --git a/src/mapper/mod.rs b/src/mapper/mod.rs index 2961d28..8c006f8 100644 --- a/src/mapper/mod.rs +++ b/src/mapper/mod.rs @@ -8,11 +8,16 @@ use crate::{ repository::{NodeVersion, Repository}, }; -use self::{error::MapperError, mapped_command::MappedCommand, mapped_dir::map_node_bin}; +use self::{ + error::MapperError, mapped_command::MappedCommand, mapped_dir::map_node_bin, + package_info::PackageInfo, +}; pub mod error; mod mapped_command; mod mapped_dir; +mod package_info; + /// Responsible for mapping to node executables /// and managing node versions pub struct Mapper { @@ -21,9 +26,10 @@ pub struct Mapper { } impl Mapper { - pub fn new(repository: Repository) -> Self { - let version = - Self::get_version().unwrap_or_else(|| repository.config.default_version.to_owned()); + pub async fn load(repository: Repository) -> Self { + let version = Self::get_version() + .await + .unwrap_or_else(|| repository.config.default_version.to_owned()); Self { repo: repository, active_version: version, @@ -77,10 +83,20 @@ impl Mapper { Ok(()) } - fn get_version() -> Option { - env::var("NODE_VERSION") + async fn get_version() -> Option { + if let Some(version) = PackageInfo::find() + .await .ok() - .and_then(|v| NodeVersion::from_str(&v).ok()) + .and_then(|i| i) + .and_then(|i| i.engines) + .and_then(|e| e.node) + { + Some(NodeVersion::Req(version)) + } else { + env::var("NODE_VERSION") + .ok() + .and_then(|v| NodeVersion::from_str(&v).ok()) + } } /// creates wrapper scripts for the current version diff --git a/src/mapper/package_info.rs b/src/mapper/package_info.rs new file mode 100644 index 0000000..3b5e9bf --- /dev/null +++ b/src/mapper/package_info.rs @@ -0,0 +1,56 @@ +use std::{collections::HashMap, path::Path}; + +use semver::VersionReq; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use tokio::fs; + +use crate::error::LibResult; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct PackageInfo { + pub engines: Option, + + #[serde(flatten)] + other: HashMap, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct EngineInfo { + pub node: Option, + + #[serde(flatten)] + other: HashMap, +} + +impl PackageInfo { + pub async fn find() -> LibResult> { + let mut dir = std::env::current_dir()?; + let file_path = dir.join("package.json"); + + if file_path.exists() { + let info = Self::load(&file_path).await?; + + Ok(Some(info)) + } else { + while let Some(parent) = dir.parent() { + dir = parent.to_owned(); + let file_path = dir.join("package.json"); + + if file_path.exists() { + let info = Self::load(&file_path).await?; + return Ok(Some(info)); + } + } + Ok(None) + } + } + + /// Loads the package.json config file + pub async fn load(path: &Path) -> LibResult { + let file_content = fs::read_to_string(&path).await?; + let cfg = serde_json::from_str(&file_content)?; + + Ok(cfg) + } +}