summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/external/distro.py152
1 files changed, 92 insertions, 60 deletions
diff --git a/lib/spack/external/distro.py b/lib/spack/external/distro.py
index 091bba3db8..ca25339ec9 100644
--- a/lib/spack/external/distro.py
+++ b/lib/spack/external/distro.py
@@ -31,14 +31,16 @@ more information.
import os
import re
import sys
+import json
import shlex
+import logging
+import argparse
import subprocess
if not sys.platform.startswith('linux'):
raise ImportError('Unsupported platform: {0}'.format(sys.platform))
-
_UNIXCONFDIR = '/etc'
_OS_RELEASE_BASENAME = 'os-release'
@@ -75,7 +77,6 @@ NORMALIZED_DISTRO_ID = {
'redhat': 'rhel', # RHEL 6.x, 7.x
}
-
# Pattern for content of distro release file (reversed)
_DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile(
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
for a number of popular Linux distributions.
"""
- return _distroi.linux_distribution(full_distribution_name)
+ return _distro.linux_distribution(full_distribution_name)
def id():
@@ -194,7 +195,7 @@ def id():
command, with ID values that differ from what was previously determined
from the distro release file name.
"""
- return _distroi.id()
+ return _distro.id()
def name(pretty=False):
@@ -233,7 +234,7 @@ def name(pretty=False):
with the value of the pretty version ("<version_id>" and "<codename>"
fields) of the distro release file, if available.
"""
- return _distroi.name(pretty)
+ return _distro.name(pretty)
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
files.
"""
- return _distroi.version(pretty, best)
+ return _distro.version(pretty, best)
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`
method.
"""
- return _distroi.version_parts(best)
+ return _distro.version_parts(best)
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`
method.
"""
- return _distroi.major_version(best)
+ return _distro.major_version(best)
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`
method.
"""
- return _distroi.minor_version(best)
+ return _distro.minor_version(best)
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`
method.
"""
- return _distroi.build_number(best)
+ return _distro.build_number(best)
def like():
@@ -350,7 +351,7 @@ def like():
`os-release man page
<http://www.freedesktop.org/software/systemd/man/os-release.html>`_.
"""
- return _distroi.like()
+ return _distro.like()
def codename():
@@ -374,7 +375,7 @@ def codename():
* the value of the "<codename>" field of the distro release file.
"""
- return _distroi.codename()
+ return _distro.codename()
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
:func:`distro.version` method.
"""
- return _distroi.info(pretty, best)
+ return _distro.info(pretty, best)
def os_release_info():
@@ -428,7 +429,7 @@ def os_release_info():
See `os-release file`_ for details about these information items.
"""
- return _distroi.os_release_info()
+ return _distro.os_release_info()
def lsb_release_info():
@@ -439,7 +440,7 @@ def lsb_release_info():
See `lsb_release command output`_ for details about these information
items.
"""
- return _distroi.lsb_release_info()
+ return _distro.lsb_release_info()
def distro_release_info():
@@ -449,7 +450,7 @@ def distro_release_info():
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):
@@ -468,7 +469,7 @@ def os_release_attr(attribute):
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):
@@ -488,7 +489,7 @@ def lsb_release_attr(attribute):
See `lsb_release command output`_ for details about these information
items.
"""
- return _distroi.lsb_release_attr(attribute)
+ return _distro.lsb_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.
"""
- return _distroi.distro_release_attr(attribute)
+ return _distro.distro_release_attr(attribute)
class LinuxDistribution(object):
@@ -590,12 +591,14 @@ class LinuxDistribution(object):
self.os_release_file = os_release_file or \
os.path.join(_UNIXCONFDIR, _OS_RELEASE_BASENAME)
self.distro_release_file = distro_release_file or '' # updated later
- self._os_release_info = self._os_release_info()
- self._lsb_release_info = self._lsb_release_info() \
+ self._os_release_info = self._get_os_release_info()
+ self._lsb_release_info = self._get_lsb_release_info() \
if include_lsb else {}
- self._distro_release_info = self._distro_release_info()
+ self._distro_release_info = self._get_distro_release_info()
def __repr__(self):
+ """Return repr of all info
+ """
return \
"LinuxDistribution(" \
"os_release_file={0!r}, " \
@@ -624,25 +627,25 @@ class LinuxDistribution(object):
)
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`.
"""
+ 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')
if distro_id:
- distro_id = distro_id.lower().replace(' ', '_')
- return NORMALIZED_OS_ID.get(distro_id, distro_id)
+ return normalize(distro_id, NORMALIZED_OS_ID)
distro_id = self.lsb_release_attr('distributor_id')
if distro_id:
- distro_id = distro_id.lower().replace(' ', '_')
- return NORMALIZED_LSB_ID.get(distro_id, distro_id)
+ return normalize(distro_id, NORMALIZED_LSB_ID)
distro_id = self.distro_release_attr('id')
if distro_id:
- distro_id = distro_id.lower().replace(' ', '_')
- return NORMALIZED_DISTRO_ID.get(distro_id, distro_id)
+ return normalize(distro_id, NORMALIZED_DISTRO_ID)
return ''
@@ -707,10 +710,10 @@ class LinuxDistribution(object):
"""
version_str = self.version(best=best)
if version_str:
- g = re.compile(r'(\d+)\.?(\d+)?\.?(\d+)?')
- m = g.match(version_str)
- if m:
- major, minor, build_number = m.groups()
+ version_regex = re.compile(r'(\d+)\.?(\d+)?\.?(\d+)?')
+ matches = version_regex.match(version_str)
+ if matches:
+ major, minor, build_number = matches.groups()
return major, minor or '', build_number or ''
return '', '', ''
@@ -832,7 +835,7 @@ class LinuxDistribution(object):
"""
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.
@@ -840,8 +843,8 @@ class LinuxDistribution(object):
A dictionary containing all information items.
"""
if os.path.isfile(self.os_release_file):
- with open(self.os_release_file, 'r') as f:
- return self._parse_os_release_content(f)
+ with open(self.os_release_file) as release_file:
+ return self._parse_os_release_content(release_file)
return {}
@staticmethod
@@ -904,7 +907,7 @@ class LinuxDistribution(object):
pass
return props
- def _lsb_release_info(self):
+ def _get_lsb_release_info(self):
"""
Get the information items from the lsb_release command output.
@@ -912,26 +915,26 @@ class LinuxDistribution(object):
A dictionary containing all information items.
"""
cmd = 'lsb_release -a'
- p = subprocess.Popen(
+ process = subprocess.Popen(
cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
- out, err = p.communicate()
- out, err = out.decode('ascii'), err.decode('ascii')
- rc = p.returncode
- if rc == 0:
- content = out.splitlines()
+ stdout, stderr = process.communicate()
+ stdout, stderr = stdout.decode('utf-8'), stderr.decode('utf-8')
+ code = process.returncode
+ if code == 0:
+ content = stdout.splitlines()
return self._parse_lsb_release_content(content)
- elif rc == 127: # Command not found
+ elif code == 127: # Command not found
return {}
else:
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):
- raise subprocess.CalledProcessError(rc, cmd, out)
+ raise subprocess.CalledProcessError(code, cmd, stdout)
elif sys.version_info[:2] == (2, 6):
- raise subprocess.CalledProcessError(rc, cmd)
+ raise subprocess.CalledProcessError(code, cmd)
@staticmethod
def _parse_lsb_release_content(lines):
@@ -949,8 +952,7 @@ class LinuxDistribution(object):
"""
props = {}
for line in lines:
- if isinstance(line, bytes):
- line = line.decode('utf-8')
+ line = line.decode('utf-8') if isinstance(line, bytes) else line
kv = line.strip('\n').split(':', 1)
if len(kv) != 2:
# Ignore lines without colon.
@@ -959,7 +961,7 @@ class LinuxDistribution(object):
props.update({k.replace(' ', '_').lower(): v.strip()})
return props
- def _distro_release_info(self):
+ def _get_distro_release_info(self):
"""
Get the information items from the specified distro release file.
@@ -1012,7 +1014,7 @@ class LinuxDistribution(object):
A dictionary containing all information items.
"""
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
# are multiple lines. We don't want them...
return self._parse_distro_release_content(fp.readline())
@@ -1032,18 +1034,48 @@ class LinuxDistribution(object):
"""
if isinstance(line, bytes):
line = line.decode('utf-8')
- m = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(
+ matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(
line.strip()[::-1])
distro_info = {}
- if m:
- distro_info['name'] = m.group(3)[::-1] # regexp ensures non-None
- if m.group(2):
- distro_info['version_id'] = m.group(2)[::-1]
- if m.group(1):
- distro_info['codename'] = m.group(1)[::-1]
+ if matches:
+ # regexp ensures non-None
+ distro_info['name'] = matches.group(3)[::-1]
+ if matches.group(2):
+ distro_info['version_id'] = matches.group(2)[::-1]
+ if matches.group(1):
+ distro_info['codename'] = matches.group(1)[::-1]
elif line:
distro_info['name'] = line.strip()
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()