Expose base python version as an atom

Adds two new atoms `base-py2` and `base-py3` that can be used to
identify the primary python version supported by the current operating
system.

This allows bindep file authors to mention correct python package names
without having to hardcode each operating system version, which is
not future proof, as it would break when new versions are released.

New way to use bindep:

python3-lxml [platform:base-py3]
python-lxml [platform:base-py2]

Before this users had to rely on hacks like including the operating
system name and version [platform:centos-7] and negative variants,
something that would being broken as soon a new release is made.

Initial implementation covers RedHat flavored, Ubuntu, Debian and MacOS
which do come with an official Python version but is made in such way
that we could enable it for any other platforms.

Change-Id: I506699fb0c80f8d9ca84e20154d1c282a08708bb
Task: https://tree.taiga.io/project/tripleo-ci-board/task/809
This commit is contained in:
Sorin Sbarnea 2019-02-28 08:52:38 +00:00
parent bf85560fd0
commit 5ff2102297
8 changed files with 73 additions and 9 deletions

View File

@ -143,6 +143,18 @@ following example::
openssh-server [platform:redhat] openssh-server [platform:redhat]
openssh [platform:suse] openssh [platform:suse]
If you need to distinguish between operating systems where python2 or python3
is the official interpreter, you can use `base-py2` and `base-py3` labels.
Keep in mind that only one would be exposed for a specific operating system
even if the system could support installation of multiple python versions.
python3-lxml [(platform:redhat platform:base-py3)]
python-lxml [(platform:redhat platform:base-py2)]
The example above will install lxml python modules on official python used
by platform. Keep it mind that ``base-py[23]`` support is currently implemented
only on Debian, Ubuntu, RedHat flavours and MacOS.
To select Python3 development packages, the OpenStack CI default file uses:: To select Python3 development packages, the OpenStack CI default file uses::
python3-all-dev [platform:dpkg !platform:ubuntu-precise] python3-all-dev [platform:dpkg !platform:ubuntu-precise]

View File

