phpup/commands/
list_remote.rs1use super::{Command, Config};
2use crate::release;
3use crate::version;
4use crate::version::Local;
5use crate::version::Version;
6use clap;
7use colored::Colorize;
8use itertools::Itertools;
9use thiserror::Error;
10
11#[derive(clap::Parser, Debug)]
12pub struct ListRemote {
13 version: Option<Version>,
14 #[clap(
15 long = "latest-patch",
16 visible_alias = "lp",
17 help = "List latest patch release (avairable only if patch number is NOT specified)"
18 )]
19 only_latest_patch: bool,
20}
21
22#[derive(Error, Debug)]
23pub enum Error {
24 #[error(transparent)]
25 FailedFetchRelease(#[from] release::FetchError),
26}
27
28impl Command for ListRemote {
29 type Error = Error;
30
31 fn run(&self, config: &Config) -> Result<(), Error> {
32 let query_versions = match &self.version {
33 Some(version) => {
34 if self.only_latest_patch && version.patch_version().is_some() {
35 println!(
36 "{}: '--latest-patch' is available only if patch number is NOT specified: {}",
37 "warning".yellow().bold(),
38 version
39 );
40 }
41 vec![*version]
42 }
43 None => {
44 vec![
45 Version::from_major(3),
46 Version::from_major(4),
47 Version::from_major(5),
48 Version::from_major(7),
49 Version::from_major(8),
50 ]
51 }
52 };
53
54 let installed_versions = version::installed(config).collect_vec();
55 let current_version = Local::current(config);
56
57 for query_version in query_versions {
58 let releases = release::fetch_all(query_version)?;
59 let remote_versions = releases.keys();
60
61 let remote_versions = if self.only_latest_patch {
62 filter_latest_patch(remote_versions).collect_vec()
63 } else {
64 remote_versions.collect_vec()
65 };
66
67 for &remote_version in remote_versions {
68 let installed = installed_versions.contains(&remote_version);
69 let remote_version = Local::Installed(remote_version);
70 let used = Some(&remote_version) == current_version.as_ref();
71 println!("{}", remote_version.to_string_by(installed, used))
72 }
73 }
74 Ok(())
75 }
76}
77
78fn filter_latest_patch<'a, I>(versions: I) -> impl Iterator<Item = &'a Version>
79where
80 I: Iterator<Item = &'a Version> + DoubleEndedIterator,
81{
82 let mut latest_patch: Option<&'a Version> = None;
83 let mut latest_patches = versions
84 .rev()
85 .filter_map(|version| {
86 if latest_patch.is_none()
87 || latest_patch.unwrap().minor_version() != version.minor_version()
88 {
89 latest_patch.replace(version)
90 } else {
91 None
92 }
93 })
94 .collect::<Vec<_>>();
95 latest_patches.push(latest_patch.unwrap());
96 latest_patches.into_iter().rev()
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn version_not_specified() {
105 let base_dir = tempfile::tempdir().unwrap();
106 let config = Config::default().with_base_dir(base_dir);
107 let cmd = ListRemote {
108 version: None,
109 only_latest_patch: false,
110 };
111 assert!(cmd.run(&config).is_ok());
112 }
113 #[test]
114 fn version_specified() {
115 let base_dir = tempfile::tempdir().unwrap();
116 let config = Config::default().with_base_dir(base_dir);
117 let cmd = ListRemote {
118 version: Some("7.2".parse().unwrap()),
119 only_latest_patch: false,
120 };
121 assert!(cmd.run(&config).is_ok());
122 }
123}
124
125