chub_cli/commands/
profile.rs1use clap::{Args, Subcommand};
2use owo_colors::OwoColorize;
3
4use chub_core::team::profiles;
5
6use crate::output;
7
8#[derive(Args)]
9pub struct ProfileArgs {
10 #[command(subcommand)]
11 command: ProfileCommand,
12}
13
14#[derive(Subcommand)]
15pub enum ProfileCommand {
16 Use(ProfileUseArgs),
18 List,
20 Current,
22}
23
24#[derive(Args)]
25pub struct ProfileUseArgs {
26 name: String,
28}
29
30pub fn run(args: ProfileArgs, json: bool) {
31 match args.command {
32 ProfileCommand::Use(use_args) => run_use(use_args, json),
33 ProfileCommand::List => run_list(json),
34 ProfileCommand::Current => run_current(json),
35 }
36}
37
38fn run_use(args: ProfileUseArgs, json: bool) {
39 let name = if args.name == "none" || args.name == "off" || args.name == "clear" {
40 None
41 } else {
42 Some(args.name.as_str())
43 };
44
45 match profiles::set_active_profile(name) {
46 Ok(()) => {
47 if json {
48 println!(
49 "{}",
50 serde_json::json!({
51 "status": "ok",
52 "profile": name,
53 })
54 );
55 } else if let Some(n) = name {
56 output::success(&format!("Profile set to: {}", n.bold()));
57 if let Ok(resolved) = profiles::resolve_profile(n) {
59 if !resolved.pins.is_empty() {
60 eprintln!(" Pins: {}", resolved.pins.join(", ").dimmed());
61 }
62 if !resolved.context.is_empty() {
63 eprintln!(" Context: {}", resolved.context.join(", ").dimmed());
64 }
65 if !resolved.rules.is_empty() {
66 eprintln!(" Rules: {} rule(s)", resolved.rules.len());
67 }
68 }
69 } else {
70 output::success("Profile cleared.");
71 }
72 }
73 Err(e) => {
74 output::error(&e.to_string(), json);
75 std::process::exit(1);
76 }
77 }
78}
79
80fn run_list(json: bool) {
81 let profiles = profiles::list_profiles();
82 let active = profiles::get_active_profile();
83
84 if json {
85 let items: Vec<serde_json::Value> = profiles
86 .iter()
87 .map(|(name, desc)| {
88 serde_json::json!({
89 "name": name,
90 "description": desc,
91 "active": active.as_deref() == Some(name.as_str()),
92 })
93 })
94 .collect();
95 println!(
96 "{}",
97 serde_json::to_string_pretty(&serde_json::json!({
98 "profiles": items,
99 "active": active,
100 }))
101 .unwrap_or_default()
102 );
103 } else {
104 if profiles.is_empty() {
105 eprintln!(
106 "{}",
107 "No profiles found. Create profiles in .chub/profiles/".dimmed()
108 );
109 return;
110 }
111 eprintln!("{}", "Available profiles:\n".bold());
112 for (name, desc) in &profiles {
113 let marker = if active.as_deref() == Some(name.as_str()) {
114 " *".green().to_string()
115 } else {
116 String::new()
117 };
118 eprintln!(" {}{}", name.bold(), marker);
119 if let Some(d) = desc {
120 eprintln!(" {}", d.dimmed());
121 }
122 }
123 }
124}
125
126fn run_current(json: bool) {
127 let active = profiles::get_active_profile();
128
129 if json {
130 println!("{}", serde_json::json!({ "profile": active }));
131 } else {
132 match active {
133 Some(name) => {
134 eprintln!("Active profile: {}", name.bold());
135 if let Ok(resolved) = profiles::resolve_profile(&name) {
136 if let Some(desc) = &resolved.description {
137 eprintln!(" {}", desc.dimmed());
138 }
139 if !resolved.pins.is_empty() {
140 eprintln!(" Pins: {}", resolved.pins.join(", "));
141 }
142 if !resolved.context.is_empty() {
143 eprintln!(" Context: {}", resolved.context.join(", "));
144 }
145 eprintln!(" Rules: {}", resolved.rules.len());
146 }
147 }
148 None => eprintln!("{}", "No active profile.".dimmed()),
149 }
150 }
151}