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 if pkg::sync::is_repo_yaml_url(handle_or_url)
185 && let Ok(registry) =
186 pkg::sync::resolve_registry_from_url(handle_or_url)
187 {
188 pkg::config::add_resolved_registry(registry.clone())?;
189
190 let handle = registry.handle.cyan();
191 println!("Registry {handle} added.");
192 if let Some(name) = ®istry.name {
193 println!(" Name: {name}");
194 }
195 if let Some(description) = ®istry.description {
196 println!(" Description: {description}");
197 }
198 println!(" Source: {}", registry.url.cyan());
199 println!("It will be synced on the next 'zoi sync' run.");
200 return Ok(());
201 }
202
203 pkg::config::add_added_registry(handle_or_url)?;
206 let url_cyan = handle_or_url.cyan();
207 println!("Registry '{url_cyan}' added.");
208 println!("It will be synced on the next 'zoi sync' run.");
209 Ok(())
210}
211
212pub fn remove_registry(handle: &str) -> Result<()> {
218 pkg::config::remove_added_registry(handle)?;
219 let handle_cyan = handle.cyan();
220 println!("Registry '{handle_cyan}' removed.");
221 Ok(())
222}
223
224pub fn list_registries() -> Result<()> {
248 let config = pkg::config::read_config()?;
249 let all_builtins = pkg::builtin_registries::load_all();
250
251 let mut configured_handles: Vec<&str> = Vec::new();
253
254 println!("{} Configured Registries", "::".bold().blue());
255
256 if let Some(ref default) = config.default_registry {
258 let handle = &default.handle;
259 let display_name = default.name.as_deref().unwrap_or(handle);
260 let display_desc = default.description.as_deref();
261
262 configured_handles.push(handle.as_str());
263
264 let handle_str = if handle.is_empty() {
265 "<not synced>".italic().to_string()
266 } else {
267 handle.cyan().to_string()
268 };
269 println!("[Set] {handle_str}: {}", display_name.white());
270 if let Some(desc) = display_desc {
271 println!(" - {desc}");
272 }
273 println!(" - Git: {}", default.url);
274 } else {
275 println!("[Set] {} not set", "<none>".dimmed());
276 }
277
278 for reg in &config.added_registries {
280 let handle = ®.handle;
281 let display_name = reg.name.as_deref().unwrap_or(handle);
282 let display_desc = reg.description.as_deref();
283
284 configured_handles.push(handle.as_str());
285
286 let handle_str = if handle.is_empty() {
287 "<not synced>".italic().to_string()
288 } else {
289 handle.cyan().to_string()
290 };
291 println!();
292 println!("[Added] {handle_str}: {}", display_name.white());
293 if let Some(desc) = display_desc {
294 println!(" - {desc}");
295 }
296 println!(" - Git: {}", reg.url);
297 }
298
299 let unadded: Vec<_> = all_builtins
301 .iter()
302 .filter(|r| !configured_handles.contains(&r.handle.as_str()))
303 .collect();
304
305 if !unadded.is_empty() {
306 println!();
307 println!("{} Available Registries", "::".bold().blue());
308 for reg in unadded {
309 let handle_str = reg.handle.cyan().to_string();
310 println!("[Unadded] {handle_str}: {}", reg.name.white());
311 println!(" - {}", reg.description);
312 println!(" - Git: {}", reg.git);
313 }
314 }
315
316 Ok(())
317}