chub_cli/commands/
bundle.rs1use std::path::PathBuf;
2
3use clap::{Args, Subcommand};
4use owo_colors::OwoColorize;
5
6use chub_core::team::bundles;
7
8use crate::output;
9
10#[derive(Args)]
11pub struct BundleArgs {
12 #[command(subcommand)]
13 command: BundleCommand,
14}
15
16#[derive(Subcommand)]
17pub enum BundleCommand {
18 Create(BundleCreateArgs),
20 Install(BundleInstallArgs),
22 List,
24}
25
26#[derive(Args)]
27pub struct BundleCreateArgs {
28 name: String,
30 #[arg(long)]
32 description: Option<String>,
33 #[arg(long)]
35 author: Option<String>,
36 #[arg(long)]
38 entries: String,
39 #[arg(long)]
41 notes: Option<String>,
42}
43
44#[derive(Args)]
45pub struct BundleInstallArgs {
46 name: String,
48}
49
50pub fn run(args: BundleArgs, json: bool) {
51 match args.command {
52 BundleCommand::Create(create_args) => run_create(create_args, json),
53 BundleCommand::Install(install_args) => run_install(install_args, json),
54 BundleCommand::List => run_list(json),
55 }
56}
57
58fn run_create(args: BundleCreateArgs, json: bool) {
59 let entries: Vec<String> = args
60 .entries
61 .split(',')
62 .map(|s| s.trim().to_string())
63 .filter(|s| !s.is_empty())
64 .collect();
65
66 match bundles::create_bundle(
67 &args.name,
68 args.description.as_deref(),
69 args.author.as_deref(),
70 entries,
71 args.notes.as_deref(),
72 ) {
73 Ok(path) => {
74 if json {
75 println!(
76 "{}",
77 serde_json::json!({
78 "status": "created",
79 "path": path.display().to_string(),
80 })
81 );
82 } else {
83 output::success(&format!("Bundle created: {}", path.display()));
84 }
85 }
86 Err(e) => {
87 output::error(&e.to_string(), json);
88 std::process::exit(1);
89 }
90 }
91}
92
93fn run_install(args: BundleInstallArgs, json: bool) {
94 let bundle = if PathBuf::from(&args.name).exists() {
96 bundles::load_bundle(&PathBuf::from(&args.name))
97 } else {
98 bundles::load_bundle_by_name(&args.name)
99 };
100
101 match bundle {
102 Ok(b) => {
103 let name = b.name.clone();
104 match bundles::install_bundle(&b) {
105 Ok(pinned) => {
106 if json {
107 println!(
108 "{}",
109 serde_json::json!({
110 "status": "installed",
111 "bundle": name,
112 "pinned": pinned,
113 })
114 );
115 } else {
116 output::success(&format!(
117 "Installed bundle \"{}\": pinned {} entries.",
118 name.bold(),
119 pinned.len()
120 ));
121 for id in &pinned {
122 eprintln!(" + {}", id);
123 }
124 }
125 }
126 Err(e) => {
127 output::error(&e.to_string(), json);
128 std::process::exit(1);
129 }
130 }
131 }
132 Err(e) => {
133 output::error(&e.to_string(), json);
134 std::process::exit(1);
135 }
136 }
137}
138
139fn run_list(json: bool) {
140 let bundles_list = bundles::list_bundles();
141
142 if json {
143 println!(
144 "{}",
145 serde_json::to_string_pretty(&serde_json::json!({
146 "bundles": bundles_list,
147 "total": bundles_list.len(),
148 }))
149 .unwrap_or_default()
150 );
151 } else {
152 if bundles_list.is_empty() {
153 eprintln!("{}", "No bundles found in .chub/bundles/".dimmed());
154 return;
155 }
156 eprintln!("{}", format!("{} bundles:\n", bundles_list.len()).bold());
157 for b in &bundles_list {
158 eprintln!(" {}", b.name.bold());
159 if let Some(ref desc) = b.description {
160 eprintln!(" {}", desc.dimmed());
161 }
162 eprintln!(" Entries: {}", b.entries.join(", "));
163 }
164 }
165}