greentic_bundle/cli/
remove.rs1use std::path::PathBuf;
2
3use anyhow::Result;
4use clap::{Args, Subcommand};
5use serde::Serialize;
6
7#[derive(Debug, Args)]
8pub struct RemoveArgs {
9 #[command(subcommand)]
10 pub command: RemoveCommand,
11}
12
13#[derive(Debug, Subcommand)]
14pub enum RemoveCommand {
15 #[command(about = "cli.remove.app_pack.about")]
16 AppPack(MutationArgs),
17 #[command(about = "cli.remove.extension_provider.about")]
18 ExtensionProvider(MutationArgs),
19}
20
21#[derive(Debug, Args)]
22pub struct MutationArgs {
23 #[arg(value_name = "ID")]
24 pub id: String,
25
26 #[arg(
27 long,
28 value_name = "PATH",
29 default_value = ".",
30 help = "cli.remove.root.option"
31 )]
32 pub root: PathBuf,
33
34 #[arg(long, default_value_t = false, help = "cli.option.dry_run")]
35 pub dry_run: bool,
36
37 #[arg(long, default_value_t = false, help = "cli.option.execute")]
38 pub execute: bool,
39}
40
41#[derive(Debug, Serialize)]
42struct MutationPreview {
43 root: String,
44 field: String,
45 action: String,
46 item: String,
47 execute: bool,
48 changed: bool,
49 current_values: Vec<String>,
50 next_values: Vec<String>,
51 expected_file_writes: Vec<String>,
52}
53
54pub fn run(args: RemoveArgs) -> Result<()> {
55 match args.command {
56 RemoveCommand::AppPack(args) => mutate(args, crate::project::ReferenceField::AppPack),
57 RemoveCommand::ExtensionProvider(args) => {
58 mutate(args, crate::project::ReferenceField::ExtensionProvider)
59 }
60 }
61}
62
63fn mutate(args: MutationArgs, field: crate::project::ReferenceField) -> Result<()> {
64 let mut workspace = crate::project::read_bundle_workspace(&args.root)?;
65 let current_values = workspace.references(field).to_vec();
66 workspace
67 .references_mut(field)
68 .retain(|value| value != &args.id);
69 workspace.canonicalize();
70 let next_values = workspace.references(field).to_vec();
71 let changed = current_values != next_values;
72 let execute = args.execute && !args.dry_run;
73 if execute {
74 crate::project::write_bundle_workspace(&args.root, &workspace)?;
75 crate::project::sync_lock_with_workspace(&args.root, &workspace)?;
76 crate::project::sync_project(&args.root)?;
77 }
78 let preview = MutationPreview {
79 root: args.root.display().to_string(),
80 field: field_name(field).to_string(),
81 action: "remove".to_string(),
82 item: args.id,
83 execute,
84 changed,
85 current_values,
86 next_values,
87 expected_file_writes: if execute {
88 vec![
89 args.root
90 .join(crate::project::WORKSPACE_ROOT_FILE)
91 .display()
92 .to_string(),
93 args.root
94 .join(crate::project::LOCK_FILE)
95 .display()
96 .to_string(),
97 args.root
98 .join("resolved/default.yaml")
99 .display()
100 .to_string(),
101 args.root
102 .join("state/resolved/default.yaml")
103 .display()
104 .to_string(),
105 ]
106 } else {
107 vec![
108 args.root
109 .join(crate::project::WORKSPACE_ROOT_FILE)
110 .display()
111 .to_string(),
112 ]
113 },
114 };
115 println!("{}", serde_json::to_string_pretty(&preview)?);
116 Ok(())
117}
118
119fn field_name(field: crate::project::ReferenceField) -> &'static str {
120 match field {
121 crate::project::ReferenceField::AppPack => "app_packs",
122 crate::project::ReferenceField::ExtensionProvider => "extension_providers",
123 }
124}