Skip to content

Commit

Permalink
Detect System package name by recipe settings (#5026) (#5215)
Browse files Browse the repository at this point in the history
* #5026 Detect package prefix name by settings

- Each package manages has a specific prefix/suffix to deal with
  architectures.
- Some package managers (e.g brew) do not provide multi-arch
  support, only an universal option.

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* #5026 Validate SystemPackageTool with settings

- Validate yum and apt when installing x86

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* #5026 Support custom platform

- User is able to specify prefix/suffix according the arch

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* #5026 Remove useless code

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* #5026 Rename methods for package name

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* #5026 Use conanfile for SystemPackageTool

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* #5026 Validate output instance

Co-Authored-By: Javier G. Sogo <jgsogo@gmail.com>

* #5026 Fix bad indented block

Signed-off-by: Uilian Ries <uilianries@gmail.com>
  • Loading branch information
uilianries authored and lasote committed Jul 1, 2019
1 parent 5ad0672 commit b75300b
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 6 deletions.
89 changes: 83 additions & 6 deletions conans/client/tools/system_pm.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import sys

from conans.client.runner import ConanRunner
from conans.client.tools.oss import OSInfo
from conans.client.tools.oss import OSInfo, cross_building, get_cross_building_settings
from conans.client.tools.files import which
from conans.errors import ConanException
from conans.util.env_reader import get_env
Expand All @@ -11,15 +11,16 @@

class SystemPackageTool(object):

def __init__(self, runner=None, os_info=None, tool=None, recommends=False, output=None):

def __init__(self, runner=None, os_info=None, tool=None, recommends=False, output=None, conanfile=None):
output = output if output else conanfile.output if conanfile else None
self._output = default_output(output, 'conans.client.tools.system_pm.SystemPackageTool')
os_info = os_info or OSInfo()
self._is_up_to_date = False
self._tool = tool or self._create_tool(os_info, output=self._output)
self._tool._sudo_str = self._get_sudo_str()
self._tool._runner = runner or ConanRunner(output=self._output)
self._tool._recommends = recommends
self._conanfile = conanfile

@staticmethod
def _get_sudo_str():
Expand Down Expand Up @@ -87,11 +88,17 @@ def update(self):
self._is_up_to_date = True
self._tool.update()

def install(self, packages, update=True, force=False):
def install(self, packages, update=True, force=False, arch_names=None):
""" Get the system package tool install command.
:param packages: String with all package to be installed e.g. "libusb-dev libfoobar-dev"
:param update: Run update command before to install
:param force: Force installing all packages
:param arch_names: Package suffix/prefix name used by installer tool e.g. {"x86_64": "amd64"}
:return: None
"""
Get the system package tool install command.
'"""
packages = [packages] if isinstance(packages, str) else list(packages)
packages = self._get_package_names(packages, arch_names)

mode = self._get_sysrequire_mode()

Expand All @@ -116,6 +123,24 @@ def install(self, packages, update=True, force=False):
self.update()
self._install_any(packages)

def _get_package_names(self, packages, arch_names):
""" Parse package names according it architecture
:param packages: list with all package to be installed e.g. ["libusb-dev libfoobar-dev"]
:param arch_names: Package suffix/prefix name used by installer tool
:return: list with all parsed names e.g. ["libusb-dev:armhf libfoobar-dev:armhf"]
"""
if self._conanfile and self._conanfile.settings and cross_building(self._conanfile.settings):
_, build_arch, _, host_arch = get_cross_building_settings(self._conanfile.settings)
arch = host_arch or build_arch
parsed_packages = []
for package in packages:
for package_name in package.split(" "):
parsed_packages.append(self._tool.get_package_name(package_name, arch,
arch_names))
return parsed_packages
return packages

def _installed(self, packages):
if not packages:
return True
Expand All @@ -141,6 +166,16 @@ class BaseTool(object):
def __init__(self, output=None):
self._output = default_output(output, 'conans.client.tools.system_pm.BaseTool')

def get_package_name(self, package, arch, arch_names):
""" Retrieve package name to installed according the target arch.
:param package: Regular package name e.g libusb-dev
:param arch: Host arch from Conanfile.settings
:param arch_names: Dictionary with suffix/prefix names e.g {"x86_64": "amd64"}
:return: Package name for Tool e.g. libusb-dev:i386
"""
return package


class NullTool(BaseTool):
def add_repository(self, repository, repo_key=None):
Expand Down Expand Up @@ -179,6 +214,20 @@ def installed(self, package_name):
% package_name, None)
return exit_code == 0

