diff --git a/rust/agama-software/src/model/state.rs b/rust/agama-software/src/model/state.rs index 018f9d0290..184e26bde5 100644 --- a/rust/agama-software/src/model/state.rs +++ b/rust/agama-software/src/model/state.rs @@ -565,7 +565,7 @@ impl From for zypp_agama::ResolvableSelected { #[derive(Default, Debug)] pub struct SoftwareOptions { /// Install only required packages (not recommended ones). - only_required: bool, + pub only_required: bool, } #[derive(Clone, Debug)] diff --git a/rust/agama-software/src/zypp_server.rs b/rust/agama-software/src/zypp_server.rs index 363f8479aa..81160a7643 100644 --- a/rust/agama-software/src/zypp_server.rs +++ b/rust/agama-software/src/zypp_server.rs @@ -129,6 +129,7 @@ pub struct ZyppServer { install_dir: Utf8PathBuf, trusted_keys: Vec, unsigned_repos: Vec, + only_required: bool, } impl ZyppServer { @@ -148,6 +149,7 @@ impl ZyppServer { registration: Default::default(), trusted_keys: vec![], unsigned_repos: vec![], + only_required: false, }; // drop the returned JoinHandle: the thread will be detached @@ -438,8 +440,10 @@ impl ZyppServer { }; } + self.only_required = state.options.only_required; + tracing::info!("Install only required packages: {}", self.only_required); // run the solver to select the dependencies, ignore the errors, the solver runs again later - let _ = zypp.run_solver(); + let _ = zypp.run_solver(self.only_required); // unselect packages including the autoselected dependencies for (name, r#type, selection) in &state.resolvables.to_vec() { @@ -450,7 +454,7 @@ impl ZyppServer { } _ = progress.cast(progress::message::Finish::new(Scope::Software)); - match zypp.run_solver() { + match zypp.run_solver(self.only_required) { Ok(result) => println!("Solver result: {result}"), Err(error) => println!("Solver failed: {error}"), }; @@ -513,7 +517,8 @@ impl ZyppServer { return Ok(()); } let _ = self.registration_finish(); // TODO: move it outside of zypp server as it do not need zypp lock - let _ = self.modify_zypp_conf(); // TODO: move it outside of zypp server as it do not need zypp lock + + self.modify_zypp_conf(); if let Err(error) = self.modify_full_repo(zypp) { tracing::warn!("Failed to modify the full repository: {error}"); @@ -597,9 +602,16 @@ impl ZyppServer { Ok(()) } - fn modify_zypp_conf(&self) -> ZyppServerResult<()> { - // TODO: implement when requireOnly is implemented - Ok(()) + fn modify_zypp_conf(&self) { + // write only if different from default + if self.only_required { + let contents = "# Use only hard dependencies as configured in installer\nsolver.onlyRequires = true\n"; + let path = self.install_dir.join("etc/zypp/zypp.conf.d/installer.conf"); + let write_result = std::fs::write(path.as_path(), contents); + if write_result.is_err() { + tracing::error!("Failed to write {path}: {write_result:?}"); + } + } } fn system_info( diff --git a/rust/package/agama.changes b/rust/package/agama.changes index 64dee31eeb..fb3b149ce9 100644 --- a/rust/package/agama.changes +++ b/rust/package/agama.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Thu Jan 29 21:10:18 UTC 2026 - Josef Reidinger + +- Add support for "onlyRequired" key in "software" section + using new libzypp zypp.conf.d directory. + (gh#agama-project/agama#3100) + ------------------------------------------------------------------- Thu Jan 29 14:56:50 UTC 2026 - Imobach Gonzalez Sosa diff --git a/rust/zypp-agama/src/lib.rs b/rust/zypp-agama/src/lib.rs index d8ee5fe9bc..22674b6164 100644 --- a/rust/zypp-agama/src/lib.rs +++ b/rust/zypp-agama/src/lib.rs @@ -542,11 +542,11 @@ impl Zypp { } } - pub fn run_solver(&self) -> ZyppResult { + pub fn run_solver(&self, only_required: bool) -> ZyppResult { unsafe { let mut status: Status = Status::default(); let status_ptr = &mut status as *mut _; - let r_res = zypp_agama_sys::run_solver(self.ptr, status_ptr); + let r_res = zypp_agama_sys::run_solver(self.ptr, only_required, status_ptr); helpers::status_to_result(status, r_res) } } 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 584f917f3b..4f7474e32a 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 @@ -213,9 +213,11 @@ 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[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, struct Status *status) noexcept; +bool run_solver(struct Zypp *zypp, bool only_required, + struct Status *status) noexcept; /// the last call that will free all pointers to zypp holded by agama void free_zypp(struct Zypp *zypp) noexcept; diff --git a/rust/zypp-agama/zypp-agama-sys/c-layer/include/repository.h b/rust/zypp-agama/zypp-agama-sys/c-layer/include/repository.h index d418659eb4..2092b1d1d9 100644 --- a/rust/zypp-agama/zypp-agama-sys/c-layer/include/repository.h +++ b/rust/zypp-agama/zypp-agama-sys/c-layer/include/repository.h @@ -10,10 +10,10 @@ extern "C" { #endif struct Repository { - bool enabled; ///< - char *url; ///< owned - char *alias; ///< owned - char *userName; ///< owned + bool enabled; ///< + char *url; ///< owned + char *alias; ///< owned + char *userName; ///< owned char *serviceName; ///< owned }; 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 4d32b6d022..7d10a9fe07 100644 --- a/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx +++ b/rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx @@ -398,7 +398,8 @@ struct PatternInfos get_patterns_info(struct Zypp *_zypp, break; } } else { - // distinguish between the "not selected" and "explicitly removed by user" states + // 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 @@ -423,9 +424,11 @@ void free_pattern_infos(const struct PatternInfos *infos) noexcept { free(infos->infos); } -bool run_solver(struct Zypp *zypp, struct Status *status) noexcept { +bool run_solver(struct Zypp *zypp, bool only_required, + struct Status *status) noexcept { try { STATUS_OK(status); + zypp->zypp_pointer->resolver()->setOnlyRequires(only_required); return zypp->zypp_pointer->resolver()->resolvePool(); } catch (zypp::Exception &excpt) { STATUS_EXCEPT(status, excpt); diff --git a/rust/zypp-agama/zypp-agama-sys/src/bindings.rs b/rust/zypp-agama/zypp-agama-sys/src/bindings.rs index 43200b2246..632f1ca615 100644 --- a/rust/zypp-agama/zypp-agama-sys/src/bindings.rs +++ b/rust/zypp-agama/zypp-agama-sys/src/bindings.rs @@ -654,8 +654,8 @@ 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[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, 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"] + 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); #[doc = " repository array in list.\n when no longer needed, use \\ref free_repository_list to release memory\n @param zypp see \\ref init_target\n @param[out] status (will overwrite existing contents)"]