Skip to main content

pacsea/logic/repos/
mod.rs

1//! Third-party repository definitions (`repos.conf`) and results-filter wiring.
2//!
3//! Phase 1 parses TOML (user-defined `[[repo]]` rows only) and exposes maps for [`crate::logic::distro::repo_toggle_for`].
4//! Shipped repo recipes (disabled by default) live in `config/repos.conf` in the Pacsea tree.
5//! Phase 3 adds privileged apply via [`apply_plan`] and the Repositories modal (see `events/modals/repositories.rs`).
6
7mod apply_plan;
8mod config;
9mod foreign_overlap;
10mod modal_data;
11mod pacman_conf;
12
13pub use apply_plan::{
14    DEFAULT_DROPIN_PATH, DEFAULT_MAIN_PACMAN_PATH, MANAGED_DROPIN_FILE, PACMAN_MANAGED_BEGIN,
15    PACMAN_MANAGED_END, RepoApplyBundle, build_repo_apply_bundle, build_repo_key_refresh_bundle,
16    read_main_pacman_conf_text,
17};
18pub use config::{
19    RepoRow, ReposConfFile, build_dynamic_visibility, build_repo_name_to_filter_map,
20    canonical_results_filter_key, disable_repo_section_in_repos_conf_if_enabled,
21    load_repo_name_map_from_path, load_resolve_repos_from_str, repo_row_declares_apply_sources,
22    repos_conf_repo_names_for_index_sl, repos_conf_section_is_disabled_with_apply_sources,
23    row_is_enabled_for_repos_conf, save_repos_conf_file, toggle_repo_enabled_for_section_in_file,
24};
25pub use foreign_overlap::{
26    ForeignRepoOverlapAnalysis, ForeignRepoOverlapEntry, analyze_foreign_repo_overlap,
27    analyze_foreign_repo_overlap_with_qm_snapshot, build_foreign_to_sync_migrate_bundle,
28    compute_foreign_repo_overlap, list_foreign_packages, sync_repo_pkgnames,
29};
30pub use modal_data::{build_repositories_modal_fields, build_repositories_modal_fields_default};
31pub use pacman_conf::{PacmanConfScan, PacmanRepoPresence, scan_pacman_conf_path};
32
33use crate::state::AppState;
34use crate::theme::Settings;
35
36/// What: Populate `repo_results_filter_by_name` from the resolved config path, if any.
37///
38/// Inputs:
39/// - `app`: Application state to update.
40/// - `repos_path`: Optional path from [`crate::theme::resolve_repos_config_path`].
41///
42/// Output:
43/// - None (mutates `app`).
44///
45/// Details:
46/// - On missing path or parse errors, the map is cleared; failures are logged in the loader.
47pub fn load_repos_config_into_app(app: &mut AppState, repos_path: Option<std::path::PathBuf>) {
48    let Some(path) = repos_path else {
49        app.repo_results_filter_by_name.clear();
50        return;
51    };
52    app.repo_results_filter_by_name = load_repo_name_map_from_path(&path);
53}
54
55/// What: Recompute `results_filter_dynamic` from settings toggles and repo map.
56///
57/// Inputs:
58/// - `app`: Application state.
59/// - `prefs`: Loaded settings (includes `results_filter_toggles`).
60///
61/// Output:
62/// - None (mutates `app`).
63///
64/// Details:
65/// - Call after `apply_settings_to_app_state` field updates and after reloading `repos.conf`.
66pub fn refresh_dynamic_filters_in_app(app: &mut AppState, prefs: &Settings) {
67    app.results_filter_dynamic = build_dynamic_visibility(
68        &prefs.results_filter_toggles,
69        &app.repo_results_filter_by_name,
70    );
71}
72
73/// What: Update one dynamic results filter, persist `settings.conf`, and re-run filtering.
74///
75/// Inputs:
76/// - `app`: Application state.
77/// - `canonical_id`: Canonical `results_filter` token from `repos.conf`.
78/// - `new_visible`: Desired visibility in Results.
79///
80/// Output:
81/// - None.
82///
83/// Details:
84/// - Ignores unknown ids; uses [`crate::theme::save_results_filter_show_canonical`].
85pub fn persist_dynamic_filter_toggle_and_refresh(
86    app: &mut AppState,
87    canonical_id: &str,
88    new_visible: bool,
89) {
90    if !app.results_filter_dynamic.contains_key(canonical_id) {
91        return;
92    }
93    if let Some(v) = app.results_filter_dynamic.get_mut(canonical_id) {
94        *v = new_visible;
95    }
96    crate::theme::save_results_filter_show_canonical(canonical_id, new_visible);
97    crate::logic::apply_filters_and_sort_preserve_selection(app);
98}
99
100/// What: Turn every dynamic repo filter on or off together, persist, and re-filter.
101///
102/// Inputs:
103/// - `app`: Application state.
104/// - `new_visible`: Target visibility for all dynamic ids.
105///
106/// Output:
107/// - None.
108///
109/// Details:
110/// - No-op when the dynamic map is empty.
111pub fn persist_dynamic_filters_set_all(app: &mut AppState, new_visible: bool) {
112    if app.results_filter_dynamic.is_empty() {
113        return;
114    }
115    let ids: Vec<String> = app.results_filter_dynamic.keys().cloned().collect();
116    for id in &ids {
117        if let Some(v) = app.results_filter_dynamic.get_mut(id) {
118            *v = new_visible;
119        }
120        crate::theme::save_results_filter_show_canonical(id, new_visible);
121    }
122    crate::logic::apply_filters_and_sort_preserve_selection(app);
123}
124
125/// What: Whether Arch-style repository tooling (pacman paths, privileged apply) is available.
126///
127/// Inputs:
128/// - None.
129///
130/// Output:
131/// - `true` on Linux; `false` elsewhere.
132///
133/// Details:
134/// - Used to gate Repositories modal actions that assume a pacman-managed system.
135#[must_use]
136pub const fn repositories_linux_actions_supported() -> bool {
137    cfg!(target_os = "linux")
138}