dnf
dnf copied to clipboard
Remote Packages Not Copied to Destdir in `download_packages` Method
Description:
I've encountered an issue with the download_packages method in DNF's base.py. While the method successfully downloads remote packages, it does not copy these downloaded packages to the destdir, even when the destdir configuration is set. This behavior is inconsistent with the handling of local packages, which are correctly copied to destdir. It's also worth noting that the conf documentation does not actually document the existence of the destdir and the downloadonly configuration settings in the API docs. Oddly, it's worth mentioning that somehow the CLI works... it's just the API that doesn't seem to do what it's supposed to here. It
Steps to Reproduce:
- Set up a DNF transaction with remote packages to be downloaded.
- Set the
base.conf.downloadonly = Trueandbase.conf.destdirto your desired output directory. - Call the
download_packagesmethod on the DNF Base object. - Observe that the downloaded remote packages are not copied to
destdir.
[root@wilrod-rhel89 ~]# python3
Python 3.6.8 (default, Sep 26 2023, 08:41:01)
[GCC 8.5.0 20210514 (Red Hat 8.5.0-20)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import dnf
>>> base = dnf.Base()
>>> base.conf.downloadonly = True
>>> base.conf.destdir = '/root/rpmdownload/baseos'
>>> base.read_all_repos()
>>> base.install_specs(['zsh'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/site-packages/dnf/base.py", line 1985, in install_specs
self._exclude_package_specs(exclude_specs)
File "/usr/lib/python3.6/site-packages/dnf/base.py", line 1931, in _exclude_package_specs
exclude_query = self.sack.query().filter(name=excludes)
AttributeError: 'NoneType' object has no attribute 'query'
>>> base.fill_sack(load_system_repo=False)
<dnf.sack.Sack object at 0x7f5f081cee18>
>>> base.install_specs(['zsh'])
>>> base.resolve()
True
>>> base.download_packages(base.transaction.install_set)
Note that this does not result in anything being downloaded to my /root/rpmdownload/baseos directory, however, executing the command worked just fine, for reasons I don't understand:
[root@wilrod-rhel89 ~]# dnf install -y --downloadonly --destdir /root/rpmdownload/baseos zsh
Updating Subscription Management repositories.
Last metadata expiration check: 2:27:49 ago on Thu 04 Jan 2024 09:21:23 PM CST.
Dependencies resolved.
========================================================================================================================
Package Architecture Version Repository Size
========================================================================================================================
Installing:
zsh x86_64 5.5.1-10.el8 rhel-8-for-x86_64-baseos-rpms 2.9 M
Transaction Summary
========================================================================================================================
Install 1 Package
Total download size: 2.9 M
Installed size: 6.9 M
DNF will only download packages for the transaction.
Downloading Packages:
zsh-5.5.1-10.el8.x86_64.rpm 5.9 MB/s | 2.9 MB 00:00
------------------------------------------------------------------------------------------------------------------------
Total 5.9 MB/s | 2.9 MB 00:00
Complete!
The downloaded packages were saved in cache until the next successful transaction.
You can remove cached packages by executing 'dnf clean packages'.
[root@wilrod-rhel89 ~]# ll rpmdownload/baseos/
total 2968
-rw-r--r--. 1 root root 3036296 Jan 4 23:49 zsh-5.5.1-10.el8.x86_64.rpm
Expected Behavior:
The downloaded remote packages should be copied to the destdir, similar to how local packages are handled.
Actual Behavior:
The downloaded remote packages remain in their original download location and are not copied to destdir.
Environment:
- DNF version: dnf-4.7.0-19.el8.noarch
- Operating System: RHEL 8.9
- Python version: 3.6
Proposed Fix:
I propose modifying the download_packages method to include a step that copies downloaded remote packages to destdir. Here is the suggested code change:
def download_packages(self, pkglist, progress=None, callback_total=None):
# Existing code for remote and local package separation
remote_pkgs, local_pkgs = self._select_remote_pkgs(pkglist)
if remote_pkgs:
# Existing code for downloading remote packages
# ...
# Additional code to copy downloaded remote packages to destdir
if self.conf.destdir:
for pkg in remote_pkgs:
# Determine the download location
download_location = pkg.localPkg()
# Determine the destination path
destination = os.path.join(self.conf.destdir, os.path.basename(download_location))
# Copy the package to destdir
shutil.copy(download_location, destination)
# Existing code for handling local packages
if self.conf.destdir:
for pkg in local_pkgs:
# Existing code for copying local packages to destdir
# ...
I believe this fix will align the behavior of the method with the expected functionality and provide a consistent experience for handling both remote and local packages.
Thanks for the report. I will try to investigate what's wrong with Base.download_packages() method. However, for issues in RHEL software please contact Red Hat support https://access.redhat.com/support/. This repository on Github is an upstream code which may or might not have the behavior you observe in RHEL.
I confirm the reported behavior in current git tree (1c43d0999178d492381ad0b43917ffd9c74016f8, 4.18.2).