diff --git a/build-tests/x86/centos/test-image-live-disk-v10/appliance.kiwi b/build-tests/x86/centos/test-image-live-disk-v10/appliance.kiwi index fefb8d6b667..5ef14647816 100644 --- a/build-tests/x86/centos/test-image-live-disk-v10/appliance.kiwi +++ b/build-tests/x86/centos/test-image-live-disk-v10/appliance.kiwi @@ -3,20 +3,20 @@ - + Marcus Schaefer marcus.schaefer@gmail.com - CentOS Stream 9 Appliance + CentOS Stream 10 Appliance - - - + + + 1.3.0 - dnf + dnf4 charge en_US us diff --git a/build-tests/x86/centos/test-image-live-disk-v9/appliance.kiwi b/build-tests/x86/centos/test-image-live-disk-v9/appliance.kiwi index 1f8a2e0fc4a..a5ff5384f69 100644 --- a/build-tests/x86/centos/test-image-live-disk-v9/appliance.kiwi +++ b/build-tests/x86/centos/test-image-live-disk-v9/appliance.kiwi @@ -16,7 +16,7 @@ 1.3.0 - dnf + dnf4 charge en_US us diff --git a/kiwi/package_manager/dnf4.py b/kiwi/package_manager/dnf4.py index 6e89dd76fde..e5f9c1bec34 100644 --- a/kiwi/package_manager/dnf4.py +++ b/kiwi/package_manager/dnf4.py @@ -15,6 +15,7 @@ # You should have received a copy of the GNU General Public License # along with kiwi. If not, see # +import os import re from typing import ( List, Dict @@ -88,6 +89,31 @@ def request_package_exclusion(self, name: str) -> None: """ self.exclude_requests.append(name) + def _get_dnf4_binary_name(self, root=None): + """ + Identify whether dnf is 'dnf4' or 'dnf-3' + + :param str root: lookup binary name below this root directory + + :return: name of dnf4 command + + :rtype: str + """ + dnf4_binary = 'dnf-3' + dnf4_search_env = { + 'PATH': os.sep.join([root, 'usr', 'bin']) + } if root else None + + # Python interpreter specific path + if Path.which( + filename='dnf4', + custom_env=dnf4_search_env, + access_mode=os.X_OK + ): + dnf4_binary = 'dnf4' + + return dnf4_binary + def setup_repository_modules( self, collection_modules: Dict[str, List[str]] ) -> None: @@ -109,7 +135,7 @@ def setup_repository_modules( } """ dnf_module_command = [ - 'dnf' + self._get_dnf4_binary_name() ] + self.dnf_args + [ '--installroot', self.root_dir, f'--releasever={self.release_version}' @@ -147,6 +173,7 @@ def process_install_requests_bootstrap( :rtype: namedtuple """ + dnf4 = self._get_dnf4_binary_name() exclude_args = [] if self.exclude_requests: # For DNF, excluding a package means removing it from @@ -156,12 +183,12 @@ def process_install_requests_bootstrap( for package in self.exclude_requests: exclude_args.append('--exclude=' + package) Command.run( - ['dnf'] + self.dnf_args + [ + [dnf4] + self.dnf_args + [ f'--releasever={self.release_version}' ] + ['makecache'] ) dnf_command = [ - 'dnf' + dnf4 ] + self.dnf_args + [ '--installroot', self.root_dir, f'--releasever={self.release_version}' @@ -181,6 +208,7 @@ def process_install_requests(self) -> CommandCallT: :rtype: namedtuple """ + dnf4 = self._get_dnf4_binary_name(self.root_dir) exclude_args = [] if self.exclude_requests: # For DNF, excluding a package means removing it from @@ -193,7 +221,7 @@ def process_install_requests(self) -> CommandCallT: self.root_dir, self.dnf_args ) dnf_command = [ - 'chroot', self.root_dir, 'dnf' + 'chroot', self.root_dir, dnf4 ] + chroot_dnf_args + [ f'--releasever={self.release_version}' ] + self.custom_args + exclude_args + [ @@ -240,9 +268,10 @@ def process_delete_requests(self, force: bool = False) -> CommandCallT: self.command_env ) else: + dnf4 = self._get_dnf4_binary_name(self.root_dir) chroot_dnf_args = Path.move_to_root(self.root_dir, self.dnf_args) dnf_command = [ - 'chroot', self.root_dir, 'dnf' + 'chroot', self.root_dir, dnf4 ] + chroot_dnf_args + [ f'--releasever={self.release_version}' ] + self.custom_args + [ @@ -261,10 +290,11 @@ def update(self) -> CommandCallT: :rtype: namedtuple """ + dnf4 = self._get_dnf4_binary_name(self.root_dir) chroot_dnf_args = Path.move_to_root(self.root_dir, self.dnf_args) return Command.call( [ - 'chroot', self.root_dir, 'dnf' + 'chroot', self.root_dir, dnf4 ] + chroot_dnf_args + [ f'--releasever={self.release_version}' ] + self.custom_args + [ diff --git a/test/unit/package_manager/dnf4_test.py b/test/unit/package_manager/dnf4_test.py index 75081df0ac6..8e37b4d405f 100644 --- a/test/unit/package_manager/dnf4_test.py +++ b/test/unit/package_manager/dnf4_test.py @@ -41,8 +41,26 @@ def test_request_package_exclusion(self): self.manager.request_package_exclusion('name') assert self.manager.exclude_requests == ['name'] + @patch('kiwi.path.Path.which') + def test_get_dnf4_binary_name(self, mock_which): + mock_which.return_value = '/usr/bin/dnf4' + assert self.manager._get_dnf4_binary_name() == 'dnf4' + mock_which.assert_called_once_with( + access_mode=1, custom_env=None, + filename='dnf4' + ) + mock_which.return_value = None + mock_which.reset_mock() + assert self.manager._get_dnf4_binary_name(root='/some/root') == 'dnf-3' + mock_which.assert_called_once_with( + access_mode=1, custom_env={'PATH': '/some/root/usr/bin'}, + filename='dnf4' + ) + + @patch('kiwi.path.Path.which') @patch('kiwi.command.Command.run') - def test_setup_repository_modules(self, mock_run): + def test_setup_repository_modules(self, mock_run, mock_exists): + mock_exists.return_value = None self.manager.setup_repository_modules( { 'disable': ['mod_c'], @@ -50,7 +68,7 @@ def test_setup_repository_modules(self, mock_run): } ) dnf_call_args = [ - 'dnf', '--config', '/root-dir/dnf.conf', + 'dnf-3', '--config', '/root-dir/dnf.conf', '-y', '--installroot', '/root-dir', '--releasever=0' ] assert mock_run.call_args_list == [ @@ -81,37 +99,41 @@ def test_setup_repository_modules(self, mock_run): ) ] + @patch('kiwi.path.Path.which') @patch('kiwi.command.Command.call') @patch('kiwi.command.Command.run') - def test_process_install_requests_bootstrap(self, mock_run, mock_call): + def test_process_install_requests_bootstrap(self, mock_run, mock_call, mock_exists): + mock_exists.return_value = None self.manager.request_package('vim') self.manager.request_collection('collection') self.manager.request_package_exclusion('skipme') self.manager.process_install_requests_bootstrap() mock_run.assert_called_once_with( [ - 'dnf', '--config', '/root-dir/dnf.conf', '-y', + 'dnf-3', '--config', '/root-dir/dnf.conf', '-y', '--releasever=0', 'makecache' ] ) mock_call.assert_called_once_with( [ - 'dnf', '--config', '/root-dir/dnf.conf', '-y', + 'dnf-3', '--config', '/root-dir/dnf.conf', '-y', '--installroot', '/root-dir', '--releasever=0', '--exclude=skipme', 'install', 'vim', '@collection' ], ['env'] ) + @patch('kiwi.path.Path.which') @patch('kiwi.command.Command.call') - def test_process_install_requests(self, mock_call): + def test_process_install_requests(self, mock_call, mock_exists): + mock_exists.return_value = None self.manager.request_package('vim') self.manager.request_collection('collection') self.manager.request_package_exclusion('skipme') self.manager.process_install_requests() mock_call.assert_called_once_with( [ - 'chroot', '/root-dir', 'dnf', '--config', '/dnf.conf', '-y', + 'chroot', '/root-dir', 'dnf-3', '--config', '/dnf.conf', '-y', '--releasever=0', '--exclude=skipme', 'install', 'vim', '@collection' ], ['env'] @@ -132,14 +154,16 @@ def test_process_delete_requests_force(self, mock_run, mock_call): ] ) + @patch('kiwi.path.Path.which') @patch('kiwi.command.Command.call') @patch('kiwi.command.Command.run') - def test_process_delete_requests_no_force(self, mock_run, mock_call): + def test_process_delete_requests_no_force(self, mock_run, mock_call, mock_exists): + mock_exists.return_value = None self.manager.request_package('vim') self.manager.process_delete_requests() mock_call.assert_called_once_with( [ - 'chroot', '/root-dir', 'dnf', + 'chroot', '/root-dir', 'dnf-3', '--config', '/dnf.conf', '-y', '--releasever=0', 'autoremove', 'vim' ], @@ -159,12 +183,14 @@ def test_process_delete_requests_package_missing( ['chroot', '/root-dir', 'rpm', '-q', 'vim'] ) + @patch('kiwi.path.Path.which') @patch('kiwi.command.Command.call') - def test_update(self, mock_call): + def test_update(self, mock_call, mock_exists): + mock_exists.return_value = None self.manager.update() mock_call.assert_called_once_with( [ - 'chroot', '/root-dir', 'dnf', + 'chroot', '/root-dir', 'dnf-3', '--config', '/dnf.conf', '-y', '--releasever=0', 'upgrade' ], ['env']