diff --git a/crates/notion-core/src/catalog.rs b/crates/notion-core/src/catalog.rs index 854258519..d3a832820 100644 --- a/crates/notion-core/src/catalog.rs +++ b/crates/notion-core/src/catalog.rs @@ -35,6 +35,8 @@ const PUBLIC_NODE_VERSION_INDEX: &'static str = "https://nodejs.org/dist/index.j /// URL of the index of available Yarn versions on the public git repository. const PUBLIC_YARN_VERSION_INDEX: &'static str = "https://github.com/notion-cli/yarn-releases/raw/master/index.json"; +/// URL of the latest Yarn version on the public yarnpkg.com +const PUBLIC_YARN_LATEST_VERSION: &'static str = "https://yarnpkg.com/latest-version"; /// Lazily loaded tool catalog. pub struct LazyCatalog { @@ -278,51 +280,7 @@ impl RegistryFetchError { impl Resolve for NodeCollection { fn resolve_public(&self, matching: &VersionReq) -> Fallible { - let index: Index = match read_cached_opt().unknown()? { - Some(serial) => serial, - None => { - let spinner = progress_spinner(&format!( - "Fetching public registry: {}", - PUBLIC_NODE_VERSION_INDEX - )); - let mut response: reqwest::Response = reqwest::get(PUBLIC_NODE_VERSION_INDEX) - .with_context(RegistryFetchError::from_error)?; - let response_text: String = response.text().unknown()?; - let cached: NamedTempFile = NamedTempFile::new().unknown()?; - - // Block to borrow cached for cached_file. - { - let mut cached_file: &File = cached.as_file(); - cached_file.write(response_text.as_bytes()).unknown()?; - } - - cached.persist(path::node_index_file()?).unknown()?; - - let expiry: NamedTempFile = NamedTempFile::new().unknown()?; - - // Block to borrow expiry for expiry_file. - { - let mut expiry_file: &File = expiry.as_file(); - - if let Some(expires_header) = response.headers().get::() { - write!(expiry_file, "{}", expires_header).unknown()?; - } else { - let expiry_date = - SystemTime::now() + Duration::from_secs(max_age(&response).into()); - - write!(expiry_file, "{}", HttpDate::from(expiry_date)).unknown()?; - } - } - - expiry.persist(path::node_index_expiry_file()?).unknown()?; - - let serial: serial::index::Index = - serde_json::de::from_str(&response_text).unknown()?; - - spinner.finish_and_clear(); - serial - } - }.into_index()?; + let index: Index = resolve_node_versions()?.into_index()?; let version = index.entries.iter() .rev() @@ -433,3 +391,76 @@ fn max_age(response: &reqwest::Response) -> u32 { // Default to four hours. 4 * 60 * 60 } + +fn resolve_node_versions() -> Result { + match read_cached_opt().unknown()? { + Some(serial) => Ok(serial), + None => { + let spinner = progress_spinner(&format!( + "Fetching public registry: {}", + PUBLIC_NODE_VERSION_INDEX + )); + let mut response: reqwest::Response = reqwest::get(PUBLIC_NODE_VERSION_INDEX) + .with_context(RegistryFetchError::from_error)?; + let response_text: String = response.text().unknown()?; + let cached: NamedTempFile = NamedTempFile::new().unknown()?; + + // Block to borrow cached for cached_file. + { + let mut cached_file: &File = cached.as_file(); + cached_file.write(response_text.as_bytes()).unknown()?; + } + + cached.persist(path::node_index_file()?).unknown()?; + + let expiry: NamedTempFile = NamedTempFile::new().unknown()?; + + // Block to borrow expiry for expiry_file. + { + let mut expiry_file: &File = expiry.as_file(); + + if let Some(expires_header) = response.headers().get::() { + write!(expiry_file, "{}", expires_header).unknown()?; + } else { + let expiry_date = + SystemTime::now() + Duration::from_secs(max_age(&response).into()); + + write!(expiry_file, "{}", HttpDate::from(expiry_date)).unknown()?; + } + } + + expiry.persist(path::node_index_expiry_file()?).unknown()?; + + let serial: serial::index::Index = + serde_json::de::from_str(&response_text).unknown()?; + + spinner.finish_and_clear(); + Ok(serial) + } + } +} + +pub fn parse_node_version(src: String) -> Fallible { + let mut version:String= src; + if version == "latest" { + let index = resolve_node_versions()?.into_index()?; + let mut latest_version:Version = index.entries.keys().next().unwrap().clone(); + for key in index.entries.keys() { + if key > &latest_version { + latest_version = key.clone(); + } + }; + version = latest_version.to_string(); + } + Ok(version) +} + +pub fn parse_yarn_version(src: String) -> Fallible { + let mut version:String = src; + if version == "latest" { + let mut response: reqwest::Response = reqwest::get(PUBLIC_YARN_LATEST_VERSION) + .with_context(RegistryFetchError::from_error)?; + version = response.text().unknown()?; + } + Ok(version) +} diff --git a/src/command/fetch.rs b/src/command/fetch.rs index bd9fbf63a..1ae418d86 100644 --- a/src/command/fetch.rs +++ b/src/command/fetch.rs @@ -1,6 +1,7 @@ use semver::VersionReq; use notion_core::serial::version::parse_requirements; +use notion_core::catalog::{parse_node_version, parse_yarn_version}; use notion_core::session::{ActivityKind, Session}; use notion_fail::{ExitCode, Fallible}; @@ -45,8 +46,14 @@ Options: }: Args, ) -> Fallible { match &arg_tool[..] { - "node" => Ok(Fetch::Node(parse_requirements(&arg_version)?)), - "yarn" => Ok(Fetch::Yarn(parse_requirements(&arg_version)?)), + "node" => { + let node_version = parse_node_version(arg_version)?; + Ok(Fetch::Node(parse_requirements(&node_version)?)) + }, + "yarn" => { + let yarn_version = parse_yarn_version(arg_version)?; + Ok(Fetch::Yarn(parse_requirements(&yarn_version)?)) + }, ref tool => { throw!(CliParseError { usage: None, diff --git a/src/command/install.rs b/src/command/install.rs index 74038a9e7..0264b8e1e 100644 --- a/src/command/install.rs +++ b/src/command/install.rs @@ -2,6 +2,7 @@ use semver::VersionReq; use notion_core::serial::version::parse_requirements; use notion_core::session::{ActivityKind, Session}; +use notion_core::catalog::{parse_node_version, parse_yarn_version}; use notion_fail::{ExitCode, Fallible}; use Notion; @@ -46,8 +47,14 @@ Options: }: Args, ) -> Fallible { match &arg_tool[..] { - "node" => Ok(Install::Node(parse_requirements(&arg_version)?)), - "yarn" => Ok(Install::Yarn(parse_requirements(&arg_version)?)), + "node" => { + let node_version = parse_node_version(arg_version)?; + Ok(Install::Node(parse_requirements(&node_version)?)) + }, + "yarn" => { + let yarn_version = parse_yarn_version(arg_version)?; + Ok(Install::Yarn(parse_requirements(&yarn_version)?)) + }, ref tool => Ok(Install::Other { name: tool.to_string(), version: parse_requirements(&arg_version)?, diff --git a/src/command/use_.rs b/src/command/use_.rs index 1c061627a..8a1283e83 100644 --- a/src/command/use_.rs +++ b/src/command/use_.rs @@ -6,6 +6,7 @@ use semver::VersionReq; use notion_core::serial::version::parse_requirements; use notion_core::session::{ActivityKind, Session}; +use notion_core::catalog::{parse_node_version, parse_yarn_version}; use notion_fail::{ExitCode, Fallible, NotionFail}; use Notion; @@ -65,8 +66,14 @@ Options: }: Args, ) -> Fallible { match &arg_tool[..] { - "node" => Ok(Use::Node(parse_requirements(&arg_version)?)), - "yarn" => Ok(Use::Yarn(parse_requirements(&arg_version)?)), + "node" => { + let node_version = parse_node_version(arg_version)?; + Ok(Use::Node(parse_requirements(&node_version)?)) + }, + "yarn" => { + let yarn_version = parse_yarn_version(arg_version)?; + Ok(Use::Yarn(parse_requirements(&yarn_version)?)) + }, ref tool => Ok(Use::Other { name: tool.to_string(), version: parse_requirements(&arg_version)?,