use super::{Command, Config};
use crate::release;
use crate::version;
use crate::version::Local;
use crate::version::Version;
use clap;
use colored::Colorize;
use itertools::Itertools;
use thiserror::Error;
#[derive(clap::Parser, Debug)]
pub struct ListRemote {
version: Option<Version>,
#[clap(
long = "latest-patch",
visible_alias = "lp",
help = "List latest patch release (avairable only if patch number is NOT specified)"
)]
only_latest_patch: bool,
}
#[derive(Error, Debug)]
pub enum Error {
#[error(transparent)]
FailedFetchRelease(#[from] release::FetchError),
}
impl Command for ListRemote {
type Error = Error;
fn run(&self, config: &Config) -> Result<(), Error> {
let query_versions = match &self.version {
Some(version) => {
if self.only_latest_patch && version.patch_version().is_some() {
println!(
"{}: '--latest-patch' is available only if patch number is NOT specified: {}",
"warning".yellow().bold(),
version
);
}
vec![*version]
}
None => {
vec![
Version::from_major(3),
Version::from_major(4),
Version::from_major(5),
Version::from_major(7),
Version::from_major(8),
]
}
};
let installed_versions = version::installed(config).collect_vec();
let current_version = Local::current(config);
for query_version in query_versions {
let releases = release::fetch_all(query_version)?;
let remote_versions = releases.keys();
let remote_versions = if self.only_latest_patch {
filter_latest_patch(remote_versions).collect_vec()
} else {
remote_versions.collect_vec()
};
for &remote_version in remote_versions {
let installed = installed_versions.contains(&remote_version);
let remote_version = Local::Installed(remote_version);
let used = Some(&remote_version) == current_version.as_ref();
println!("{}", remote_version.to_string_by(installed, used))
}
}
Ok(())
}
}
fn filter_latest_patch<'a, I>(versions: I) -> impl Iterator<Item = &'a Version>
where
I: Iterator<Item = &'a Version> + DoubleEndedIterator,
{
let mut latest_patch: Option<&'a Version> = None;
let mut latest_patches = versions
.rev()
.filter_map(|version| {
if latest_patch.is_none()
|| latest_patch.unwrap().minor_version() != version.minor_version()
{
latest_patch.replace(version)
} else {
None
}
})
.collect::<Vec<_>>();
latest_patches.push(latest_patch.unwrap());
latest_patches.into_iter().rev()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn version_not_specified() {
let base_dir = tempfile::tempdir().unwrap();
let config = Config::default().with_base_dir(base_dir);
let cmd = ListRemote {
version: None,
only_latest_patch: false,
};
assert!(cmd.run(&config).is_ok());
}
#[test]
fn version_specified() {
let base_dir = tempfile::tempdir().unwrap();
let config = Config::default().with_base_dir(base_dir);
let cmd = ListRemote {
version: Some("7.2".parse().unwrap()),
only_latest_patch: false,
};
assert!(cmd.run(&config).is_ok());
}
}