mz_deploy/cli/commands/
profile.rs1use crate::cli::CliError;
29use crate::config::{ProfilesConfig, read_mzprofile, write_mzprofile};
30use crate::{info, log};
31use owo_colors::{OwoColorize, Stream, Style};
32use serde::Serialize;
33use std::fmt;
34use std::path::Path;
35
36#[derive(Serialize)]
38struct ProfileListing {
39 profiles: Vec<ProfileEntry>,
40
41 source: String,
42}
43
44#[derive(Serialize)]
45struct ProfileEntry {
46 name: String,
47 active: bool,
48}
49
50impl fmt::Display for ProfileListing {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 if self.profiles.is_empty() {
53 return write!(f, "No profiles found in {}", self.source);
54 }
55 let mut first = true;
56 for entry in &self.profiles {
57 if !first {
58 writeln!(f)?;
59 }
60 first = false;
61 if entry.active {
62 write!(
63 f,
64 " {} {}",
65 entry.name.if_supports_color(Stream::Stderr, |t| t.green()),
66 "(active)".if_supports_color(Stream::Stderr, |t| t.dimmed())
67 )?;
68 } else {
69 write!(f, " {}", entry.name)?;
70 }
71 }
72 Ok(())
73 }
74}
75
76pub fn list(
78 directory: &Path,
79 cli_profile: Option<&str>,
80 profiles_dir: Option<&Path>,
81) -> Result<(), CliError> {
82 let profiles_config = ProfilesConfig::load(profiles_dir)?;
83 let active = resolve_active(directory, cli_profile)?;
84 let names = profiles_config.profile_names();
85
86 let profiles = names
87 .iter()
88 .map(|name| ProfileEntry {
89 name: (*name).to_string(),
90 active: active.as_deref() == Some(*name),
91 })
92 .collect();
93
94 log::output(&ProfileListing {
95 profiles,
96 source: profiles_config.source_path().display().to_string(),
97 });
98 Ok(())
99}
100
101pub fn set(directory: &Path, profiles_dir: Option<&Path>, name: &str) -> Result<(), CliError> {
106 let profiles_config = ProfilesConfig::load(profiles_dir)?;
107 let _ = profiles_config.get_profile(name)?;
109
110 write_mzprofile(directory, name)?;
111
112 let check_style = Style::new().green().bold();
113 info!(
114 " {} default profile set to {}",
115 "✓".if_supports_color(Stream::Stderr, |t| check_style.style(t)),
116 name.if_supports_color(Stream::Stderr, |t| t.green()),
117 );
118 Ok(())
119}
120
121pub fn current(directory: &Path, cli_profile: Option<&str>) -> Result<(), CliError> {
123 if let Some(name) = cli_profile {
124 let source = if std::env::var_os("MZ_DEPLOY_PROFILE").is_some() {
128 "MZ_DEPLOY_PROFILE env var"
129 } else {
130 "--profile flag"
131 };
132 info!(
133 " {} ({})",
134 name.if_supports_color(Stream::Stderr, |t| t.green()),
135 source.if_supports_color(Stream::Stderr, |t| t.dimmed())
136 );
137 return Ok(());
138 }
139
140 match read_mzprofile(directory)? {
141 Some(name) => {
142 info!(
143 " {} ({})",
144 name.if_supports_color(Stream::Stderr, |t| t.green()),
145 "project default".if_supports_color(Stream::Stderr, |t| t.dimmed()),
146 );
147 }
148 None => {
149 info!(
150 " {} no profile selected — run {} to set one",
151 "⚠".if_supports_color(Stream::Stderr, |t| t.yellow()),
152 "mz-deploy profile set <name>".if_supports_color(Stream::Stderr, |t| t.cyan()),
153 );
154 }
155 }
156 Ok(())
157}
158
159fn resolve_active(directory: &Path, cli_profile: Option<&str>) -> Result<Option<String>, CliError> {
160 if let Some(p) = cli_profile {
161 return Ok(Some(p.to_string()));
162 }
163 Ok(read_mzprofile(directory)?)
164}