def get_package_name(self, package, arch, arch_names):
if arch_names is None:
arch_names = {"x86_64": "amd64",
"x86": "i386",
"ppc32": "powerpc",
"ppc64le": "ppc64el",
"armv7": "arm",
"armv7hf": "armhf",
"armv8": "arm64",
"s390x": "s390x"}
if arch in arch_names:
return "%s:%s" % (package, arch_names[arch])
return package


class YumTool(BaseTool):
def add_repository(self, repository, repo_key=None):
Expand All @@ -196,6 +245,20 @@ def installed(self, package_name):
exit_code = self._runner("rpm -q %s" % package_name, None)
return exit_code == 0

def get_package_name(self, package, arch, arch_names):
if arch_names is None:
arch_names = {"x86_64": "x86_64",
"x86": "i?86",
"ppc32": "powerpc",
"ppc64le": "ppc64le",
"armv7": "armv7",
"armv7hf": "armv7hl",
"armv8": "aarch64",
"s390x": "s390x"}
if arch in arch_names:
return "%s.%s" % (package, arch_names[arch])
return package


class BrewTool(BaseTool):
def add_repository(self, repository, repo_key=None):
Expand Down Expand Up @@ -275,6 +338,13 @@ def installed(self, package_name):
exit_code = self._runner("pacman -Qi %s" % package_name, None)
return exit_code == 0

def get_package_name(self, package, arch, arch_names):
if arch_names is None:
arch_names = {"x86": "lib32"}
if arch in arch_names:
return "%s-%s" % (arch_names[arch], package)
return package


class ZypperTool(BaseTool):
def add_repository(self, repository, repo_key=None):
Expand All @@ -291,6 +361,13 @@ def installed(self, package_name):
exit_code = self._runner("rpm -q %s" % package_name, None)
return exit_code == 0

def get_package_name(self, package, arch, arch_names):
if arch_names is None:
arch_names = {"x86": "i586"}
if arch in arch_names:
return "%s.%s" % (arch_names[arch], package)
return package


def _run(runner, command, output, accepted_returns=None):
accepted_returns = accepted_returns or [0, ]
Expand Down
37 changes: 37 additions & 0 deletions conans/test/unittests/client/tools/system_pm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from conans.errors import ConanException
from conans.test.unittests.util.tools_test import RunnerMock
from conans.test.utils.tools import TestBufferConanOutput
from conans.test.utils.conanfile import MockSettings, MockConanfile


class SystemPackageToolTest(unittest.TestCase):
Expand Down Expand Up @@ -166,6 +167,16 @@ def system_package_tool_test(self):
spt.install("a_package", force=True)
self.assertEqual(runner.command_called, "sudo -A yum install -y a_package")

settings = MockSettings({"arch": "x86", "arch_build": "x86_64", "os": "Linux",
"os_build": "Linux"})
conanfile = MockConanfile(settings)
spt = SystemPackageTool(runner=runner, os_info=os_info, output=self.out,
conanfile=conanfile)
spt.install("a_package", force=False)
self.assertEqual(runner.command_called, "rpm -q a_package.i?86")
spt.install("a_package", force=True)
self.assertEqual(runner.command_called, "sudo -A yum install -y a_package.i?86")

os_info.linux_distro = "debian"
spt = SystemPackageTool(runner=runner, os_info=os_info, output=self.out)
with self.assertRaises(ConanException):
Expand Down Expand Up @@ -235,6 +246,32 @@ def system_package_tool_test(self):
spt.update()
self.assertEqual(runner.command_called, "apt-get update")

for arch, distro_arch in {"x86_64": "", "x86": ":i386", "ppc32": ":powerpc",
"ppc64le": ":ppc64el", "armv7": ":arm", "armv7hf": ":armhf",
"armv8": ":arm64", "s390x": ":s390x"}.items():
settings = MockSettings({"arch": arch,
"arch_build": "x86_64",
"os": "Linux",
"os_build": "Linux"})
conanfile = MockConanfile(settings)
spt = SystemPackageTool(runner=runner, os_info=os_info, output=self.out,
conanfile=conanfile)
spt.install("a_package", force=True)
self.assertEqual(runner.command_called,
"apt-get install -y --no-install-recommends a_package%s" % distro_arch)

for arch, distro_arch in {"x86_64": "", "x86": ":all"}.items():
settings = MockSettings({"arch": arch,
"arch_build": "x86_64",
"os": "Linux",
"os_build": "Linux"})
conanfile = MockConanfile(settings)
spt = SystemPackageTool(runner=runner, os_info=os_info, output=self.out,
conanfile=conanfile)
spt.install("a_package", force=True, arch_names={"x86": "all"})
self.assertEqual(runner.command_called,
"apt-get install -y --no-install-recommends a_package%s" % distro_arch)

os_info.is_macos = True
os_info.is_linux = False
os_info.is_windows = False
Expand Down

0 comments on commit b75300b

Please sign in to comment.