Skip to main content

zoi_cli/cmd/
sync.rs

1//! Logic for the `sync` command.
2//!
3//! This module provides commands for syncing package databases from registries,
4//! and managing the list of configured registries.
5
6use anyhow::Result;
7use colored::Colorize;
8
9use crate::cli::SetupScope;
10use crate::pkg;
11
12/// Run the sync command to update package databases.
13///
14/// # Errors
15///
16/// Returns an error if the sync process fails.
17pub 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
45/// Run a project-local sync command.
46///
47/// # Errors
48///
49/// Returns an error if the project-local sync process fails.
50pub 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
70/// Set the default registry URL or use a pre-defined keyword.
71///
72/// # Errors
73///
74/// Returns an error if the configuration cannot be updated.
75pub fn set_registry(url_or_keyword: &str) -> Result<()> {
76    let url_storage;
77    let url = match url_or_keyword {
78        "default" => {
79            url_storage = pkg::config::get_default_registry();
80            &url_storage
81        }
82        "gitlab" => "https://gitlab.com/zillowe/zillwen/zusty/zoidberg.git",
83        "github" => "https://github.com/zillowe/zoidberg.git",
84        "codeberg" => "https://codeberg.org/zillowe/zoidberg.git",
85        _ => url_or_keyword
86    };
87
88    pkg::config::set_default_registry(url)?;
89    let url_cyan = url.cyan();
90    println!("Default registry set to: {url_cyan}");
91    println!("The new registry will be used the next time you run 'zoi sync'");
92    Ok(())
93}
94
95/// Add a new registry URL to the list of tracked registries.
96///
97/// # Errors
98///
99/// Returns an error if the directory path is invalid or if the configuration
100/// cannot be updated.
101pub fn add_registry(url: &str) -> Result<()> {
102    let mut final_url = url.to_string();
103    let path = std::path::Path::new(url);
104    if path.is_dir() {
105        final_url = std::fs::canonicalize(path)?.to_string_lossy().to_string();
106    }
107
108    pkg::config::add_added_registry(&final_url)?;
109    let url_cyan = final_url.cyan();
110    println!("Registry '{url_cyan}' added.");
111    println!("It will be synced on the next 'zoi sync' run.");
112    Ok(())
113}
114
115/// Remove a registry by its handle or URL.
116///
117/// # Errors
118///
119/// Returns an error if the registry cannot be removed from the configuration.
120pub fn remove_registry(handle: &str) -> Result<()> {
121    pkg::config::remove_added_registry(handle)?;
122    let handle_cyan = handle.cyan();
123    println!("Registry '{handle_cyan}' removed.");
124    Ok(())
125}
126
127/// List all configured and tracked registries.
128///
129/// # Errors
130///
131/// Returns an error if the configuration cannot be read.
132pub fn list_registries() -> Result<()> {
133    let config = crate::pkg::config::read_config()?;
134    let db_root = crate::pkg::resolve::get_db_root()?;
135
136    println!("{} Configured Registries", "::".bold().blue());
137
138    if let Some(default) = config.default_registry {
139        let handle = &default.handle;
140        let mut desc = String::new();
141        if !handle.is_empty() {
142            let repo_path = db_root.join(handle);
143            if let Ok(repo_config) =
144                crate::pkg::config::read_repo_config(&repo_path)
145            {
146                let repo_desc = &repo_config.description;
147                desc = format!(" - {repo_desc}");
148            }
149        }
150        let handle_str = if handle.is_empty() {
151            "<not synced>".italic().to_string()
152        } else {
153            handle.cyan().to_string()
154        };
155        let url_cyan = default.url.cyan();
156        let url = &default.url;
157        println!("[Set] {handle_str}: {url}{url_cyan}");
158        if !desc.is_empty() {
159            let desc_dimmed = desc.dimmed();
160            println!("      {desc_dimmed}");
161        }
162    } else {
163        println!("[Set]: <not set>");
164    }
165
166    if !config.added_registries.is_empty() {
167        println!();
168        for reg in config.added_registries {
169            let handle = &reg.handle;
170            let mut desc = String::new();
171            if !handle.is_empty() {
172                let repo_path = db_root.join(handle);
173                if let Ok(repo_config) =
174                    crate::pkg::config::read_repo_config(&repo_path)
175                {
176                    let repo_desc = &repo_config.description;
177                    desc = format!(" - {repo_desc}");
178                }
179            }
180            let handle_str = if handle.is_empty() {
181                "<not synced>".italic().to_string()
182            } else {
183                handle.cyan().to_string()
184            };
185            let url_cyan = reg.url.cyan();
186            let url = &reg.url;
187            println!("[Add] {handle_str}: {url}{url_cyan}");
188            if !desc.is_empty() {
189                let desc_dimmed = desc.dimmed();
190                println!("      {desc_dimmed}");
191            }
192        }
193    }
194    Ok(())
195}