Update external distro package to 1.0.1 (#2381)

This commit is contained in:
Adam J. Stewart 2016-11-22 16:01:01 -06:00 committed by Todd Gamblin
parent 1901b05b9c
commit f351e4402c

View File

@ -31,14 +31,16 @@
import os import os
import re import re
import sys import sys
import json
import shlex import shlex
import logging
import argparse
import subprocess import subprocess
if not sys.platform.startswith('linux'): if not sys.platform.startswith('linux'):
raise ImportError('Unsupported platform: {0}'.format(sys.platform)) raise ImportError('Unsupported platform: {0}'.format(sys.platform))
_UNIXCONFDIR = '/etc' _UNIXCONFDIR = '/etc'
_OS_RELEASE_BASENAME = 'os-release' _OS_RELEASE_BASENAME = 'os-release'
@ -75,7 +77,6 @@
'redhat': 'rhel', # RHEL 6.x, 7.x 'redhat': 'rhel', # RHEL 6.x, 7.x
} }
# Pattern for content of distro release file (reversed) # Pattern for content of distro release file (reversed)
_DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile( _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile(
r'(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)') r'(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)')
@ -119,7 +120,7 @@ def linux_distribution(full_distribution_name=True):
method normalizes the distro ID string to a reliable machine-readable value method normalizes the distro ID string to a reliable machine-readable value
for a number of popular Linux distributions. for a number of popular Linux distributions.
""" """
return _distroi.linux_distribution(full_distribution_name) return _distro.linux_distribution(full_distribution_name)
def id(): def id():
@ -194,7 +195,7 @@ def id():
command, with ID values that differ from what was previously determined command, with ID values that differ from what was previously determined
from the distro release file name. from the distro release file name.
""" """
return _distroi.id() return _distro.id()
def name(pretty=False): def name(pretty=False):
@ -233,7 +234,7 @@ def name(pretty=False):
with the value of the pretty version ("<version_id>" and "<codename>" with the value of the pretty version ("<version_id>" and "<codename>"
fields) of the distro release file, if available. fields) of the distro release file, if available.
""" """
return _distroi.name(pretty) return _distro.name(pretty)
def version(pretty=False, best=False): def version(pretty=False, best=False):
@ -277,7 +278,7 @@ def version(pretty=False, best=False):
the lsb_release command, if it follows the format of the distro release the lsb_release command, if it follows the format of the distro release
files. files.
""" """
return _distroi.version(pretty, best) return _distro.version(pretty, best)
def version_parts(best=False): def version_parts(best=False):
@ -294,7 +295,7 @@ def version_parts(best=False):
For a description of the *best* parameter, see the :func:`distro.version` For a description of the *best* parameter, see the :func:`distro.version`
method. method.
""" """
return _distroi.version_parts(best) return _distro.version_parts(best)
def major_version(best=False): def major_version(best=False):
@ -307,7 +308,7 @@ def major_version(best=False):
For a description of the *best* parameter, see the :func:`distro.version` For a description of the *best* parameter, see the :func:`distro.version`
method. method.
""" """
return _distroi.major_version(best) return _distro.major_version(best)
def minor_version(best=False): def minor_version(best=False):
@ -320,7 +321,7 @@ def minor_version(best=False):
For a description of the *best* parameter, see the :func:`distro.version` For a description of the *best* parameter, see the :func:`distro.version`
method. method.
""" """
return _distroi.minor_version(best) return _distro.minor_version(best)
def build_number(best=False): def build_number(best=False):
@ -333,7 +334,7 @@ def build_number(best=False):
For a description of the *best* parameter, see the :func:`distro.version` For a description of the *best* parameter, see the :func:`distro.version`
method. method.
""" """
return _distroi.build_number(best) return _distro.build_number(best)
def like(): def like():
@ -350,7 +351,7 @@ def like():
`os-release man page `os-release man page
<http://www.freedesktop.org/software/systemd/man/os-release.html>`_. <http://www.freedesktop.org/software/systemd/man/os-release.html>`_.
""" """
return _distroi.like() return _distro.like()
def codename(): def codename():
@ -374,7 +375,7 @@ def codename():
* the value of the "<codename>" field of the distro release file. * the value of the "<codename>" field of the distro release file.
""" """
return _distroi.codename() return _distro.codename()
def info(pretty=False, best=False): def info(pretty=False, best=False):
@ -418,7 +419,7 @@ def info(pretty=False, best=False):
For a description of the *pretty* and *best* parameters, see the For a description of the *pretty* and *best* parameters, see the
:func:`distro.version` method. :func:`distro.version` method.
""" """
return _distroi.info(pretty, best) return _distro.info(pretty, best)
def os_release_info(): def os_release_info():
@ -428,7 +429,7 @@ def os_release_info():
See `os-release file`_ for details about these information items. See `os-release file`_ for details about these information items.
""" """
return _distroi.os_release_info() return _distro.os_release_info()
def lsb_release_info(): def lsb_release_info():
@ -439,7 +440,7 @@ def lsb_release_info():
See `lsb_release command output`_ for details about these information See `lsb_release command output`_ for details about these information
items. items.
""" """
return _distroi.lsb_release_info() return _distro.lsb_release_info()
def distro_release_info(): def distro_release_info():
@ -449,7 +450,7 @@ def distro_release_info():
See `distro release file`_ for details about these information items. See `distro release file`_ for details about these information items.
""" """
return _distroi.distro_release_info() return _distro.distro_release_info()
def os_release_attr(attribute): def os_release_attr(attribute):
@ -468,7 +469,7 @@ def os_release_attr(attribute):
See `os-release file`_ for details about these information items. See `os-release file`_ for details about these information items.
""" """
return _distroi.os_release_attr(attribute) return _distro.os_release_attr(attribute)
def lsb_release_attr(attribute): def lsb_release_attr(attribute):
@ -488,7 +489,7 @@ def lsb_release_attr(attribute):
See `lsb_release command output`_ for details about these information See `lsb_release command output`_ for details about these information
items. items.
""" """
return _distroi.lsb_release_attr(attribute) return _distro.lsb_release_attr(attribute)
def distro_release_attr(attribute): def distro_release_attr(attribute):
@ -507,7 +508,7 @@ def distro_release_attr(attribute):
See `distro release file`_ for details about these information items. See `distro release file`_ for details about these information items.
""" """
return _distroi.distro_release_attr(attribute) return _distro.distro_release_attr(attribute)
class LinuxDistribution(object): class LinuxDistribution(object):
@ -590,12 +591,14 @@ def __init__(self,
self.os_release_file = os_release_file or \ self.os_release_file = os_release_file or \
os.path.join(_UNIXCONFDIR, _OS_RELEASE_BASENAME) os.path.join(_UNIXCONFDIR, _OS_RELEASE_BASENAME)
self.distro_release_file = distro_release_file or '' # updated later self.distro_release_file = distro_release_file or '' # updated later
self._os_release_info = self._os_release_info() self._os_release_info = self._get_os_release_info()
self._lsb_release_info = self._lsb_release_info() \ self._lsb_release_info = self._get_lsb_release_info() \
if include_lsb else {} if include_lsb else {}
self._distro_release_info = self._distro_release_info() self._distro_release_info = self._get_distro_release_info()
def __repr__(self): def __repr__(self):
"""Return repr of all info
"""
return \ return \
"LinuxDistribution(" \ "LinuxDistribution(" \
"os_release_file={0!r}, " \ "os_release_file={0!r}, " \
@ -624,25 +627,25 @@ def linux_distribution(self, full_distribution_name=True):
) )
def id(self): def id(self):
""" """Return the distro ID of the Linux distribution, as a string.
Return the distro ID of the Linux distribution, as a string.
For details, see :func:`distro.id`. For details, see :func:`distro.id`.
""" """
def normalize(distro_id, table):
distro_id = distro_id.lower().replace(' ', '_')
return table.get(distro_id, distro_id)
distro_id = self.os_release_attr('id') distro_id = self.os_release_attr('id')
if distro_id: if distro_id:
distro_id = distro_id.lower().replace(' ', '_') return normalize(distro_id, NORMALIZED_OS_ID)
return NORMALIZED_OS_ID.get(distro_id, distro_id)
distro_id = self.lsb_release_attr('distributor_id') distro_id = self.lsb_release_attr('distributor_id')
if distro_id: if distro_id:
distro_id = distro_id.lower().replace(' ', '_') return normalize(distro_id, NORMALIZED_LSB_ID)
return NORMALIZED_LSB_ID.get(distro_id, distro_id)
distro_id = self.distro_release_attr('id') distro_id = self.distro_release_attr('id')
if distro_id: if distro_id:
distro_id = distro_id.lower().replace(' ', '_') return normalize(distro_id, NORMALIZED_DISTRO_ID)
return NORMALIZED_DISTRO_ID.get(distro_id, distro_id)
return '' return ''
@ -707,10 +710,10 @@ def version_parts(self, best=False):
""" """
version_str = self.version(best=best) version_str = self.version(best=best)
if version_str: if version_str:
g = re.compile(r'(\d+)\.?(\d+)?\.?(\d+)?') version_regex = re.compile(r'(\d+)\.?(\d+)?\.?(\d+)?')
m = g.match(version_str) matches = version_regex.match(version_str)
if m: if matches:
major, minor, build_number = m.groups() major, minor, build_number = matches.groups()
return major, minor or '', build_number or '' return major, minor or '', build_number or ''
return '', '', '' return '', '', ''
@ -832,7 +835,7 @@ def distro_release_attr(self, attribute):
""" """
return self._distro_release_info.get(attribute, '') return self._distro_release_info.get(attribute, '')
def _os_release_info(self): def _get_os_release_info(self):
""" """
Get the information items from the specified os-release file. Get the information items from the specified os-release file.
@ -840,8 +843,8 @@ def _os_release_info(self):
A dictionary containing all information items. A dictionary containing all information items.
""" """
if os.path.isfile(self.os_release_file): if os.path.isfile(self.os_release_file):
with open(self.os_release_file, 'r') as f: with open(self.os_release_file) as release_file:
return self._parse_os_release_content(f) return self._parse_os_release_content(release_file)
return {} return {}
@staticmethod @staticmethod
@ -904,7 +907,7 @@ def _parse_os_release_content(lines):
pass pass
return props return props
def _lsb_release_info(self): def _get_lsb_release_info(self):
""" """
Get the information items from the lsb_release command output. Get the information items from the lsb_release command output.
@ -912,26 +915,26 @@ def _lsb_release_info(self):
A dictionary containing all information items. A dictionary containing all information items.
""" """
cmd = 'lsb_release -a' cmd = 'lsb_release -a'
p = subprocess.Popen( process = subprocess.Popen(
cmd, cmd,
shell=True, shell=True,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
out, err = p.communicate() stdout, stderr = process.communicate()
out, err = out.decode('ascii'), err.decode('ascii') stdout, stderr = stdout.decode('utf-8'), stderr.decode('utf-8')
rc = p.returncode code = process.returncode
if rc == 0: if code == 0:
content = out.splitlines() content = stdout.splitlines()
return self._parse_lsb_release_content(content) return self._parse_lsb_release_content(content)
elif rc == 127: # Command not found elif code == 127: # Command not found
return {} return {}
else: else:
if sys.version_info[:2] >= (3, 5): if sys.version_info[:2] >= (3, 5):
raise subprocess.CalledProcessError(rc, cmd, out, err) raise subprocess.CalledProcessError(code, cmd, stdout, stderr)
elif sys.version_info[:2] >= (2, 7): elif sys.version_info[:2] >= (2, 7):
raise subprocess.CalledProcessError(rc, cmd, out) raise subprocess.CalledProcessError(code, cmd, stdout)
elif sys.version_info[:2] == (2, 6): elif sys.version_info[:2] == (2, 6):
raise subprocess.CalledProcessError(rc, cmd) raise subprocess.CalledProcessError(code, cmd)
@staticmethod @staticmethod
def _parse_lsb_release_content(lines): def _parse_lsb_release_content(lines):
@ -949,8 +952,7 @@ def _parse_lsb_release_content(lines):
""" """
props = {} props = {}
for line in lines: for line in lines:
if isinstance(line, bytes): line = line.decode('utf-8') if isinstance(line, bytes) else line
line = line.decode('utf-8')
kv = line.strip('\n').split(':', 1) kv = line.strip('\n').split(':', 1)
if len(kv) != 2: if len(kv) != 2:
# Ignore lines without colon. # Ignore lines without colon.
@ -959,7 +961,7 @@ def _parse_lsb_release_content(lines):
props.update({k.replace(' ', '_').lower(): v.strip()}) props.update({k.replace(' ', '_').lower(): v.strip()})
return props return props
def _distro_release_info(self): def _get_distro_release_info(self):
""" """
Get the information items from the specified distro release file. Get the information items from the specified distro release file.
@ -1012,7 +1014,7 @@ def _parse_distro_release_file(self, filepath):
A dictionary containing all information items. A dictionary containing all information items.
""" """
if os.path.isfile(filepath): if os.path.isfile(filepath):
with open(filepath, 'r') as fp: with open(filepath) as fp:
# Only parse the first line. For instance, on SLES there # Only parse the first line. For instance, on SLES there
# are multiple lines. We don't want them... # are multiple lines. We don't want them...
return self._parse_distro_release_content(fp.readline()) return self._parse_distro_release_content(fp.readline())
@ -1032,18 +1034,48 @@ def _parse_distro_release_content(line):
""" """
if isinstance(line, bytes): if isinstance(line, bytes):
line = line.decode('utf-8') line = line.decode('utf-8')
m = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match( matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(
line.strip()[::-1]) line.strip()[::-1])
distro_info = {} distro_info = {}
if m: if matches:
distro_info['name'] = m.group(3)[::-1] # regexp ensures non-None # regexp ensures non-None
if m.group(2): distro_info['name'] = matches.group(3)[::-1]
distro_info['version_id'] = m.group(2)[::-1] if matches.group(2):
if m.group(1): distro_info['version_id'] = matches.group(2)[::-1]
distro_info['codename'] = m.group(1)[::-1] if matches.group(1):
distro_info['codename'] = matches.group(1)[::-1]
elif line: elif line:
distro_info['name'] = line.strip() distro_info['name'] = line.strip()
return distro_info return distro_info
_distroi = LinuxDistribution() _distro = LinuxDistribution()
def main():
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler(sys.stdout))
parser = argparse.ArgumentParser(description="Linux distro info tool")
parser.add_argument(
'--json',
'-j',
help="Output in machine readable format",
action="store_true")
args = parser.parse_args()
if args.json:
logger.info(json.dumps(info(), indent=4, sort_keys=True))
else:
logger.info('Name: %s', name(pretty=True))
distribution_version = version(pretty=True)
if distribution_version:
logger.info('Version: %s', distribution_version)
distribution_codename = codename()
if distribution_codename:
logger.info('Codename: %s', distribution_codename)
if __name__ == '__main__':
main()