From 8cd20a5adf774e82d35c0b0c1b7524b8db0aed0f Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Fri, 6 Feb 2026 15:12:44 +0100 Subject: [PATCH 1/5] implement new get patterns in zypp-agama to be able to filter user patterns later --- rust/zypp-agama/src/lib.rs | 43 ++++++++- .../zypp-agama-sys/c-layer/README.md | 1 + .../zypp-agama-sys/c-layer/include/lib.h | 31 ++++++- .../zypp-agama/zypp-agama-sys/c-layer/lib.cxx | 90 ++++++++++++++----- .../zypp-agama/zypp-agama-sys/src/bindings.rs | 51 +++++++++++ 5 files changed, 191 insertions(+), 25 deletions(-) diff --git a/rust/zypp-agama/src/lib.rs b/rust/zypp-agama/src/lib.rs index 22674b6164..e38c048926 100644 --- a/rust/zypp-agama/src/lib.rs +++ b/rust/zypp-agama/src/lib.rs @@ -6,7 +6,7 @@ use std::{ use errors::ZyppResult; use zypp_agama_sys::{ - get_patterns_info, PatternNames, ProgressCallback, ProgressData, Status, ZyppProgressCallback, + PatternNames, ProgressCallback, ProgressData, Status, ZyppProgressCallback, get_patterns, get_patterns_info }; pub mod errors; @@ -60,6 +60,19 @@ pub struct PatternInfo { pub selected: ResolvableSelected, } +// TODO: should we add also e.g. serd serializers here? +#[derive(Debug)] +pub struct Pattern { + pub name: String, + pub category: String, + pub icon: String, + pub description: String, + pub summary: String, + pub order: String, + pub repo_alias: String, + pub selected: ResolvableSelected, +} + // TODO: is there better way how to use type from ProgressCallback binding type? unsafe extern "C" fn zypp_progress_callback( zypp_data: ProgressData, @@ -265,6 +278,34 @@ impl Zypp { } } + pub fn list_patterns(&self) -> ZyppResult> { + unsafe { + let mut status: Status = Status::default(); + let status_ptr = &mut status as *mut _; + + let patterns = get_patterns(self.ptr, status_ptr); + helpers::status_to_result_void(status)?; + + let mut r_patterns = Vec::with_capacity(patterns.size as usize); + for i in 0..patterns.size as usize { + let c_pattern = *(patterns.list.add(i)); + let r_pattern = Pattern { + name: string_from_ptr(c_pattern.name), + category: string_from_ptr(c_pattern.category), + icon: string_from_ptr(c_pattern.icon), + description: string_from_ptr(c_pattern.description), + summary: string_from_ptr(c_pattern.summary), + order: string_from_ptr(c_pattern.order), + repo_alias: string_from_ptr(c_pattern.repo_alias), + selected: c_pattern.selected.into(), + }; + r_patterns.push(r_pattern); + } + zypp_agama_sys::free_patterns(&patterns); + Ok(r_patterns) + } + } + pub fn patterns_info(&self, names: Vec<&str>) -> ZyppResult> { unsafe { let mut status: Status = Status::default(); diff --git a/rust/zypp-agama/zypp-agama-sys/c-layer/README.md b/rust/zypp-agama/zypp-agama-sys/c-layer/README.md index 78d4a15c26..6258088c53 100644 --- a/rust/zypp-agama/zypp-agama-sys/c-layer/README.md +++ b/rust/zypp-agama/zypp-agama-sys/c-layer/README.md @@ -24,4 +24,5 @@ that allows to call easily libzypp functionality from languages that have issue - if pointer provided by method is non-trivial ( usually struct ), then there have to be API call to free it. - if method gets any pointer, it is still owned by caller who is responsible for its deallocation. - if callback method receive any pointer, it is owned by library and library will deallocate it after callback finish. +- if a pointer is owned by the library (and should not be freed by the caller), it must be explicitly documented (e.g. `///< library owned`). - ideally C layer should only have runtime dependency on libzypp and libstdc++ diff --git a/rust/zypp-agama/zypp-agama-sys/c-layer/include/lib.h b/rust/zypp-agama/zypp-agama-sys/c-layer/include/lib.h index 4f7474e32a..184cea988a 100644 --- a/rust/zypp-agama/zypp-agama-sys/c-layer/include/lib.h +++ b/rust/zypp-agama/zypp-agama-sys/c-layer/include/lib.h @@ -152,13 +152,39 @@ void resolvable_reset_all(struct Zypp *_zypp) noexcept; /// @return count of packages unsigned packages_to_install(struct Zypp *_zypp) noexcept; +/// Representation of zypp::Pattern. +/// https://doc.opensuse.org/projects/libzypp/HEAD/classzypp_1_1Pattern.html +// Note: it will soon replace PatternInfo. It co-lives now as internmediate +// steps for performance reasons elements are NOT owned +struct Pattern { + const char *name; ///< owned + const char *category; ///< owned + const char *icon; ///< owned + const char *description; ///< owned + const char *summary; ///< owned + const char *order; ///< owned + const char *repo_alias; ///< owned + enum RESOLVABLE_SELECTED selected; +}; + +struct Patterns { + struct Pattern *list; ///< owned, *size* items + unsigned size; +}; + +/// Get Pattern details. +/// Unknown patterns are simply omitted from the result. Match by +/// PatternInfo.name, not by index. +struct Patterns get_patterns(struct Zypp *_zypp, + struct Status *status) noexcept; +void free_patterns(const struct Patterns *patterns) noexcept; + struct PatternNames { /// names of patterns const char *const *const names; /// size of names array unsigned size; }; - /// Info from zypp::Pattern. /// https://doc.opensuse.org/projects/libzypp/HEAD/classzypp_1_1Pattern.html struct PatternInfo { @@ -213,7 +239,8 @@ bool is_package_selected(struct Zypp *zypp, const char *tag, /// Runs solver /// @param zypp see \ref init_target -/// @param only_required if true, only required packages are installed (ignoring recommended packages) +/// @param only_required if true, only required packages are installed (ignoring +/// recommended packages) /// @param[out] status (will overwrite existing contents) /// @return true if solver pass and false if it found some dependency issues bool run_solver(struct Zypp *zypp, bool only_required, diff --git a/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx b/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx index 7d10a9fe07..652ae6e776 100644 --- a/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx +++ b/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx @@ -357,6 +357,73 @@ void resolvable_reset_all(struct Zypp *_zypp) noexcept { item.statusReset(); } +static RESOLVABLE_SELECTED +convert_selected(zypp::ui::Selectable::constPtr selectable) { + auto &status = selectable->theObj().status(); + if (status.isToBeInstalled()) { + switch (status.getTransactByValue()) { + case zypp::ResStatus::TransactByValue::USER: + return RESOLVABLE_SELECTED::USER_SELECTED; + case zypp::ResStatus::TransactByValue::APPL_HIGH: + case zypp::ResStatus::TransactByValue::APPL_LOW: + return RESOLVABLE_SELECTED::APPLICATION_SELECTED; + case zypp::ResStatus::TransactByValue::SOLVER: + return RESOLVABLE_SELECTED::SOLVER_SELECTED; + } + } else { + // distinguish between the "not selected" and "explicitly removed by user" + // states + if (status.getTransactByValue() == zypp::ResStatus::TransactByValue::USER) + return RESOLVABLE_SELECTED::USER_REMOVED; + else + return RESOLVABLE_SELECTED::NOT_SELECTED; + } + + return RESOLVABLE_SELECTED::NOT_SELECTED; +} + +struct Patterns get_patterns(struct Zypp *zypp, + struct Status *status) noexcept { + auto iterator = + zypp->zypp_pointer->poolProxy().byKind(zypp::ResKind::pattern); + + Patterns result = { + (struct Pattern *)malloc(iterator.size() * sizeof(Patterns)), + 0 // initialize with zero and increase after each successful add of + // pattern info + }; + + for (const auto iter : iterator) { + Pattern &pattern = result.list[result.size]; + auto zypp_pattern = iter->candidateAsKind(); + pattern.name = strdup(iter->name().c_str()); + pattern.category = strdup(zypp_pattern->category().c_str()); + pattern.description = strdup(zypp_pattern->description().c_str()); + pattern.icon = strdup(zypp_pattern->icon().c_str()); + pattern.summary = strdup(zypp_pattern->summary().c_str()); + pattern.order = strdup(zypp_pattern->order().c_str()); + pattern.repo_alias = strdup(zypp_pattern->repoInfo().alias().c_str()); + pattern.selected = convert_selected(iter.get()); + result.size++; + } + + STATUS_OK(status); + return result; +} + +void free_patterns(const struct Patterns *patterns) noexcept { + for (unsigned i = 0; i < patterns->size; ++i) { + free((void *)patterns->list[i].name); + free((void *)patterns->list[i].category); + free((void *)patterns->list[i].description); + free((void *)patterns->list[i].icon); + free((void *)patterns->list[i].summary); + free((void *)patterns->list[i].order); + free((void *)patterns->list[i].repo_alias); + } + free((void *)patterns->list); +} + struct PatternInfos get_patterns_info(struct Zypp *_zypp, struct PatternNames names, struct Status *status) noexcept { @@ -383,28 +450,7 @@ struct PatternInfos get_patterns_info(struct Zypp *_zypp, result.infos[i].icon = strdup(pattern->icon().c_str()); result.infos[i].summary = strdup(pattern->summary().c_str()); result.infos[i].order = strdup(pattern->order().c_str()); - auto &status = selectable->theObj().status(); - if (status.isToBeInstalled()) { - switch (status.getTransactByValue()) { - case zypp::ResStatus::TransactByValue::USER: - result.infos[i].selected = RESOLVABLE_SELECTED::USER_SELECTED; - break; - case zypp::ResStatus::TransactByValue::APPL_HIGH: - case zypp::ResStatus::TransactByValue::APPL_LOW: - result.infos[i].selected = RESOLVABLE_SELECTED::APPLICATION_SELECTED; - break; - case zypp::ResStatus::TransactByValue::SOLVER: - result.infos[i].selected = RESOLVABLE_SELECTED::SOLVER_SELECTED; - break; - } - } else { - // distinguish between the "not selected" and "explicitly removed by user" - // states - if (status.getTransactByValue() == zypp::ResStatus::TransactByValue::USER) - result.infos[i].selected = RESOLVABLE_SELECTED::USER_REMOVED; - else - result.infos[i].selected = RESOLVABLE_SELECTED::NOT_SELECTED; - } + result.infos[i].selected = convert_selected(selectable); result.size++; }; diff --git a/rust/zypp-agama/zypp-agama-sys/src/bindings.rs b/rust/zypp-agama/zypp-agama-sys/src/bindings.rs index 632f1ca615..aa05dde375 100644 --- a/rust/zypp-agama/zypp-agama-sys/src/bindings.rs +++ b/rust/zypp-agama/zypp-agama-sys/src/bindings.rs @@ -473,6 +473,54 @@ pub const RESOLVABLE_SELECTED_USER_SELECTED: RESOLVABLE_SELECTED = 3; #[doc = " explicitly removed by user"] pub const RESOLVABLE_SELECTED_USER_REMOVED: RESOLVABLE_SELECTED = 4; pub type RESOLVABLE_SELECTED = ::std::os::raw::c_uint; +#[doc = " Representation of zypp::Pattern.\n https://doc.opensuse.org/projects/libzypp/HEAD/classzypp_1_1Pattern.html"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Pattern { + #[doc = "< owned"] + pub name: *const ::std::os::raw::c_char, + #[doc = "< owned"] + pub category: *const ::std::os::raw::c_char, + #[doc = "< owned"] + pub icon: *const ::std::os::raw::c_char, + #[doc = "< owned"] + pub description: *const ::std::os::raw::c_char, + #[doc = "< owned"] + pub summary: *const ::std::os::raw::c_char, + #[doc = "< owned"] + pub order: *const ::std::os::raw::c_char, + #[doc = "< owned"] + pub repo_alias: *const ::std::os::raw::c_char, + pub selected: RESOLVABLE_SELECTED, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of Pattern"][::std::mem::size_of::() - 64usize]; + ["Alignment of Pattern"][::std::mem::align_of::() - 8usize]; + ["Offset of field: Pattern::name"][::std::mem::offset_of!(Pattern, name) - 0usize]; + ["Offset of field: Pattern::category"][::std::mem::offset_of!(Pattern, category) - 8usize]; + ["Offset of field: Pattern::icon"][::std::mem::offset_of!(Pattern, icon) - 16usize]; + ["Offset of field: Pattern::description"] + [::std::mem::offset_of!(Pattern, description) - 24usize]; + ["Offset of field: Pattern::summary"][::std::mem::offset_of!(Pattern, summary) - 32usize]; + ["Offset of field: Pattern::order"][::std::mem::offset_of!(Pattern, order) - 40usize]; + ["Offset of field: Pattern::repo_alias"][::std::mem::offset_of!(Pattern, repo_alias) - 48usize]; + ["Offset of field: Pattern::selected"][::std::mem::offset_of!(Pattern, selected) - 56usize]; +}; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Patterns { + #[doc = "< owned, *size* items"] + pub list: *mut Pattern, + pub size: ::std::os::raw::c_uint, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of Patterns"][::std::mem::size_of::() - 16usize]; + ["Alignment of Patterns"][::std::mem::align_of::() - 8usize]; + ["Offset of field: Patterns::list"][::std::mem::offset_of!(Patterns, list) - 0usize]; + ["Offset of field: Patterns::size"][::std::mem::offset_of!(Patterns, size) - 8usize]; +}; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct PatternNames { @@ -629,6 +677,9 @@ unsafe extern "C" { #[doc = " @brief Amount of packages selected for installation\n @param _zypp see \\ref init_target\n @return count of packages"] pub fn packages_to_install(_zypp: *mut Zypp) -> ::std::os::raw::c_uint; #[doc = " Get Pattern details.\n Unknown patterns are simply omitted from the result. Match by\n PatternInfo.name, not by index."] + pub fn get_patterns(_zypp: *mut Zypp, status: *mut Status) -> Patterns; + pub fn free_patterns(patterns: *const Patterns); + #[doc = " Get Pattern details.\n Unknown patterns are simply omitted from the result. Match by\n PatternInfo.name, not by index."] pub fn get_patterns_info( _zypp: *mut Zypp, names: PatternNames, From 995fb717c33f1b8ae7995c2f55886188f8945bcb Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Fri, 6 Feb 2026 16:08:57 +0100 Subject: [PATCH 2/5] Add addons patterns Decision for current implementation is to include all patterns from repositories that is not added by products or from base product scc repositories --- rust/agama-software/src/model/registration.rs | 6 ++ rust/agama-software/src/zypp_server.rs | 62 ++++++++++++++----- rust/zypp-agama/src/lib.rs | 3 +- .../zypp-agama/zypp-agama-sys/src/bindings.rs | 2 +- 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/rust/agama-software/src/model/registration.rs b/rust/agama-software/src/model/registration.rs index 941fd038c2..d6a07c5041 100644 --- a/rust/agama-software/src/model/registration.rs +++ b/rust/agama-software/src/model/registration.rs @@ -67,6 +67,8 @@ pub struct Registration { // `to_registration_info` function. connect_params: ConnectParams, creds: Credentials, + /// list of services for each registered product + /// the first service is always the one for base product registration services: Vec, // Holds the addons information because the status cannot be obtained from SCC yet // (e.g., whether and add-on is register or its registration code). @@ -266,6 +268,10 @@ impl Registration { fn find_registered_addon(&self, id: &str) -> Option<&Addon> { self.addons.iter().find(|a| a.id == id) } + + pub fn base_product_service_name(&self) -> Option { + self.services.first().map(|s| s.name.clone()) + } } /// A builder for a [Registration] object. diff --git a/rust/agama-software/src/zypp_server.rs b/rust/agama-software/src/zypp_server.rs index 81160a7643..0db01e61a1 100644 --- a/rust/agama-software/src/zypp_server.rs +++ b/rust/agama-software/src/zypp_server.rs @@ -641,14 +641,54 @@ impl ZyppServer { Ok(()) } - fn patterns(&self, product: &ProductSpec, zypp: &zypp_agama::Zypp) -> ZyppResult> { - let pattern_names: Vec<_> = product + fn user_patterns<'a>( + &self, + product: &'a ProductSpec, + zypp: &zypp_agama::Zypp, + ) -> ZyppResult + use<'a, '_>> { + let product_pattern_names: Vec<_> = product .software .user_patterns .iter() .map(|p| p.name()) .collect(); + let repositories = zypp.list_repositories()?; + + let zypp_patterns = zypp.list_patterns()?; + + Ok(zypp_patterns.into_iter().filter(move |p| { + // lets explain here logic for user selectable patterns + // if pattern is listed in product pattern names then use it + // else include only patterns coming from repository that is + // NOT predefined as agama-* one neither from repository + // added by base product registration + if product_pattern_names.contains(&p.name.as_str()) { + true + } else { + let repository = repositories.iter().find(|r| r.alias == p.repo_alias); + let Some(repository) = repository else { + tracing::error!( + "Unknown alias {} found in pattern selectable.", + p.repo_alias + ); + return false; + }; + if repository.alias.starts_with("agama-") { + false + } else { + if let RegistrationStatus::Registered(registration) = &self.registration { + repository.service.is_some() + && repository.service != registration.base_product_service_name() + } else { + false + } + } + } + })) + } + + fn patterns(&self, product: &ProductSpec, zypp: &zypp_agama::Zypp) -> ZyppResult> { let preselected_patterns: Vec<_> = product .software .user_patterns @@ -657,10 +697,8 @@ impl ZyppServer { .map(|p| p.name()) .collect(); - let patterns = zypp.patterns_info(pattern_names)?; - - let patterns = patterns - .into_iter() + let patterns = self + .user_patterns(product, zypp)? .map(|p| { let preselected = preselected_patterns.contains(&p.name.as_str()); Pattern { @@ -765,18 +803,12 @@ impl ZyppServer { product: &ProductSpec, zypp: &zypp_agama::Zypp, ) -> Result, ZyppServerError> { - let pattern_names = product - .software - .user_patterns - .iter() - .map(|p| p.name()) - .collect(); - let patterns_info = zypp.patterns_info(pattern_names); - patterns_info + self.user_patterns(product, zypp) .map(|patterns| { patterns - .iter() .map(|pattern| { + // NOTE: cannot be implemented From as one lives in agama-utils which does not depend on zypp-agama and should not + // and other way it also does not make sense let tag = match pattern.selected { zypp_agama::ResolvableSelected::Installation => SelectedBy::Auto, zypp_agama::ResolvableSelected::Not => SelectedBy::None, diff --git a/rust/zypp-agama/src/lib.rs b/rust/zypp-agama/src/lib.rs index e38c048926..ac674a5b53 100644 --- a/rust/zypp-agama/src/lib.rs +++ b/rust/zypp-agama/src/lib.rs @@ -6,7 +6,8 @@ use std::{ use errors::ZyppResult; use zypp_agama_sys::{ - PatternNames, ProgressCallback, ProgressData, Status, ZyppProgressCallback, get_patterns, get_patterns_info + get_patterns, get_patterns_info, PatternNames, ProgressCallback, ProgressData, Status, + ZyppProgressCallback, }; pub mod errors; diff --git a/rust/zypp-agama/zypp-agama-sys/src/bindings.rs b/rust/zypp-agama/zypp-agama-sys/src/bindings.rs index aa05dde375..fb5aa788d3 100644 --- a/rust/zypp-agama/zypp-agama-sys/src/bindings.rs +++ b/rust/zypp-agama/zypp-agama-sys/src/bindings.rs @@ -705,7 +705,7 @@ unsafe extern "C" { tag: *const ::std::os::raw::c_char, status: *mut Status, ) -> bool; - #[doc = " Runs solver\n @param zypp see \\ref init_target\n @param only_required if true, only required packages are installed (ignoring recommended packages)\n @param[out] status (will overwrite existing contents)\n @return true if solver pass and false if it found some dependency issues"] + #[doc = " Runs solver\n @param zypp see \\ref init_target\n @param only_required if true, only required packages are installed (ignoring\n recommended packages)\n @param[out] status (will overwrite existing contents)\n @return true if solver pass and false if it found some dependency issues"] pub fn run_solver(zypp: *mut Zypp, only_required: bool, status: *mut Status) -> bool; #[doc = " the last call that will free all pointers to zypp holded by agama"] pub fn free_zypp(zypp: *mut Zypp); From 5d21a6c5f2c490b9c3fa580a4fbca41639c9015a Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Mon, 9 Feb 2026 14:03:02 +0100 Subject: [PATCH 3/5] add working C code together with bench and example --- rust/Cargo.lock | 210 +++++++++++++++++- rust/zypp-agama/Cargo.toml | 8 + rust/zypp-agama/benches/list_patterns.rs | 52 +++++ rust/zypp-agama/examples/list_patterns.rs | 48 ++++ rust/zypp-agama/src/callbacks.rs | 3 + rust/zypp-agama/zypp-agama-sys/Cargo.toml | 2 +- .../zypp-agama/zypp-agama-sys/c-layer/lib.cxx | 12 +- 7 files changed, 321 insertions(+), 14 deletions(-) create mode 100644 rust/zypp-agama/benches/list_patterns.rs create mode 100644 rust/zypp-agama/examples/list_patterns.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 2dc5c9f2c0..14fb1bbd04 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -495,6 +495,15 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -510,6 +519,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstream" version = "0.6.18" @@ -1135,6 +1150,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.2.20" @@ -1201,6 +1222,33 @@ dependencies = [ "phf_codegen", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cidr" version = "0.3.1" @@ -1429,6 +1477,60 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "criterion" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" +dependencies = [ + "alloca", + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools 0.13.0", + "num-traits", + "oorandom", + "page_size", + "plotters", + "rayon", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" +dependencies = [ + "cast", + "itertools 0.13.0", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -2091,6 +2193,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy 0.8.39", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -2640,6 +2753,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -3255,6 +3377,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + [[package]] name = "openssl" version = "0.10.75" @@ -3325,6 +3453,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "pam" version = "0.8.0" @@ -3566,6 +3704,34 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "polling" version = "3.7.4" @@ -3608,7 +3774,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.25", + "zerocopy 0.8.39", ] [[package]] @@ -3767,6 +3933,26 @@ dependencies = [ "getrandom 0.3.2", ] +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.5.11" @@ -4698,6 +4884,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tokio" version = "1.49.0" @@ -5852,11 +6048,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ - "zerocopy-derive 0.8.25", + "zerocopy-derive 0.8.39", ] [[package]] @@ -5872,9 +6068,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", @@ -5981,6 +6177,8 @@ dependencies = [ name = "zypp-agama" version = "0.1.0" dependencies = [ + "criterion", + "glob", "tracing", "url", "zypp-agama-sys", diff --git a/rust/zypp-agama/Cargo.toml b/rust/zypp-agama/Cargo.toml index 3a0d9d51ec..21b1d8d032 100644 --- a/rust/zypp-agama/Cargo.toml +++ b/rust/zypp-agama/Cargo.toml @@ -7,3 +7,11 @@ edition = "2021" zypp-agama-sys = { path="./zypp-agama-sys" } url = "2.5.7" tracing = "0.1.41" + +[dev-dependencies] +criterion = { version = "0.8", features = ["html_reports"] } +glob = "0.3.1" + +[[bench]] +name = "list_patterns" +harness = false diff --git a/rust/zypp-agama/benches/list_patterns.rs b/rust/zypp-agama/benches/list_patterns.rs new file mode 100644 index 0000000000..28a65e92e2 --- /dev/null +++ b/rust/zypp-agama/benches/list_patterns.rs @@ -0,0 +1,52 @@ +use std::fs; + +use criterion::{criterion_group, criterion_main, Criterion}; + +fn criterion_benchmark(c: &mut Criterion) { + let _ = fs::remove_dir_all("/tmp/zypp"); + fs::create_dir_all("/tmp/zypp").unwrap(); + let zypp = zypp_agama::Zypp::init_target( + "/tmp/zypp", + zypp_agama::callbacks::empty_init_target_progress, + ) + .unwrap(); + + const GPG_KEYS: &str = "/usr/lib/rpm/gnupg/keys/gpg-*"; + for file in glob::glob(GPG_KEYS).unwrap() { + match file { + Ok(file) => { + if let Err(e) = zypp.import_gpg_key(&file.to_string_lossy()) { + tracing::error!("Failed to import GPG key: {}", e); + } + } + Err(e) => { + tracing::error!("Could not read GPG key file: {}", e); + } + } + } + + zypp.add_repository( + "tw", + "https://download.opensuse.org/tumbleweed/repo/oss/", + |_, _| true, + ) + .unwrap(); + zypp.refresh_repository( + "tw", + &zypp_agama::callbacks::download_progress::EmptyCallback, + &mut zypp_agama::callbacks::security::EmptyCallback, + ) + .unwrap(); + zypp.load_source( + zypp_agama::callbacks::empty_progress, + &mut zypp_agama::callbacks::security::EmptyCallback, + ) + .unwrap(); + + c.bench_function("list patterns", |b| { + b.iter(|| zypp.list_patterns().unwrap()) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/rust/zypp-agama/examples/list_patterns.rs b/rust/zypp-agama/examples/list_patterns.rs new file mode 100644 index 0000000000..816b2abc0d --- /dev/null +++ b/rust/zypp-agama/examples/list_patterns.rs @@ -0,0 +1,48 @@ +use std::fs; + +pub fn main() { + let _ = fs::remove_dir_all("/tmp/zypp"); + fs::create_dir_all("/tmp/zypp").unwrap(); + let zypp = zypp_agama::Zypp::init_target( + "/tmp/zypp", + zypp_agama::callbacks::empty_init_target_progress, + ) + .unwrap(); + + const GPG_KEYS: &str = "/usr/lib/rpm/gnupg/keys/gpg-*"; + for file in glob::glob(GPG_KEYS).unwrap() { + match file { + Ok(file) => { + if let Err(e) = zypp.import_gpg_key(&file.to_string_lossy()) { + tracing::error!("Failed to import GPG key: {}", e); + } + } + Err(e) => { + tracing::error!("Could not read GPG key file: {}", e); + } + } + } + + zypp.add_repository( + "tw", + "https://download.opensuse.org/tumbleweed/repo/oss/", + |_, _| true, + ) + .unwrap(); + zypp.refresh_repository( + "tw", + &zypp_agama::callbacks::download_progress::EmptyCallback, + &mut zypp_agama::callbacks::security::EmptyCallback, + ) + .unwrap(); + zypp.load_source( + zypp_agama::callbacks::empty_progress, + &mut zypp_agama::callbacks::security::EmptyCallback, + ) + .unwrap(); + zypp.create_repo_cache("tw", zypp_agama::callbacks::empty_progress) + .unwrap(); + zypp.load_repo_cache("tw").unwrap(); + println!("TW patterns:"); + println!("{:?}", zypp.list_patterns().unwrap()); +} diff --git a/rust/zypp-agama/src/callbacks.rs b/rust/zypp-agama/src/callbacks.rs index 96a4871b80..22f4cdb48c 100644 --- a/rust/zypp-agama/src/callbacks.rs +++ b/rust/zypp-agama/src/callbacks.rs @@ -10,6 +10,9 @@ pub fn empty_progress(_value: i64, _text: String) -> bool { true } +// empty init target callback +pub fn empty_init_target_progress(_text: String, _stage: u32, _total: u32) {} + pub enum ProblemResponse { RETRY, ABORT, diff --git a/rust/zypp-agama/zypp-agama-sys/Cargo.toml b/rust/zypp-agama/zypp-agama-sys/Cargo.toml index 1f485acc8c..c19f1cb7cd 100644 --- a/rust/zypp-agama/zypp-agama-sys/Cargo.toml +++ b/rust/zypp-agama/zypp-agama-sys/Cargo.toml @@ -7,4 +7,4 @@ edition.workspace = true tracing = "0.1.41" [build-dependencies] -bindgen = { version= "0.72.1", features = ["runtime"] } +bindgen = { version= "0.72.1", features = ["runtime"] } \ No newline at end of file diff --git a/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx b/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx index 652ae6e776..a0649f3fb5 100644 --- a/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx +++ b/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx @@ -357,9 +357,7 @@ void resolvable_reset_all(struct Zypp *_zypp) noexcept { item.statusReset(); } -static RESOLVABLE_SELECTED -convert_selected(zypp::ui::Selectable::constPtr selectable) { - auto &status = selectable->theObj().status(); +static RESOLVABLE_SELECTED convert_selected(zypp::ResStatus status) { if (status.isToBeInstalled()) { switch (status.getTransactByValue()) { case zypp::ResStatus::TransactByValue::USER: @@ -385,10 +383,10 @@ convert_selected(zypp::ui::Selectable::constPtr selectable) { struct Patterns get_patterns(struct Zypp *zypp, struct Status *status) noexcept { auto iterator = - zypp->zypp_pointer->poolProxy().byKind(zypp::ResKind::pattern); + zypp->zypp_pointer->pool().proxy().byKind(zypp::ResKind::pattern); Patterns result = { - (struct Pattern *)malloc(iterator.size() * sizeof(Patterns)), + (struct Pattern *)malloc(iterator.size() * sizeof(Pattern)), 0 // initialize with zero and increase after each successful add of // pattern info }; @@ -403,7 +401,7 @@ struct Patterns get_patterns(struct Zypp *zypp, pattern.summary = strdup(zypp_pattern->summary().c_str()); pattern.order = strdup(zypp_pattern->order().c_str()); pattern.repo_alias = strdup(zypp_pattern->repoInfo().alias().c_str()); - pattern.selected = convert_selected(iter.get()); + pattern.selected = convert_selected(iter->theObj().status()); result.size++; } @@ -450,7 +448,7 @@ struct PatternInfos get_patterns_info(struct Zypp *_zypp, result.infos[i].icon = strdup(pattern->icon().c_str()); result.infos[i].summary = strdup(pattern->summary().c_str()); result.infos[i].order = strdup(pattern->order().c_str()); - result.infos[i].selected = convert_selected(selectable); + result.infos[i].selected = convert_selected(selectable->theObj().status()); result.size++; }; From 280828bb5399285d6bf68c6b8efd37419bc370d9 Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Mon, 9 Feb 2026 19:59:09 +0100 Subject: [PATCH 4/5] remove patterns_info which is replaced by get_patterns --- rust/zypp-agama/src/lib.rs | 38 +--------- .../zypp-agama-sys/c-layer/include/lib.h | 33 --------- .../zypp-agama/zypp-agama-sys/c-layer/lib.cxx | 46 ------------ .../zypp-agama/zypp-agama-sys/src/bindings.rs | 70 ------------------- 4 files changed, 1 insertion(+), 186 deletions(-) diff --git a/rust/zypp-agama/src/lib.rs b/rust/zypp-agama/src/lib.rs index ac674a5b53..2114efecde 100644 --- a/rust/zypp-agama/src/lib.rs +++ b/rust/zypp-agama/src/lib.rs @@ -6,7 +6,7 @@ use std::{ use errors::ZyppResult; use zypp_agama_sys::{ - get_patterns, get_patterns_info, PatternNames, ProgressCallback, ProgressData, Status, + get_patterns, ProgressCallback, ProgressData, Status, ZyppProgressCallback, }; @@ -307,42 +307,6 @@ impl Zypp { } } - pub fn patterns_info(&self, names: Vec<&str>) -> ZyppResult> { - unsafe { - let mut status: Status = Status::default(); - let status_ptr = &mut status as *mut _; - let c_names: Vec = names - .iter() - .map(|s| CString::new(*s).expect("CString must not contain internal NUL")) - .collect(); - let c_ptr_names: Vec<*const c_char> = - c_names.iter().map(|c| c.as_c_str().as_ptr()).collect(); - let pattern_names = PatternNames { - size: names.len() as u32, - names: c_ptr_names.as_ptr(), - }; - let infos = get_patterns_info(self.ptr, pattern_names, status_ptr); - helpers::status_to_result_void(status)?; - - let mut r_infos = Vec::with_capacity(infos.size as usize); - for i in 0..infos.size as usize { - let c_info = *(infos.infos.add(i)); - let r_info = PatternInfo { - name: string_from_ptr(c_info.name), - category: string_from_ptr(c_info.category), - icon: string_from_ptr(c_info.icon), - description: string_from_ptr(c_info.description), - summary: string_from_ptr(c_info.summary), - order: string_from_ptr(c_info.order), - selected: c_info.selected.into(), - }; - r_infos.push(r_info); - } - zypp_agama_sys::free_pattern_infos(&infos); - Ok(r_infos) - } - } - pub fn import_gpg_key(&self, file_path: &str) -> ZyppResult<()> { unsafe { let mut status: Status = Status::default(); diff --git a/rust/zypp-agama/zypp-agama-sys/c-layer/include/lib.h b/rust/zypp-agama/zypp-agama-sys/c-layer/include/lib.h index 184cea988a..bcc2a73954 100644 --- a/rust/zypp-agama/zypp-agama-sys/c-layer/include/lib.h +++ b/rust/zypp-agama/zypp-agama-sys/c-layer/include/lib.h @@ -154,8 +154,6 @@ unsigned packages_to_install(struct Zypp *_zypp) noexcept; /// Representation of zypp::Pattern. /// https://doc.opensuse.org/projects/libzypp/HEAD/classzypp_1_1Pattern.html -// Note: it will soon replace PatternInfo. It co-lives now as internmediate -// steps for performance reasons elements are NOT owned struct Pattern { const char *name; ///< owned const char *category; ///< owned @@ -179,37 +177,6 @@ struct Patterns get_patterns(struct Zypp *_zypp, struct Status *status) noexcept; void free_patterns(const struct Patterns *patterns) noexcept; -struct PatternNames { - /// names of patterns - const char *const *const names; - /// size of names array - unsigned size; -}; -/// Info from zypp::Pattern. -/// https://doc.opensuse.org/projects/libzypp/HEAD/classzypp_1_1Pattern.html -struct PatternInfo { - char *name; ///< owned - char *category; ///< owned - char *icon; ///< owned - char *description; ///< owned - char *summary; ///< owned - char *order; ///< owned - enum RESOLVABLE_SELECTED selected; -}; - -struct PatternInfos { - struct PatternInfo *infos; ///< owned, *size* items - unsigned size; -}; - -/// Get Pattern details. -/// Unknown patterns are simply omitted from the result. Match by -/// PatternInfo.name, not by index. -struct PatternInfos get_patterns_info(struct Zypp *_zypp, - struct PatternNames names, - struct Status *status) noexcept; -void free_pattern_infos(const struct PatternInfos *infos) noexcept; - void import_gpg_key(struct Zypp *zypp, const char *const pathname, struct Status *status) noexcept; diff --git a/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx b/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx index a0649f3fb5..fa1d41f2b7 100644 --- a/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx +++ b/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx @@ -422,52 +422,6 @@ void free_patterns(const struct Patterns *patterns) noexcept { free((void *)patterns->list); } -struct PatternInfos get_patterns_info(struct Zypp *_zypp, - struct PatternNames names, - struct Status *status) noexcept { - PatternInfos result = { - (struct PatternInfo *)malloc(names.size * sizeof(PatternInfo)), - 0 // initialize with zero and increase after each successful add of - // pattern info - }; - - for (unsigned j = 0; j < names.size; ++j) { - zypp::ui::Selectable::constPtr selectable = - zypp::ui::Selectable::get(zypp::ResKind::pattern, names.names[j]); - // we do not find any pattern - if (!selectable.get()) - continue; - - // we know here that we get only patterns - zypp::Pattern::constPtr pattern = - zypp::asKind(selectable->theObj().resolvable()); - unsigned i = result.size; - result.infos[i].name = strdup(pattern->name().c_str()); - result.infos[i].category = strdup(pattern->category().c_str()); - result.infos[i].description = strdup(pattern->description().c_str()); - result.infos[i].icon = strdup(pattern->icon().c_str()); - result.infos[i].summary = strdup(pattern->summary().c_str()); - result.infos[i].order = strdup(pattern->order().c_str()); - result.infos[i].selected = convert_selected(selectable->theObj().status()); - result.size++; - }; - - STATUS_OK(status); - return result; -} - -void free_pattern_infos(const struct PatternInfos *infos) noexcept { - for (unsigned i = 0; i < infos->size; ++i) { - free(infos->infos[i].name); - free(infos->infos[i].category); - free(infos->infos[i].icon); - free(infos->infos[i].description); - free(infos->infos[i].summary); - free(infos->infos[i].order); - } - free(infos->infos); -} - bool run_solver(struct Zypp *zypp, bool only_required, struct Status *status) noexcept { try { diff --git a/rust/zypp-agama/zypp-agama-sys/src/bindings.rs b/rust/zypp-agama/zypp-agama-sys/src/bindings.rs index fb5aa788d3..e6d72e45e8 100644 --- a/rust/zypp-agama/zypp-agama-sys/src/bindings.rs +++ b/rust/zypp-agama/zypp-agama-sys/src/bindings.rs @@ -523,69 +523,6 @@ const _: () = { }; #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct PatternNames { - #[doc = " names of patterns"] - pub names: *const *const ::std::os::raw::c_char, - #[doc = " size of names array"] - pub size: ::std::os::raw::c_uint, -} -#[allow(clippy::unnecessary_operation, clippy::identity_op)] -const _: () = { - ["Size of PatternNames"][::std::mem::size_of::() - 16usize]; - ["Alignment of PatternNames"][::std::mem::align_of::() - 8usize]; - ["Offset of field: PatternNames::names"][::std::mem::offset_of!(PatternNames, names) - 0usize]; - ["Offset of field: PatternNames::size"][::std::mem::offset_of!(PatternNames, size) - 8usize]; -}; -#[doc = " Info from zypp::Pattern.\n https://doc.opensuse.org/projects/libzypp/HEAD/classzypp_1_1Pattern.html"] -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct PatternInfo { - #[doc = "< owned"] - pub name: *mut ::std::os::raw::c_char, - #[doc = "< owned"] - pub category: *mut ::std::os::raw::c_char, - #[doc = "< owned"] - pub icon: *mut ::std::os::raw::c_char, - #[doc = "< owned"] - pub description: *mut ::std::os::raw::c_char, - #[doc = "< owned"] - pub summary: *mut ::std::os::raw::c_char, - #[doc = "< owned"] - pub order: *mut ::std::os::raw::c_char, - pub selected: RESOLVABLE_SELECTED, -} -#[allow(clippy::unnecessary_operation, clippy::identity_op)] -const _: () = { - ["Size of PatternInfo"][::std::mem::size_of::() - 56usize]; - ["Alignment of PatternInfo"][::std::mem::align_of::() - 8usize]; - ["Offset of field: PatternInfo::name"][::std::mem::offset_of!(PatternInfo, name) - 0usize]; - ["Offset of field: PatternInfo::category"] - [::std::mem::offset_of!(PatternInfo, category) - 8usize]; - ["Offset of field: PatternInfo::icon"][::std::mem::offset_of!(PatternInfo, icon) - 16usize]; - ["Offset of field: PatternInfo::description"] - [::std::mem::offset_of!(PatternInfo, description) - 24usize]; - ["Offset of field: PatternInfo::summary"] - [::std::mem::offset_of!(PatternInfo, summary) - 32usize]; - ["Offset of field: PatternInfo::order"][::std::mem::offset_of!(PatternInfo, order) - 40usize]; - ["Offset of field: PatternInfo::selected"] - [::std::mem::offset_of!(PatternInfo, selected) - 48usize]; -}; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct PatternInfos { - #[doc = "< owned, *size* items"] - pub infos: *mut PatternInfo, - pub size: ::std::os::raw::c_uint, -} -#[allow(clippy::unnecessary_operation, clippy::identity_op)] -const _: () = { - ["Size of PatternInfos"][::std::mem::size_of::() - 16usize]; - ["Alignment of PatternInfos"][::std::mem::align_of::() - 8usize]; - ["Offset of field: PatternInfos::infos"][::std::mem::offset_of!(PatternInfos, infos) - 0usize]; - ["Offset of field: PatternInfos::size"][::std::mem::offset_of!(PatternInfos, size) - 8usize]; -}; -#[repr(C)] -#[derive(Debug, Copy, Clone)] pub struct Repository { #[doc = "<"] pub enabled: bool, @@ -679,13 +616,6 @@ unsafe extern "C" { #[doc = " Get Pattern details.\n Unknown patterns are simply omitted from the result. Match by\n PatternInfo.name, not by index."] pub fn get_patterns(_zypp: *mut Zypp, status: *mut Status) -> Patterns; pub fn free_patterns(patterns: *const Patterns); - #[doc = " Get Pattern details.\n Unknown patterns are simply omitted from the result. Match by\n PatternInfo.name, not by index."] - pub fn get_patterns_info( - _zypp: *mut Zypp, - names: PatternNames, - status: *mut Status, - ) -> PatternInfos; - pub fn free_pattern_infos(infos: *const PatternInfos); pub fn import_gpg_key( zypp: *mut Zypp, pathname: *const ::std::os::raw::c_char, From 0f4f0c4d5b644d798afb6d3c1cc8b6297c74fa7f Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Tue, 10 Feb 2026 09:25:35 +0100 Subject: [PATCH 5/5] simplify a bit code --- rust/agama-software/src/zypp_server.rs | 40 ++++++++++++-------------- rust/zypp-agama/src/lib.rs | 5 +--- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/rust/agama-software/src/zypp_server.rs b/rust/agama-software/src/zypp_server.rs index 0db01e61a1..d2f481402b 100644 --- a/rust/agama-software/src/zypp_server.rs +++ b/rust/agama-software/src/zypp_server.rs @@ -652,9 +652,7 @@ impl ZyppServer { .iter() .map(|p| p.name()) .collect(); - let repositories = zypp.list_repositories()?; - let zypp_patterns = zypp.list_patterns()?; Ok(zypp_patterns.into_iter().filter(move |p| { @@ -664,26 +662,26 @@ impl ZyppServer { // NOT predefined as agama-* one neither from repository // added by base product registration if product_pattern_names.contains(&p.name.as_str()) { - true + return true; + } + + let repository = repositories.iter().find(|r| r.alias == p.repo_alias); + let Some(repository) = repository else { + tracing::error!( + "Unknown alias {} found in pattern selectable.", + p.repo_alias + ); + return false; + }; + if repository.alias.starts_with("agama-") { + return false; + } + + if let RegistrationStatus::Registered(registration) = &self.registration { + repository.service.is_some() + && repository.service != registration.base_product_service_name() } else { - let repository = repositories.iter().find(|r| r.alias == p.repo_alias); - let Some(repository) = repository else { - tracing::error!( - "Unknown alias {} found in pattern selectable.", - p.repo_alias - ); - return false; - }; - if repository.alias.starts_with("agama-") { - false - } else { - if let RegistrationStatus::Registered(registration) = &self.registration { - repository.service.is_some() - && repository.service != registration.base_product_service_name() - } else { - false - } - } + false } })) } diff --git a/rust/zypp-agama/src/lib.rs b/rust/zypp-agama/src/lib.rs index 2114efecde..6ff0c8c013 100644 --- a/rust/zypp-agama/src/lib.rs +++ b/rust/zypp-agama/src/lib.rs @@ -5,10 +5,7 @@ use std::{ }; use errors::ZyppResult; -use zypp_agama_sys::{ - get_patterns, ProgressCallback, ProgressData, Status, - ZyppProgressCallback, -}; +use zypp_agama_sys::{get_patterns, ProgressCallback, ProgressData, Status, ZyppProgressCallback}; pub mod errors; pub use errors::ZyppError;