@ -22,7 +22,11 @@ from parsley import makeGrammar
import platform import platform
import subprocess import subprocess
import sys import sys
# packaging is newer, usually available but not guaranteed
try:
from packaging.version import parse as as_ver
except ImportError:
from distutils.version import LooseVersion as as_ver
import distro import distro
@ -60,6 +64,8 @@ comment = ws? '#' any* '\n' -> None
any = ~'\n' anything any = ~'\n' anything
blank = ws? '\n' -> None blank = ws? '\n' -> None
""" """
PY2 = "base-py2"
PY3 = "base-py3"
def get_depends(filename=None): def get_depends(filename=None):
@ -303,6 +309,7 @@ class Depends(object):
# detect available macos package managers # detect available macos package managers
if os.system('which brew >/dev/null') == 0: if os.system('which brew >/dev/null') == 0:
atoms.add('brew') atoms.add('brew')
atoms.add(PY2)
self.platform = Brew() self.platform = Brew()
return ["platform:%s" % (atom,) for atom in sorted(atoms)] return ["platform:%s" % (atom,) for atom in sorted(atoms)]
distro_id = distro.id() distro_id = distro.id()
@ -315,6 +322,7 @@ class Depends(object):
# NOTE(toabctl): distro can be more than one string (i.e. "SUSE LINUX") # NOTE(toabctl): distro can be more than one string (i.e. "SUSE LINUX")
codename = distro.codename().lower() codename = distro.codename().lower()
release = distro.version().lower() release = distro.version().lower()
release_version = as_ver(release)
# NOTE(toabctl): space is a delimiter for bindep, so remove the spaces # NOTE(toabctl): space is a delimiter for bindep, so remove the spaces
distro_id = "".join(distro_id.split()).lower() distro_id = "".join(distro_id.split()).lower()
atoms = set([distro_id]) atoms = set([distro_id])
@ -322,6 +330,14 @@ class Depends(object):
atoms.update(self.releasebits(distro_id, release)) atoms.update(self.releasebits(distro_id, release))
if distro_id in ["debian", "ubuntu"]: if distro_id in ["debian", "ubuntu"]:
atoms.add("dpkg") atoms.add("dpkg")
# https://wiki.debian.org/Python
# https://wiki.ubuntu.com/Python
if (distro_id == 'ubuntu' and release_version >=
as_ver("16.04")) or (distro_id == 'debian' and
release_version >= as_ver("10")):
atoms.add(PY3)
else:
atoms.add(PY2)
self.platform = Dpkg() self.platform = Dpkg()
# RPM distros seem to be especially complicated # RPM distros seem to be especially complicated
elif distro_id in ["amzn", "amazonami", elif distro_id in ["amzn", "amazonami",
@ -338,12 +354,14 @@ class Depends(object):
atoms.add("rhel") atoms.add("rhel")
atoms.update(self.codenamebits("rhel", codename)) atoms.update(self.codenamebits("rhel", codename))
atoms.update(self.releasebits("rhel", release)) atoms.update(self.releasebits("rhel", release))
atoms.add(PY2 if release_version < as_ver("8") else PY3)
elif distro_id == 'rhel' and 'server' in distro.name().lower(): elif distro_id == 'rhel' and 'server' in distro.name().lower():
atoms.add("redhatenterpriseserver") atoms.add("redhatenterpriseserver")
atoms.update(self.codenamebits("redhatenterpriseserver", atoms.update(self.codenamebits("redhatenterpriseserver",
codename)) codename))
atoms.update(self.releasebits("redhatenterpriseserver", atoms.update(self.releasebits("redhatenterpriseserver",
release)) release))
atoms.add(PY2 if release_version < as_ver("8") else PY3)
elif (distro_id == 'rhel' and elif (distro_id == 'rhel' and
'workstation' in distro.name().lower()): 'workstation' in distro.name().lower()):
atoms.add("redhatenterpriseworkstation") atoms.add("redhatenterpriseworkstation")
@ -351,6 +369,7 @@ class Depends(object):
codename)) codename))
atoms.update(self.releasebits("redhatenterpriseworkstation", atoms.update(self.releasebits("redhatenterpriseworkstation",
release)) release))
atoms.add(PY2 if release_version < as_ver("8") else PY3)
elif "amzn" in distro_id: elif "amzn" in distro_id:
atoms.add("amazonami") atoms.add("amazonami")
atoms.update(self.codenamebits("amazonami", codename)) atoms.update(self.codenamebits("amazonami", codename))
@ -375,6 +394,10 @@ class Depends(object):
atoms.add("sles") atoms.add("sles")
atoms.update(self.codenamebits("sles", codename)) atoms.update(self.codenamebits("sles", codename))
atoms.update(self.releasebits("sles", release)) atoms.update(self.releasebits("sles", release))
elif "fedora" in distro_id:
atoms.add(PY2 if release_version < as_ver("23") else PY3)
elif "centos" in distro_id or "rhel" in distro_id:
atoms.add(PY2 if release_version < as_ver("8") else PY3)
# Family aliases # Family aliases
if 'suse' in distro_id or distro_id == 'sles': if 'suse' in distro_id or distro_id == 'sles':

View File

@ -85,7 +85,10 @@ python-devel [platform:rpm]
dev-lang/python [platform:gentoo] dev-lang/python [platform:gentoo]
python-libvirt [platform:dpkg] python-libvirt [platform:dpkg]
python-lxml [!platform:gentoo !platform:fedora] python-lxml [!platform:gentoo !platform:fedora]
python2-lxml [platform:fedora] # base-py3 covers CentOS>=8, Fedora>=23, RHEL>=8
python3-lxml [(platform:redhat platform:base-py3)]
# base-py2 covers CentOS<8, Fedora<23, RHEL<8
python-lxml [(platform:redhat platform:base-py2)]
dev-python/lxml [platform:gentoo] dev-python/lxml [platform:gentoo]
# Note that python3-all-dev includes python3-all, added # Note that python3-all-dev includes python3-all, added
# both here for documentary purpose. # both here for documentary purpose.

