Skip to content

Commit

Permalink
Fix Dnf and Yum to accept 100 as a return code (#11668)
Browse files Browse the repository at this point in the history
* wip

* wip

* wip

* wip

* wip

* wip
  • Loading branch information
czoido committed Jul 19, 2022
1 parent 442d112 commit d40f5b5
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 8 deletions.
16 changes: 13 additions & 3 deletions conan/tools/system/package_manager.py
Expand Up @@ -11,6 +11,9 @@ class _SystemPackageManagerTool(object):
install_command = ""
update_command = ""
check_command = ""
accepted_install_codes = [0]
accepted_update_codes = [0]
accepted_check_codes = [0, 1]

def __init__(self, conanfile):
self._conanfile = conanfile
Expand Down Expand Up @@ -61,6 +64,12 @@ def run(self, method, *args, **kwargs):
if self._active_tool == self.__class__.tool_name:
return method(*args, **kwargs)

def _conanfile_run(self, command, accepted_returns):
ret = self._conanfile.run(command, ignore_errors=True)
if ret not in accepted_returns:
raise ConanException("Command '%s' failed" % command)
return ret

def install_substitutes(self, *args, **kwargs):
return self.run(self._install_substitutes, *args, **kwargs)

Expand Down Expand Up @@ -109,7 +118,7 @@ def _install(self, packages, update=False, check=True, **kwargs):
tool=self.tool_name,
packages=" ".join(packages_arch),
**kwargs)
return self._conanfile.run(command)
return self._conanfile_run(command, self.accepted_install_codes)
else:
self._conanfile.output.info("System requirements: {} already "
"installed".format(" ".join(packages)))
Expand All @@ -124,7 +133,7 @@ def _update(self):
"'-c tools.system.package_manager:mode={1}'".format(self.mode_check,
self.mode_install))
command = self.update_command.format(sudo=self.sudo_str, tool=self.tool_name)
return self._conanfile.run(command)
return self._conanfile_run(command, self.accepted_update_codes)

def _check(self, packages):
missing = [pkg for pkg in packages if self.check_package(self.get_package_name(pkg)) != 0]
Expand All @@ -133,7 +142,7 @@ def _check(self, packages):
def check_package(self, package):
command = self.check_command.format(tool=self.tool_name,
package=package)
return self._conanfile.run(command, ignore_errors=True)
return self._conanfile_run(command, self.accepted_check_codes)


class Apt(_SystemPackageManagerTool):
Expand Down Expand Up @@ -167,6 +176,7 @@ class Yum(_SystemPackageManagerTool):
install_command = "{sudo}{tool} install -y {packages}"
update_command = "{sudo}{tool} check-update -y"
check_command = "rpm -q {package}"
accepted_update_codes = [0, 100]

def __init__(self, conanfile, arch_names=None):
super(Yum, self).__init__(conanfile)
Expand Down
53 changes: 48 additions & 5 deletions conans/test/integration/tools/system/package_manager_test.py
@@ -1,4 +1,5 @@
import platform
from unittest.mock import MagicMock, patch

import mock
import pytest
Expand Down Expand Up @@ -111,7 +112,11 @@ def test_tools_install_mode_check(tool_class):
context_mock.return_value = "host"
tool = tool_class(conanfile)
with pytest.raises(ConanException) as exc_info:
tool.install(["package1", "package2"])
def fake_check(*args, **kwargs):
return ["package1", "package2"]
from conan.tools.system.package_manager import _SystemPackageManagerTool
with patch.object(_SystemPackageManagerTool, 'check', MagicMock(side_effect=fake_check)):
tool.install(["package1", "package2"])
assert exc_info.value.args[0] == "System requirements: 'package1, package2' are missing but " \
"can't install because tools.system.package_manager:mode is " \
"'check'.Please update packages manually or set " \
Expand Down Expand Up @@ -140,7 +145,6 @@ def test_tools_update_mode_check(tool_class):
"'-c tools.system.package_manager:mode=install'"



@pytest.mark.parametrize("tool_class, result", [
(Apt, "apt-get update"),
(Yum, "yum check-update -y"),
Expand All @@ -165,6 +169,42 @@ def test_tools_update_mode_install(tool_class, result):
assert tool._conanfile.command == result


@pytest.mark.parametrize("tool_class, result", [
(Yum, "yum check-update -y"),
(Dnf, "dnf check-update -y"),
])
def test_dnf_yum_return_code_100(tool_class, result):
# https://github.com/conan-io/conan/issues/11661
conanfile = ConanFileMock()
conanfile.conf = Conf()
conanfile.settings = Settings()
conanfile.conf["tools.system.package_manager:tool"] = tool_class.tool_name
conanfile.conf["tools.system.package_manager:mode"] = "install"
with mock.patch('conans.ConanFile.context', new_callable=PropertyMock) as context_mock:
context_mock.return_value = "host"
tool = tool_class(conanfile)

def fake_run(command, win_bash=False, subsystem=None, env=None, ignore_errors=False):
assert command == result
return 100 if "check-update" in command else 0

conanfile.run = fake_run
tool.update()

#check that some random return code fails
with mock.patch('conans.ConanFile.context', new_callable=PropertyMock) as context_mock:
context_mock.return_value = "host"
tool = tool_class(conanfile)

def fake_run(command, win_bash=False, subsystem=None, env=None, ignore_errors=False):
return 55 if "check-update" in command else 0

conanfile.run = fake_run
with pytest.raises(ConanException) as exc_info:
tool.update()
assert f"Command '{result}' failed" == str(exc_info.value)


@pytest.mark.parametrize("tool_class, result", [
(Apt, 'apt-get install -y --no-install-recommends package1 package2'),
(Yum, 'yum install -y package1 package2'),
Expand All @@ -185,8 +225,12 @@ def test_tools_install_mode_install(tool_class, result):
with mock.patch('conans.ConanFile.context', new_callable=PropertyMock) as context_mock:
context_mock.return_value = "host"
tool = tool_class(conanfile)
tool.install(["package1", "package2"])
assert tool._conanfile.command == result

def fake_check(*args, **kwargs):
return ["package1", "package2"]
from conan.tools.system.package_manager import _SystemPackageManagerTool
with patch.object(_SystemPackageManagerTool, 'check', MagicMock(side_effect=fake_check)):
tool.install(["package1", "package2"])


@pytest.mark.parametrize("tool_class, result", [
Expand All @@ -209,4 +253,3 @@ def test_tools_check(tool_class, result):
context_mock.return_value = "host"
tool = tool_class(conanfile)
tool.check(["package"])
assert tool._conanfile.command == result
1 change: 1 addition & 0 deletions conans/test/utils/mocks.py
Expand Up @@ -197,6 +197,7 @@ def run(self, command, win_bash=False, subsystem=None, env=None, ignore_errors=F
self.command = command
self.path = os.environ["PATH"]
self.captured_env = {key: value for key, value in os.environ.items()}
return 0


MockOptions = MockSettings
Expand Down

0 comments on commit d40f5b5

Please sign in to comment.