use clap::Args;
use console::style;
use topcoat_ui::manage::{self, AddAction, AddOptions, Package, Selection};
use super::PackageArg;
use crate::common::prompt;
#[derive(Args)]
pub(super) struct AddCommand {
#[arg(required_unless_present = "all", conflicts_with = "all")]
components: Vec<String>,
#[arg(short, long)]
all: bool,
#[arg(short, long)]
registry: Option<String>,
#[arg(short, long)]
overwrite: bool,
#[command(flatten)]
package: PackageArg,
}
impl AddCommand {
pub(super) fn run(self) {
if let Err(error) = self.run_inner() {
if error != prompt::CANCELLED {
eprintln!("{}", style(error).red());
}
std::process::exit(1);
}
}
fn run_inner(self) -> Result<(), String> {
let package = Package::locate(self.package.package)?;
let options = AddOptions {
selection: if self.all {
Selection::All
} else {
Selection::Named(self.components)
},
registry: self.registry,
overwrite: self.overwrite,
};
let mut confirm = confirm;
let entries = manage::add(&package, &options, &mut confirm)?;
let mut written = false;
for entry in entries {
let file = style(format!("({})", entry.file.display())).dim();
let name = style(entry.name).bold();
match entry.action {
AddAction::Installed => {
written = true;
println!(
"{} added {name} {file} from {}",
style("+").green(),
entry.registry
);
}
AddAction::Overwritten => {
written = true;
println!(
"{} updated {name} {file} from {}",
style("~").yellow(),
entry.registry
);
}
AddAction::Skipped => {
println!(
"{}",
style(format!("- skipped {name} {file}: already installed")).dim()
);
}
}
}
if !written {
println!("{} already up to date", style("✓").green());
}
Ok(())
}
}
fn confirm(question: &str) -> Result<bool, String> {
if !prompt::is_interactive() {
return Err(format!(
"{question} (no terminal to prompt on; pass --registry to choose)"
));
}
cliclack::confirm(question)
.initial_value(false)
.interact()
.map_err(|error| prompt::error(&error))
}