3939#include < libdnf5/rpm/package_set.hpp>
4040#include < libdnf5/rpm/rpm_signature.hpp>
4141#include < libdnf5/transaction/offline.hpp>
42+ #include < libdnf5/transaction/transaction_item_action.hpp>
4243#include < libdnf5/utils/bgettext/bgettext-lib.h>
4344#include < libdnf5/utils/bgettext/bgettext-mark-domain.h>
4445#include < libdnf5/utils/fs/file.hpp>
@@ -337,6 +338,37 @@ void Context::Impl::store_offline(libdnf5::base::Transaction & transaction) {
337338 state.write ();
338339}
339340
341+ // / Prepopulate the offline destdir with already-cached packages from the repo
342+ // / cache to avoid re-downloading them. Must be called before setting destdir,
343+ // / so that get_package_path() / is_available_locally() still resolve to the
344+ // / repo cache.
345+ static void prepopulate_offline_cache (
346+ libdnf5::base::Transaction & transaction, const std::filesystem::path & packages_dir) {
347+ bool packages_dir_created = false ;
348+ for (auto & tspkg : transaction.get_transaction_packages ()) {
349+ if (!libdnf5::transaction::transaction_item_action_is_inbound (tspkg.get_action ())) {
350+ continue ;
351+ }
352+ auto pkg = tspkg.get_package ();
353+ if (pkg.get_repo ()->get_type () == libdnf5::repo::Repo::Type::COMMANDLINE) {
354+ continue ;
355+ }
356+ if (!pkg.is_available_locally ()) {
357+ continue ;
358+ }
359+ if (!packages_dir_created) {
360+ std::filesystem::create_directories (packages_dir);
361+ packages_dir_created = true ;
362+ }
363+ auto cached_path = std::filesystem::path (pkg.get_package_path ());
364+ auto dest_path = packages_dir / cached_path.filename ();
365+ std::error_code ec;
366+ if (!std::filesystem::exists (dest_path, ec)) {
367+ std::filesystem::copy_file (cached_path, dest_path, ec);
368+ }
369+ }
370+ }
371+
340372void Context::Impl::download_and_run (libdnf5::base::Transaction & transaction) {
341373 if (!transaction_store_path.empty ()) {
342374 auto & config = base.get_config ();
@@ -356,9 +388,10 @@ void Context::Impl::download_and_run(libdnf5::base::Transaction & transaction) {
356388 throw libdnf5::cli::AbortedByUserError ();
357389 }
358390 }
391+ std::filesystem::create_directories (transaction_store_path);
392+ prepopulate_offline_cache (transaction, packages_location);
359393 auto & destdir_opt = config.get_destdir_option ();
360394 destdir_opt.set (packages_location);
361- std::filesystem::create_directories (transaction_store_path);
362395 // Override keepcache option because stored transaction packages should be always kept.
363396 // Following transactions should never remove them.
364397 auto & keepcache_opt = config.get_keepcache_option ();
@@ -389,7 +422,9 @@ void Context::Impl::download_and_run(libdnf5::base::Transaction & transaction) {
389422 throw libdnf5::cli::AbortedByUserError ();
390423 }
391424 }
392- base.get_config ().get_destdir_option ().set (offline_destdir / " packages" );
425+ const auto & packages_dir = offline_destdir / " packages" ;
426+ prepopulate_offline_cache (transaction, packages_dir);
427+ base.get_config ().get_destdir_option ().set (packages_dir);
393428 transaction.set_download_local_pkgs (true );
394429 }
395430
0 commit comments