View File

@ -0,0 +1,16 @@
NAME="Red Hat Enterprise Linux"
VERSION="8.0 (Ootpa)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="8.0"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Red Hat Enterprise Linux 8.0 (Ootpa)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:8.0:GA"
HOME_URL="https://www.redhat.com/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8"
REDHAT_BUGZILLA_PRODUCT_VERSION=8.0
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="8.0"

View File

@ -129,8 +129,8 @@ class TestDepends(TestCase):
platform_profiles = depends.platform_profiles() platform_profiles = depends.platform_profiles()
self.assertThat(platform_profiles, Contains("platform:darwin")) self.assertThat(platform_profiles, Contains("platform:darwin"))
def test_detects_rhel(self): def test_detects_rhel7(self):
with DistroFixture("RHELServer"): with DistroFixture("RHELServer7"):
depends = Depends("") depends = Depends("")
platform_profiles = depends.platform_profiles() platform_profiles = depends.platform_profiles()
self.assertThat( self.assertThat(
@ -142,9 +142,10 @@ class TestDepends(TestCase):
self.assertThat( self.assertThat(
platform_profiles, platform_profiles,
Contains("platform:redhat")) Contains("platform:redhat"))
self.assertThat(platform_profiles, Contains("platform:base-py2"))
def test_detects_rhel_workstation(self): def test_detects_rhel_workstation(self):
with DistroFixture("RHELWorkstation"): with DistroFixture("RHELWorkstation7"):
depends = Depends("") depends = Depends("")
platform_profiles = depends.platform_profiles() platform_profiles = depends.platform_profiles()
self.assertThat( self.assertThat(
@ -156,13 +157,22 @@ class TestDepends(TestCase):
self.assertThat( self.assertThat(
platform_profiles, platform_profiles,
Contains("platform:redhat")) Contains("platform:redhat"))
self.assertThat(platform_profiles, Contains("platform:base-py2"))
def test_detects_fedora(self): def test_detects_fedora23(self):
with DistroFixture("Fedora"): with DistroFixture("Fedora23"):
depends = Depends("") depends = Depends("")
platform_profiles = depends.platform_profiles() platform_profiles = depends.platform_profiles()
self.assertThat(platform_profiles, Contains("platform:fedora")) self.assertThat(platform_profiles, Contains("platform:fedora"))
self.assertThat(platform_profiles, Contains("platform:redhat")) self.assertThat(platform_profiles, Contains("platform:redhat"))
self.assertThat(platform_profiles, Contains("platform:base-py3"))
def test_detects_rhel8(self):
with DistroFixture("rhel8"):
depends = Depends("")
platform_profiles = depends.platform_profiles()
self.assertThat(platform_profiles, Contains("platform:redhat"))
self.assertThat(platform_profiles, Contains("platform:base-py3"))
def test_detects_opensuse_project(self): def test_detects_opensuse_project(self):
# TODO what does an os-release for opensuse project look like? # TODO what does an os-release for opensuse project look like?
@ -243,14 +253,14 @@ class TestDepends(TestCase):
self.assertIsInstance(depends.platform, Rpm) self.assertIsInstance(depends.platform, Rpm)
def test_rhel_implies_rpm(self): def test_rhel_implies_rpm(self):
with DistroFixture("RHELServer"): with DistroFixture("RHELServer7"):
depends = Depends("") depends = Depends("")
self.assertThat( self.assertThat(
depends.platform_profiles(), Contains("platform:rpm")) depends.platform_profiles(), Contains("platform:rpm"))
self.assertIsInstance(depends.platform, Rpm) self.assertIsInstance(depends.platform, Rpm)
def test_fedora_implies_rpm(self): def test_fedora_implies_rpm(self):
with DistroFixture("Fedora"): with DistroFixture("Fedora23"):
depends = Depends("") depends = Depends("")
self.assertThat( self.assertThat(
depends.platform_profiles(), Contains("platform:rpm")) depends.platform_profiles(), Contains("platform:rpm"))