seaplane_cli/cli/cmds/flight/
delete.rs1use clap::{ArgMatches, Command};
2
3use crate::{
4 cli::{
5 errors,
6 validator::{validate_flight_name, validate_name_id},
7 CliCommand,
8 },
9 context::Ctx,
10 error::{CliErrorKind, Result},
11};
12
13#[derive(Copy, Clone, Debug)]
14pub struct SeaplaneFlightDelete;
15
16impl SeaplaneFlightDelete {
17 pub fn command() -> Command {
18 let validator = |s: &str| validate_name_id(validate_flight_name, s);
19 Command::new("delete")
22 .visible_aliases(["del", "remove", "rm"])
23 .about("Delete a local Flight Plan")
24 .arg(arg!(flight required =["NAME|ID"])
25 .value_parser(validator)
26 .help("The name or ID of the Flight Plan to remove, must be unambiguous"))
27 .arg(arg!(--force -('f'))
28 .help("Delete this Flight Plan even if referenced by a local Formation Plan, or deletes ALL Flight Plan referenced by the name or ID even if ambiguous"))
29 .arg(arg!(--all -('a'))
30 .help("Delete all matching Flight Plans even when the name or ID is ambiguous"))
31 }
32}
33
34impl CliCommand for SeaplaneFlightDelete {
35 fn run(&self, ctx: &mut Ctx) -> Result<()> {
36 if ctx.args.stateless {
37 cli_eprint!(@Red, "error: ");
38 cli_eprint!("'");
39 cli_eprint!(@Yellow, "--stateless");
40 cli_eprint!("' cannot be used with '");
41 cli_eprint!(@Yellow, "seaplane flight delete");
42 cli_eprintln!("'");
43 cli_eprintln!("(hint: 'seaplane flight delete' only modifies local plans)");
44 cli_eprint!("(hint: you may want 'seaplane ");
45 cli_eprint!(@Green, "formation ");
46 cli_eprintln!("delete' instead)");
47 std::process::exit(1);
48 }
49
50 let indices = if ctx.args.all {
52 ctx.db
53 .flights
54 .indices_of_left_matches(ctx.args.name_id.as_ref().unwrap())
55 } else {
56 ctx.db
57 .flights
58 .indices_of_matches(ctx.args.name_id.as_ref().unwrap())
59 };
60
61 match indices.len() {
62 0 => errors::no_matching_item(ctx.args.name_id.clone().unwrap(), false, ctx.args.all)?,
63 1 => (),
64 _ => {
65 if !(ctx.args.all || ctx.args.force) {
66 errors::ambiguous_item(ctx.args.name_id.clone().unwrap(), true)?;
67 }
68 }
69 }
70
71 let flights_in_use: Vec<String> = ctx
73 .db
74 .flights
75 .iter()
76 .enumerate()
77 .filter(|(i, _)| indices.contains(i))
78 .filter_map(|(_, flight)| {
79 if ctx.db.formations.has_flight(flight.model.name()) {
80 Some(flight.model.name().to_owned())
81 } else {
82 None
83 }
84 })
85 .collect();
86 if !flights_in_use.is_empty() {
88 if !ctx.args.force {
89 return Err(CliErrorKind::FlightsInUse(flights_in_use).into_err());
90 }
91 for flight in flights_in_use {
93 ctx.db.formations.remove_flight(&flight);
94 }
97 ctx.persist_formations()?;
98 }
99
100 ctx.db
102 .flights
103 .remove_indices(&indices)
104 .iter()
105 .for_each(|flight| {
106 cli_println!("Deleted local Flight Plan {}", &flight.id.to_string());
107 });
108
109 ctx.persist_flights()?;
110
111 if !ctx.internal_run {
112 cli_println!(
113 "\nSuccessfully removed {} item{}",
114 indices.len(),
115 if indices.len() > 1 { "s" } else { "" }
116 );
117 }
118 Ok(())
119 }
120
121 fn update_ctx(&self, matches: &ArgMatches, ctx: &mut Ctx) -> Result<()> {
122 ctx.args.force = matches.get_flag("force");
123 ctx.args.all = matches.get_flag("all");
124 ctx.args.name_id = matches.get_one::<String>("flight").map(ToOwned::to_owned);
125 Ok(())
126 }
127}