Update vendored distro (#79227)
Commit bb35d41
in branch python2.7-support from 2022-10-10:
https://github.com/python-distro/distro/commit/bb35d41
This commit is contained in:
parent
505b29b2a9
commit
f79a54ae22
|
@ -0,0 +1,2 @@
|
|||
minor_changes:
|
||||
- updated the vendored distro library to upstream version (https://github.com/ansible/ansible/pull/79227)
|
|
@ -31,6 +31,8 @@ access to OS distribution information is needed. See `Python issue 1322
|
|||
<https://bugs.python.org/issue1322>`_ for more information.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
@ -136,56 +138,6 @@ _DISTRO_RELEASE_IGNORE_BASENAMES = (
|
|||
)
|
||||
|
||||
|
||||
#
|
||||
# Python 2.6 does not have subprocess.check_output so replicate it here
|
||||
#
|
||||
def _my_check_output(*popenargs, **kwargs):
|
||||
r"""Run command with arguments and return its output as a byte string.
|
||||
|
||||
If the exit code was non-zero it raises a CalledProcessError. The
|
||||
CalledProcessError object will have the return code in the returncode
|
||||
attribute and output in the output attribute.
|
||||
|
||||
The arguments are the same as for the Popen constructor. Example:
|
||||
|
||||
>>> check_output(["ls", "-l", "/dev/null"])
|
||||
'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
|
||||
|
||||
The stdout argument is not allowed as it is used internally.
|
||||
To capture standard error in the result, use stderr=STDOUT.
|
||||
|
||||
>>> check_output(["/bin/sh", "-c",
|
||||
... "ls -l non_existent_file ; exit 0"],
|
||||
... stderr=STDOUT)
|
||||
'ls: non_existent_file: No such file or directory\n'
|
||||
|
||||
This is a backport of Python-2.7's check output to Python-2.6
|
||||
"""
|
||||
if 'stdout' in kwargs:
|
||||
raise ValueError(
|
||||
'stdout argument not allowed, it will be overridden.'
|
||||
)
|
||||
process = subprocess.Popen(
|
||||
stdout=subprocess.PIPE, *popenargs, **kwargs
|
||||
)
|
||||
output, unused_err = process.communicate()
|
||||
retcode = process.poll()
|
||||
if retcode:
|
||||
cmd = kwargs.get("args")
|
||||
if cmd is None:
|
||||
cmd = popenargs[0]
|
||||
# Deviation from Python-2.7: Python-2.6's CalledProcessError does not
|
||||
# have an argument for the stdout so simply omit it.
|
||||
raise subprocess.CalledProcessError(retcode, cmd)
|
||||
return output
|
||||
|
||||
|
||||
try:
|
||||
_check_output = subprocess.check_output
|
||||
except AttributeError:
|
||||
_check_output = _my_check_output
|
||||
|
||||
|
||||
def linux_distribution(full_distribution_name=True):
|
||||
# type: (bool) -> Tuple[str, str, str]
|
||||
"""
|
||||
|
@ -204,7 +156,8 @@ def linux_distribution(full_distribution_name=True):
|
|||
|
||||
* ``version``: The result of :func:`distro.version`.
|
||||
|
||||
* ``codename``: The result of :func:`distro.codename`.
|
||||
* ``codename``: The extra item (usually in parentheses) after the
|
||||
os-release version number, or the result of :func:`distro.codename`.
|
||||
|
||||
The interface of this function is compatible with the original
|
||||
:py:func:`platform.linux_distribution` function, supporting a subset of
|
||||
|
@ -251,8 +204,9 @@ def id():
|
|||
"fedora" Fedora
|
||||
"sles" SUSE Linux Enterprise Server
|
||||
"opensuse" openSUSE
|
||||
"amazon" Amazon Linux
|
||||
"amzn" Amazon Linux
|
||||
"arch" Arch Linux
|
||||
"buildroot" Buildroot
|
||||
"cloudlinux" CloudLinux OS
|
||||
"exherbo" Exherbo Linux
|
||||
"gentoo" GenToo Linux
|
||||
|
@ -272,6 +226,8 @@ def id():
|
|||
"netbsd" NetBSD
|
||||
"freebsd" FreeBSD
|
||||
"midnightbsd" MidnightBSD
|
||||
"rocky" Rocky Linux
|
||||
"guix" Guix System
|
||||
============== =========================================
|
||||
|
||||
If you have a need to get distros for reliable IDs added into this set,
|
||||
|
@ -366,6 +322,10 @@ def version(pretty=False, best=False):
|
|||
sources in a fixed priority order does not always yield the most precise
|
||||
version (e.g. for Debian 8.2, or CentOS 7.1).
|
||||
|
||||
Some other distributions may not provide this kind of information. In these
|
||||
cases, an empty string would be returned. This behavior can be observed
|
||||
with rolling releases distributions (e.g. Arch Linux).
|
||||
|
||||
The *best* parameter can be used to control the approach for the returned
|
||||
version:
|
||||
|
||||
|
@ -681,7 +641,7 @@ except ImportError:
|
|||
|
||||
def __get__(self, obj, owner):
|
||||
# type: (Any, Type[Any]) -> Any
|
||||
assert obj is not None, "call {0} on an instance".format(self._fname)
|
||||
assert obj is not None, "call {} on an instance".format(self._fname)
|
||||
ret = obj.__dict__[self._fname] = self._f(obj)
|
||||
return ret
|
||||
|
||||
|
@ -776,10 +736,6 @@ class LinuxDistribution(object):
|
|||
* :py:exc:`IOError`: Some I/O issue with an os-release file or distro
|
||||
release file.
|
||||
|
||||
* :py:exc:`subprocess.CalledProcessError`: The lsb_release command had
|
||||
some issue (other than not being available in the program execution
|
||||
path).
|
||||
|
||||
* :py:exc:`UnicodeError`: A data source has unexpected characters or
|
||||
uses an unexpected encoding.
|
||||
"""
|
||||
|
@ -837,7 +793,7 @@ class LinuxDistribution(object):
|
|||
return (
|
||||
self.name() if full_distribution_name else self.id(),
|
||||
self.version(),
|
||||
self.codename(),
|
||||
self._os_release_info.get("release_codename") or self.codename(),
|
||||
)
|
||||
|
||||
def id(self):
|
||||
|
@ -913,6 +869,9 @@ class LinuxDistribution(object):
|
|||
).get("version_id", ""),
|
||||
self.uname_attr("release"),
|
||||
]
|
||||
if self.id() == "debian" or "debian" in self.like().split():
|
||||
# On Debian-like, add debian_version file content to candidates list.
|
||||
versions.append(self._debian_version)
|
||||
version = ""
|
||||
if best:
|
||||
# This algorithm uses the last version in priority order that has
|
||||
|
@ -1155,12 +1114,17 @@ class LinuxDistribution(object):
|
|||
# stripped, etc.), so the tokens are now either:
|
||||
# * variable assignments: var=value
|
||||
# * commands or their arguments (not allowed in os-release)
|
||||
# Ignore any tokens that are not variable assignments
|
||||
if "=" in token:
|
||||
k, v = token.split("=", 1)
|
||||
props[k.lower()] = v
|
||||
else:
|
||||
# Ignore any tokens that are not variable assignments
|
||||
pass
|
||||
|
||||
if "version" in props:
|
||||
# extract release codename (if any) from version attribute
|
||||
match = re.search(r"\((\D+)\)|,\s*(\D+)", props["version"])
|
||||
if match:
|
||||
release_codename = match.group(1) or match.group(2)
|
||||
props["codename"] = props["release_codename"] = release_codename
|
||||
|
||||
if "version_codename" in props:
|
||||
# os-release added a version_codename field. Use that in
|
||||
|
@ -1171,16 +1135,6 @@ class LinuxDistribution(object):
|
|||
elif "ubuntu_codename" in props:
|
||||
# Same as above but a non-standard field name used on older Ubuntus
|
||||
props["codename"] = props["ubuntu_codename"]
|
||||
elif "version" in props:
|
||||
# If there is no version_codename, parse it from the version
|
||||
match = re.search(r"(\(\D+\))|,(\s+)?\D+", props["version"])
|
||||
if match:
|
||||
codename = match.group()
|
||||
codename = codename.strip("()")
|
||||
codename = codename.strip(",")
|
||||
codename = codename.strip()
|
||||
# codename appears within paranthese.
|
||||
props["codename"] = codename
|
||||
|
||||
return props
|
||||
|
||||
|
@ -1198,7 +1152,7 @@ class LinuxDistribution(object):
|
|||
with open(os.devnull, "wb") as devnull:
|
||||
try:
|
||||
cmd = ("lsb_release", "-a")
|
||||
stdout = _check_output(cmd, stderr=devnull)
|
||||
stdout = subprocess.check_output(cmd, stderr=devnull)
|
||||
# Command not found or lsb_release returned error
|
||||
except (OSError, subprocess.CalledProcessError):
|
||||
return {}
|
||||
|
@ -1233,18 +1187,31 @@ class LinuxDistribution(object):
|
|||
@cached_property
|
||||
def _uname_info(self):
|
||||
# type: () -> Dict[str, str]
|
||||
if not self.include_uname:
|
||||
return {}
|
||||
with open(os.devnull, "wb") as devnull:
|
||||
try:
|
||||
cmd = ("uname", "-rs")
|
||||
stdout = _check_output(cmd, stderr=devnull)
|
||||
stdout = subprocess.check_output(cmd, stderr=devnull)
|
||||
except OSError:
|
||||
return {}
|
||||
content = self._to_str(stdout).splitlines()
|
||||
return self._parse_uname_content(content)
|
||||
|
||||
@cached_property
|
||||
def _debian_version(self):
|
||||
# type: () -> str
|
||||
try:
|
||||
with open(os.path.join(self.etc_dir, "debian_version")) as fp:
|
||||
return fp.readline().rstrip()
|
||||
except (OSError, IOError):
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def _parse_uname_content(lines):
|
||||
# type: (Sequence[str]) -> Dict[str, str]
|
||||
if not lines:
|
||||
return {}
|
||||
props = {}
|
||||
match = re.search(r"^([^\s]+)\s+([\d\.]+)", lines[0].strip())
|
||||
if match:
|
||||
|
@ -1270,7 +1237,7 @@ class LinuxDistribution(object):
|
|||
if isinstance(text, bytes):
|
||||
return text.decode(encoding)
|
||||
else:
|
||||
if isinstance(text, unicode): # noqa pylint: disable=undefined-variable
|
||||
if isinstance(text, unicode): # noqa
|
||||
return text.encode(encoding)
|
||||
|
||||
return text
|
||||
|
@ -1325,6 +1292,7 @@ class LinuxDistribution(object):
|
|||
"manjaro-release",
|
||||
"oracle-release",
|
||||
"redhat-release",
|
||||
"rocky-release",
|
||||
"sl-release",
|
||||
"slackware-version",
|
||||
]
|
||||
|
@ -1403,13 +1371,36 @@ def main():
|
|||
logger.setLevel(logging.DEBUG)
|
||||
logger.addHandler(logging.StreamHandler(sys.stdout))
|
||||
|
||||
dist = _distro
|
||||
parser = argparse.ArgumentParser(description="OS distro info tool")
|
||||
parser.add_argument(
|
||||
"--json", "-j", help="Output in machine readable format", action="store_true"
|
||||
)
|
||||
|
||||
logger.info("Name: %s", dist.name(pretty=True))
|
||||
distribution_version = dist.version(pretty=True)
|
||||
logger.info("Version: %s", distribution_version)
|
||||
distribution_codename = dist.codename()
|
||||
logger.info("Codename: %s", distribution_codename)
|
||||
parser.add_argument(
|
||||
"--root-dir",
|
||||
"-r",
|
||||
type=str,
|
||||
dest="root_dir",
|
||||
help="Path to the root filesystem directory (defaults to /)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.root_dir:
|
||||
dist = LinuxDistribution(
|
||||
include_lsb=False, include_uname=False, root_dir=args.root_dir
|
||||
)
|
||||
else:
|
||||
dist = _distro
|
||||
|
||||
if args.json:
|
||||
logger.info(json.dumps(dist.info(), indent=4, sort_keys=True))
|
||||
else:
|
||||
logger.info("Name: %s", dist.name(pretty=True))
|
||||
distribution_version = dist.version(pretty=True)
|
||||
logger.info("Version: %s", distribution_version)
|
||||
distribution_codename = dist.codename()
|
||||
logger.info("Codename: %s", distribution_codename)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -72,8 +72,10 @@ lib/ansible/module_utils/compat/selinux.py import-3.9!skip # pass/fail depends o
|
|||
lib/ansible/module_utils/distro/_distro.py future-import-boilerplate # ignore bundled
|
||||
lib/ansible/module_utils/distro/_distro.py metaclass-boilerplate # ignore bundled
|
||||
lib/ansible/module_utils/distro/_distro.py no-assert
|
||||
lib/ansible/module_utils/distro/_distro.py pylint:using-constant-test # bundled code we don't want to modify
|
||||
lib/ansible/module_utils/distro/_distro.py pep8!skip # bundled code we don't want to modify
|
||||
lib/ansible/module_utils/distro/_distro.py pylint:ansible-format-automatic-specification # ignore bundled
|
||||
lib/ansible/module_utils/distro/_distro.py pylint:undefined-variable # ignore bundled
|
||||
lib/ansible/module_utils/distro/_distro.py pylint:using-constant-test # bundled code we don't want to modify
|
||||
lib/ansible/module_utils/distro/__init__.py empty-init # breaks namespacing, bundled, do not override
|
||||
lib/ansible/module_utils/facts/__init__.py empty-init # breaks namespacing, deprecate and eventually remove
|
||||
lib/ansible/module_utils/facts/network/linux.py pylint:disallowed-name
|
||||
|
|
Loading…
Reference in New Issue