1use anyhow::Result;
7use colored::Colorize;
8
9use crate::cli::SetupScope;
10use crate::pkg;
11
12pub fn run(
18 verbose: bool,
19 fallback: bool,
20 no_pm: bool,
21 force: bool,
22 scope: Option<SetupScope>
23) -> Result<()> {
24 println!("{} Syncing package databases...", "::".bold().blue());
25
26 if force {
27 println!(
28 "{} Force sync enabled, removing existing databases...",
29 "::".bold().yellow()
30 );
31 }
32
33 let pkg_scope = match scope {
34 Some(SetupScope::User) => Some(crate::pkg::types::Scope::User),
35 Some(SetupScope::System) => Some(crate::pkg::types::Scope::System),
36 None => None
37 };
38
39 pkg::sync::run(verbose, fallback, no_pm, force, pkg_scope)?;
40
41 println!("{}", "Sync complete.".green());
42 Ok(())
43}
44
45pub fn run_local(
51 verbose: bool,
52 fallback: bool,
53 force: bool,
54 frozen: bool
55) -> Result<()> {
56 if frozen {
57 crate::pkg::frozen::set_frozen(true);
58 }
59 println!(
60 "{} Syncing project-local package databases...",
61 "::".bold().blue()
62 );
63
64 pkg::sync::run_local(verbose, fallback, force, frozen)?;
65
66 println!("{}", "Local sync complete.".green());
67 Ok(())
68}
69
70fn warn_third_party(name: &str, registry_type: &str) {
72 if registry_type != "official" {
73 eprintln!(
74 "{} {} is a third-party registry. Use with caution and verify its \
75 authenticity before installing packages.",
76 "!".yellow().bold(),
77 name.cyan()
78 );
79 }
80}
81
82pub fn set_registry(url_or_handle: &str) -> Result<()> {
97 let handle_or_url_storage;
99 let handle_or_url = if url_or_handle == "default" {
100 handle_or_url_storage = pkg::builtin_registries::get_set()?
101 .map_or_else(|| "zoidberg".to_string(), |r| r.handle);
102 &handle_or_url_storage
103 } else {
104 url_or_handle
105 };
106
107 let builtin = pkg::builtin_registries::get(handle_or_url);
109
110 if let Some(ref reg) = builtin {
112 warn_third_party(®.name, ®.registry_type);
113 }
114
115 pkg::config::set_default_registry(handle_or_url)?;
119
120 let (display_handle, display_url) = match builtin {
122 Some(ref reg) => (reg.handle.as_str(), reg.git.as_str()),
123 None => (handle_or_url, handle_or_url)
124 };
125
126 println!("Default registry set to: {}", display_handle.cyan());
127 if !display_url.is_empty() && display_url != display_handle {
128 println!(" Git: {display_url}");
129 }
130 println!("The new registry will be used the next time you run 'zoi sync'");
131 Ok(())
132}
133
134pub fn add_registry(handle_or_url: &str) -> Result<()> {
146 let resolved_storage;
148 let handle_or_url = if handle_or_url == "default" {
149 resolved_storage = pkg::builtin_registries::get_set()?
150 .map_or_else(|| "zoidberg".to_string(), |r| r.handle);
151 &resolved_storage
152 } else {
153 handle_or_url
154 };
155
156 let path = std::path::Path::new(handle_or_url);
158 if path.is_dir() {
159 let final_url =
160 std::fs::canonicalize(path)?.to_string_lossy().to_string();
161 pkg::config::add_added_registry(&final_url)?;
162 let url_cyan = final_url.cyan();
163 println!("Registry '{url_cyan}' added.");
164 println!("It will be synced on the next 'zoi sync' run.");
165 return Ok(());
166 }
167
168 if let Some(reg) = pkg::builtin_registries::get(handle_or_url) {
170 warn_third_party(®.name, ®.registry_type);
171
172 pkg::config::add_added_registry(handle_or_url)?;
173 println!("Registry {} added.", reg.handle.cyan());
174 println!(" Name: {}", reg.name);
175 println!(" Git: {}", reg.git);
176 println!("It will be synced on the next 'zoi sync' run.");
177 return Ok(());
178 }
179
180 pkg::config::add_added_registry(handle_or_url)?;
182 let url_cyan = handle_or_url.cyan();
183 println!("Registry '{url_cyan}' added.");
184 println!("It will be synced on the next 'zoi sync' run.");
185 Ok(())
186}
187
188pub fn remove_registry(handle: &str) -> Result<()> {
194 pkg::config::remove_added_registry(handle)?;
195 let handle_cyan = handle.cyan();
196 println!("Registry '{handle_cyan}' removed.");
197 Ok(())
198}
199
200pub fn list_registries() -> Result<()> {
224 let config = pkg::config::read_config()?;
225 let all_builtins = pkg::builtin_registries::load_all();
226
227 let mut configured_handles: Vec<&str> = Vec::new();
229
230 println!("{} Configured Registries", "::".bold().blue());
231
232 if let Some(ref default) = config.default_registry {
234 let handle = &default.handle;
235 let display_name = default.name.as_deref().unwrap_or(handle);
236 let display_desc = default.description.as_deref();
237
238 configured_handles.push(handle.as_str());
239
240 let handle_str = if handle.is_empty() {
241 "<not synced>".italic().to_string()
242 } else {
243 handle.cyan().to_string()
244 };
245 println!("[Set] {handle_str}: {}", display_name.white());
246 if let Some(desc) = display_desc {
247 println!(" - {desc}");
248 }
249 println!(" - Git: {}", default.url);
250 } else {
251 println!("[Set] {} not set", "<none>".dimmed());
252 }
253
254 for reg in &config.added_registries {
256 let handle = ®.handle;
257 let display_name = reg.name.as_deref().unwrap_or(handle);
258 let display_desc = reg.description.as_deref();
259
260 configured_handles.push(handle.as_str());
261
262 let handle_str = if handle.is_empty() {
263 "<not synced>".italic().to_string()
264 } else {
265 handle.cyan().to_string()
266 };
267 println!();
268 println!("[Added] {handle_str}: {}", display_name.white());
269 if let Some(desc) = display_desc {
270 println!(" - {desc}");
271 }
272 println!(" - Git: {}", reg.url);
273 }
274
275 let unadded: Vec<_> = all_builtins
277 .iter()
278 .filter(|r| !configured_handles.contains(&r.handle.as_str()))
279 .collect();
280
281 if !unadded.is_empty() {
282 println!();
283 println!("{} Available Registries", "::".bold().blue());
284 for reg in unadded {
285 let handle_str = reg.handle.cyan().to_string();
286 println!("[Unadded] {handle_str}: {}", reg.name.white());
287 println!(" - {}", reg.description);
288 println!(" - Git: {}", reg.git);
289 }
290 }
291
292 Ok(())
293}