use std::collections::HashMap;
use clap::Args;
use itertools::Itertools;
use lux_lib::{
config::Config, lockfile::LocalPackage, lua_version::LuaVersion, package::PackageVersion,
progress::MultiProgress, remote_package_db::RemotePackageDB, workspace::Workspace,
};
use miette::{IntoDiagnostic, Result};
use text_trees::{FormatCharacters, StringTreeNode, TreeFormatting};
use crate::{args::OutputFormat, workspace::sync_dependencies_if_locked};
#[derive(Args)]
pub struct Outdated {
#[arg(long, default_value = "text", value_enum, ignore_case = true)]
output_format: OutputFormat,
}
pub async fn outdated(outdated_data: Outdated, config: Config) -> Result<()> {
let progress = MultiProgress::new(&config);
let bar = progress.map(MultiProgress::new_bar);
let workspace = Workspace::current()?;
let tree = match &workspace {
Some(project) => {
sync_dependencies_if_locked(project, MultiProgress::new_arc(&config), &config).await?;
project.tree(&config)?
}
None => {
let lua_version = LuaVersion::from(&config)?.clone();
config.user_tree(lua_version)?
}
};
let package_db = RemotePackageDB::from_config(&config, &bar).await?;
bar.map(|b| b.set_message("🔎 Checking for outdated rocks...".to_string()));
let rock_list = tree.as_rock_list()?;
let rock_list = rock_list
.iter()
.map(|rock| {
rock.to_package()
.has_update(&package_db)
.map(|mb_version| mb_version.map(|version| (rock, version)))
})
.filter_map_ok(|mb_tuple| mb_tuple)
.try_collect::<_, Vec<(&LocalPackage, PackageVersion)>, _>()?;
let rock_list = rock_list
.iter()
.sorted_by_key(|(rock, _)| rock.name().to_owned())
.into_group_map_by(|(rock, _)| rock.name().to_owned());
bar.map(|b| b.finish_and_clear());
match outdated_data.output_format {
OutputFormat::Json => {
let jsonified_rock_list = rock_list
.iter()
.map(|(key, values)| {
(
key,
values
.iter()
.map(|(k, v)| (k.version().to_string(), v.to_string()))
.collect::<HashMap<_, _>>(),
)
})
.collect::<HashMap<_, _>>();
println!(
"{}",
serde_json::to_string(&jsonified_rock_list).into_diagnostic()?
);
}
OutputFormat::Text => {
let formatting = TreeFormatting::dir_tree(FormatCharacters::box_chars());
for (rock_name, updates) in rock_list {
let mut tree = StringTreeNode::new(rock_name.to_string());
for (rock, latest_version) in updates {
tree.push(format!("{} => {}", rock.version(), latest_version));
}
println!(
"{}",
tree.to_string_with_format(&formatting).into_diagnostic()?
);
}
}
}
Ok(())
}