# HG changeset patch # User Edwin Takahashi # Date 1572468170 0 # Node ID d2d9fe01fc33af4538940e833a6696d973ebea74 # Parent eddb9fcaaa4bd4fdb4e32024f92f969abfe92f58 Bug 1212502 - Switch mozinfo to using the 'distro' package to get linux distribution info r=ahal,KWierso Differential Revision: https://phabricator.services.mozilla.com/D49366 diff --git a/build/virtualenv_packages.txt b/build/virtualenv_packages.txt --- a/build/virtualenv_packages.txt +++ b/build/virtualenv_packages.txt @@ -10,16 +10,17 @@ mozilla.pth:third_party/python/atomicwri mozilla.pth:third_party/python/attrs/src python2:mozilla.pth:third_party/python/backports mozilla.pth:third_party/python/biplist mozilla.pth:third_party/python/blessings mozilla.pth:third_party/python/Click mozilla.pth:third_party/python/compare-locales mozilla.pth:third_party/python/configobj mozilla.pth:third_party/python/cram +mozilla.pth:third_party/python/distro mozilla.pth:third_party/python/dlmanager mozilla.pth:third_party/python/enum34 mozilla.pth:third_party/python/fluent mozilla.pth:third_party/python/funcsigs python2:mozilla.pth:third_party/python/futures mozilla.pth:third_party/python/mohawk mozilla.pth:third_party/python/more-itertools mozilla.pth:third_party/python/mozilla-version diff --git a/python/mozbuild/mozbuild/action/test_archive.py b/python/mozbuild/mozbuild/action/test_archive.py --- a/python/mozbuild/mozbuild/action/test_archive.py +++ b/python/mozbuild/mozbuild/action/test_archive.py @@ -245,16 +245,22 @@ ARCHIVE_FILES = { }, { 'source': buildconfig.topsrcdir, 'base': 'third_party/python/six', 'pattern': '**', 'dest': 'tools/six', }, { + 'source': buildconfig.topsrcdir, + 'base': 'third_party/python/distro', + 'pattern': '**', + 'dest': 'tools/distro', + }, + { 'source': buildconfig.topobjdir, 'base': '', 'pattern': 'mozinfo.json', }, { 'source': buildconfig.topobjdir, 'base': 'dist/bin', 'patterns': [ @@ -431,16 +437,22 @@ ARCHIVE_FILES = { 'dest': 'mozharness', }, { 'source': buildconfig.topsrcdir, 'base': 'third_party/python/six', 'pattern': 'six.py', 'dest': 'mozharness', }, + { + 'source': buildconfig.topsrcdir, + 'base': 'third_party/python/distro', + 'pattern': 'distro.py', + 'dest': 'mozharness', + }, ], 'reftest': [ { 'source': buildconfig.topobjdir, 'base': '_tests', 'pattern': 'reftest/**', }, { diff --git a/testing/mozbase/mozinfo/mozinfo/mozinfo.py b/testing/mozbase/mozinfo/mozinfo/mozinfo.py --- a/testing/mozbase/mozinfo/mozinfo/mozinfo.py +++ b/testing/mozbase/mozinfo/mozinfo/mozinfo.py @@ -9,16 +9,17 @@ # information and having behaviour depend on it from __future__ import absolute_import, print_function import os import platform import re import sys + from .string_version import StringVersion from ctypes.util import find_library # keep a copy of the os module since updating globals overrides this _os = os class unknown(object): @@ -93,35 +94,45 @@ if system in ["Microsoft", "Windows"]: version = "%d.%d.%d" % (major, minor, build_number) os_version = "%d.%d" % (major, minor) elif system.startswith(('MINGW', 'MSYS_NT')): # windows/mingw python build (msys) info['os'] = 'win' os_version = version = unknown elif system == "Linux": - if hasattr(platform, "linux_distribution"): - (distro, os_version, codename) = platform.linux_distribution() + # Only attempt to import distro for Linux. + # https://github.com/nir0s/distro/issues/177 + try: + import distro + except ImportError: + pass + # First use distro package, then fall back to platform. + # This will only until Mozilla upgrades python to 3.8. + if hasattr(distro, "linux_distribution"): + (distribution, os_version, codename) = distro.linux_distribution() + elif hasattr(platform, "linux_distribution"): + (distribution, os_version, codename) = platform.linux_distribution() else: - (distro, os_version, codename) = platform.dist() + (distribution, os_version, codename) = platform.dist() if not processor: processor = machine - version = "%s %s" % (distro, os_version) + version = "%s %s" % (distribution, os_version) # Bug in Python 2's `platform` library: # It will return a triple of empty strings if the distribution is not supported. # It works on Python 3. If we don't have an OS version, # the unit tests fail to run. - if not distro and not os_version and not codename: - distro = 'lfs' + if not distribution and not os_version and not codename: + distribution = 'lfs' version = release os_version = release info['os'] = 'linux' - info['linux_distro'] = distro + info['linux_distro'] = distribution elif system in ['DragonFly', 'FreeBSD', 'NetBSD', 'OpenBSD']: info['os'] = 'bsd' version = os_version = sys.platform elif system == "Darwin": (release, versioninfo, machine) = platform.mac_ver() version = "OS X %s" % release versionNums = release.split('.')[:2] os_version = "%s.%s" % (versionNums[0], versionNums[1]) diff --git a/testing/mozbase/mozinfo/setup.py b/testing/mozbase/mozinfo/setup.py --- a/testing/mozbase/mozinfo/setup.py +++ b/testing/mozbase/mozinfo/setup.py @@ -4,17 +4,20 @@ from __future__ import absolute_import from setuptools import setup PACKAGE_VERSION = "1.1.0" # dependencies -deps = ["mozfile >= 0.12"] +deps = [ + "distro == 1.4.0", + "mozfile >= 0.12", +] setup( name="mozinfo", version=PACKAGE_VERSION, description="Library to get system information for use in Mozilla testing", long_description="see https://firefox-source-docs.mozilla.org/mozbase/index.html", classifiers=[ "Programming Language :: Python :: 2.7", diff --git a/testing/mozharness/tox.ini b/testing/mozharness/tox.ini --- a/testing/mozharness/tox.ini +++ b/testing/mozharness/tox.ini @@ -1,14 +1,15 @@ [tox] envlist = py27-hg4.3 [base] deps = coverage + distro nose rednose {toxinidir}/../mozbase/mozlog mozbase = {toxinidir}/../mozbase/ [testenv] basepython = python2.7 diff --git a/third_party/python/distro/CHANGELOG.md b/third_party/python/distro/CHANGELOG.md new file mode 100644 --- /dev/null +++ b/third_party/python/distro/CHANGELOG.md @@ -0,0 +1,147 @@ +## 1.4.0 (2019.2.4) + +BACKWARD COMPATIBILITY: +* Prefer the VERSION_CODENAME field of os-release to parsing it from VERSION [[#230](https://github.com/nir0s/distro/pull/230)] + +BUG FIXES: +* Return _uname_info from the uname_info() method [[#233](https://github.com/nir0s/distro/pull/233)] +* Fixed CloudLinux id discovery [[#234](https://github.com/nir0s/distro/pull/234)] +* Update Oracle matching [[#224](https://github.com/nir0s/distro/pull/224)] + +DOCS: +* Update Fedora package link [[#225](https://github.com/nir0s/distro/pull/225)] +* Distro is the recommended replacement for platform.linux_distribution [[#220](https://github.com/nir0s/distro/pull/220)] + +RELEASE: +* Use Markdown for long description in setup.py [[#219](https://github.com/nir0s/distro/pull/219)] + +Additionally, The Python2.6 branch was fixed and rebased on top of master. It is now passing all tests. Thanks [abadger](https://github.com/abadger)! + +## 1.3.0 (2018.05.09) + +ENHANCEMENTS: +* Added support for OpenBSD, FreeBSD, and NetBSD [[#207](https://github.com/nir0s/distro/issues/207)] + +TESTS: +* Add test for Kali Linux Rolling [[#214](https://github.com/nir0s/distro/issues/214)] + +DOCS: +* Update docs with regards to #207 [[#209](https://github.com/nir0s/distro/issues/209)] +* Add Ansible reference implementation and fix arch-linux link [[#213](https://github.com/nir0s/distro/issues/213)] +* Add facter reference implementation [[#213](https://github.com/nir0s/distro/issues/213)] + +## 1.2.0 (2017.12.24) + +BACKWARD COMPATIBILITY: +* Don't raise ImportError on non-linux platforms [[#202](https://github.com/nir0s/distro/issues/202)] + +ENHANCEMENTS: +* Lazily load the LinuxDistribution data [[#201](https://github.com/nir0s/distro/issues/201)] + +BUG FIXES: +* Stdout of shell should be decoded with sys.getfilesystemencoding() [[#203](https://github.com/nir0s/distro/issues/203)] + +TESTS: +* Explicitly set Python versions on Travis for flake [[#204](https://github.com/nir0s/distro/issues/204)] + + +## 1.1.0 (2017.11.28) + +BACKWARD COMPATIBILITY: +* Drop python3.3 support [[#199](https://github.com/nir0s/distro/issues/199)] +* Remove Official Python26 support [[#195](https://github.com/nir0s/distro/issues/195)] + +TESTS: +* Add MandrivaLinux test case [[#181](https://github.com/nir0s/distro/issues/181)] +* Add test cases for CloudLinux 5, 6, and 7 [[#180](https://github.com/nir0s/distro/issues/180)] + +RELEASE: +* Modify MANIFEST to include resources for tests and docs in source tarballs [[97c91a1](97c91a1)] + +## 1.0.4 (2017.04.01) + +BUG FIXES: +* Guess common *-release files if /etc not readable [[#175](https://github.com/nir0s/distro/issues/175)] + +## 1.0.3 (2017.03.19) + +ENHANCEMENTS: +* Show keys for empty values when running distro from the CLI [[#160](https://github.com/nir0s/distro/issues/160)] +* Add manual mapping for `redhatenterpriseserver` (previously only redhatenterpriseworkstation was mapped) [[#148](https://github.com/nir0s/distro/issues/148)] +* Race condition in `_parse_distro_release_file` [[#163](https://github.com/nir0s/distro/issues/163)] + +TESTS: +* Add RHEL5 test case [[#165](https://github.com/nir0s/distro/issues/165)] +* Add OpenELEC test case [[#166](https://github.com/nir0s/distro/issues/166)] +* Replace nose with pytest [[#158](https://github.com/nir0s/distro/issues/158)] + +RELEASE: +* Update classifiers +* Update supported Python versions (with py36) + +## 1.0.2 (2017.01.12) + +TESTS: +* Test on py33, py36 and py3 based flake8 + +RELEASE: +* Add MANIFEST file (which also includes the LICENSE as part of Issue [[#139](https://github.com/nir0s/distro/issues/139)]) +* Default to releasing using Twine [[#121](https://github.com/nir0s/distro/issues/121)] +* Add setup.cfg file [[#145](https://github.com/nir0s/distro/issues/145)] +* Update license in setup.py + +## 1.0.1 (2016-11-03) + +ENHANCEMENTS: +* Prettify distro -j's output and add more elaborate docs [[#147](https://github.com/nir0s/distro/issues/147)] +* Decode output of `lsb_release` as utf-8 [[#144](https://github.com/nir0s/distro/issues/144)] +* Logger now uses `message %s, string` form to not-evaulate log messages if unnecessary [[#145](https://github.com/nir0s/distro/issues/145)] + +TESTS: +* Increase code-coverage [[#146](https://github.com/nir0s/distro/issues/146)] +* Fix landscape code-quality warnings [[#145](https://github.com/nir0s/distro/issues/145)] + +RELEASE: +* Add CONTRIBUTING.md + +## 1.0.0 (2016-09-25) + +BACKWARD COMPATIBILITY: +* raise exception when importing on non-supported platforms [[#129](https://github.com/nir0s/distro/issues/129)] + +ENHANCEMENTS: +* Use `bytes` invariantly [[#135](https://github.com/nir0s/distro/issues/135)] +* Some minor code adjustments plus a CLI [[#134](https://github.com/nir0s/distro/issues/134)] +* Emit stderr if `lsb_release` fails + +BUG FIXES: +* Fix some encoding related issues + +TESTS: +* Add many test cases (e.g. Raspbian 8, CoreOS, Amazon Linux, Scientific Linux, Gentoo, Manjaro) +* Completely redo the testing framework to make it easier to add tests +* Test on pypy + +RELEASE: +* Remove six as a dependency + +## 0.6.0 (2016-04-21) + +This is the first release of `distro`. +All previous work was done on `ld` and therefore unmentioned here. See the release log in GitHub if you want the entire log. + +BACKWARD COMPATIBILITY: +* No longer a package. constants.py has been removed and distro is now a single module + +ENHANCEMENTS: +* distro.info() now receives best and pretty flags +* Removed get_ prefix from get_*_release_attr functions +* Codename is now passed in distro.info() + +TESTS: +* Added Linux Mint test case +* Now testing on Python 3.4 + +DOCS: +* Documentation fixes + diff --git a/third_party/python/distro/CONTRIBUTING.md b/third_party/python/distro/CONTRIBUTING.md new file mode 100644 --- /dev/null +++ b/third_party/python/distro/CONTRIBUTING.md @@ -0,0 +1,54 @@ +# General + +* Contributing to distro identification currently doesn't have any specific standards and rather depends on the specific implementation. +* A 100% coverage is expected for each PR unless explicitly authorized by the reviewer. +* Please try to maintain maximum code-health (via landscape.io). + +# Contributing distro specific tests + +Distro's tests are implemented via a standardized framework under `tests/test_distro.py` + +For each distribution, tests should be added in the relevant class according to which distribution file(s) exists on it, so, for example, tests should be added under `TestOSRelease` where `/etc/os-release` is available. + +The tests must be self-contained, meaning that the release files for the distribution should be maintained in the repository under `tests/resources/distros/distribution_name+distribution_version`. + +A tests method would like somewhat like this: + +```python +def test_centos7_os_release(self): + desired_outcome = { + 'id': 'centos', + 'name': 'CentOS Linux', + 'pretty_name': 'CentOS Linux 7 (Core)', + 'version': '7', + 'pretty_version': '7 (Core)', + 'best_version': '7', + 'like': 'rhel fedora', + 'codename': 'Core' + } + self._test_outcome(desired_outcome) +``` + +The framework will automatically try to pick up the relevant file according to the method's name (`centos7` meaning the folder should be named `centos7` as well) and compare the `desired_outcome` with the parsed files found under the test dir. + +The exception to the rule is under the `TestDistroRelease` test class which should look somewhat like this: + +```python +def test_centos5_dist_release(self): + desired_outcome = { + 'id': 'centos', + 'name': 'CentOS', + 'pretty_name': 'CentOS 5.11 (Final)', + 'version': '5.11', + 'pretty_version': '5.11 (Final)', + 'best_version': '5.11', + 'codename': 'Final', + 'major_version': '5', + 'minor_version': '11' + } + self._test_outcome(desired_outcome, 'centos', '5') +``` + +Where the name of the method is not indicative of the lookup folder but rather tha two last arguments in `_test_outcome`. + +A test case is mandatory under `TestOverall` for a PR to be complete. \ No newline at end of file diff --git a/third_party/python/distro/CONTRIBUTORS.md b/third_party/python/distro/CONTRIBUTORS.md new file mode 100644 --- /dev/null +++ b/third_party/python/distro/CONTRIBUTORS.md @@ -0,0 +1,13 @@ +Thanks! + +* https://github.com/andy-maier +* https://github.com/SethMichaelLarson +* https://github.com/asottile +* https://github.com/MartijnBraam +* https://github.com/funkyfuture +* https://github.com/adamjstewart +* https://github.com/xavfernandez +* https://github.com/xsuchy +* https://github.com/marcoceppi +* https://github.com/tgamblin +* https://github.com/sebix diff --git a/third_party/python/distro/LICENSE b/third_party/python/distro/LICENSE new file mode 100644 --- /dev/null +++ b/third_party/python/distro/LICENSE @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/third_party/python/distro/MANIFEST.in b/third_party/python/distro/MANIFEST.in new file mode 100644 --- /dev/null +++ b/third_party/python/distro/MANIFEST.in @@ -0,0 +1,12 @@ +include *.md +include *.py +include *.txt +include LICENSE +include CHANGES +include Makefile + +graft tests + +include docs/* + +global-exclude *.py[co] diff --git a/third_party/python/distro/Makefile b/third_party/python/distro/Makefile new file mode 100644 --- /dev/null +++ b/third_party/python/distro/Makefile @@ -0,0 +1,145 @@ +# Copyright 2015,2016 Nir Cohen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Name of this package +PACKAGENAME = distro + +# Additional options for Sphinx +SPHINXOPTS = -v + +# Paper format for the Sphinx LaTex/PDF builder. +# Valid values: a4, letter +SPHINXPAPER = a4 + +# Sphinx build subtree. +SPHINXBUILDDIR = build_docs + +# Directory where conf.py is located +SPHINXCONFDIR = docs + +# Directory where input files for Sphinx are located +SPHINXSOURCEDIR = . + +# Sphinx build command (Use 'pip install sphinx' to get it) +SPHINXBUILD = sphinx-build + +# Internal variables for Sphinx +SPHINXPAPEROPT_a4 = -D latex_paper_size=a4 +SPHINXPAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(SPHINXBUILDDIR)/doctrees -c $(SPHINXCONFDIR) \ + $(SPHINXPAPEROPT_$(SPHINXPAPER)) $(SPHINXOPTS) \ + $(SPHINXSOURCEDIR) + +.PHONY: help +help: + @echo 'Please use "make " where is one of' + @echo " release - build a release and publish it" + @echo " dev - prepare a development environment (includes tests)" + @echo " instdev - prepare a development environment (no tests)" + @echo " install - install into current Python environment" + @echo " html - generate docs as standalone HTML files in: $(SPHINXBUILDDIR)/html" + @echo " pdf - generate docs as PDF (via LaTeX) for paper format: $(SPHINXPAPER) in: $(SPHINXBUILDDIR)/pdf" + @echo " man - generate docs as manual pages in: $(SPHINXBUILDDIR)/man" + @echo " docchanges - generate an overview of all changed/added/deprecated items in docs" + @echo " doclinkcheck - check all external links in docs for integrity" + @echo " doccoverage - run coverage check of the documentation" + @echo " clobber - remove any build products" + @echo " build - build the package" + @echo " test - test from this directory using tox, including test coverage" + @echo " publish - upload to PyPI" + @echo " clean - remove any temporary build products" + @echo " dry-run - perform all action required for a release without actually releasing" + +.PHONY: release +release: test clean build publish + @echo "$@ done." + +.PHONY: test +test: + pip install 'tox>=1.7.2' + tox + @echo "$@ done." + +.PHONY: clean +clean: + rm -rf dist build $(PACKAGENAME).egg-info + @echo "$@ done." + +.PHONY: build +build: + python setup.py sdist bdist_wheel + +.PHONY: publish +publish: + twine upload -r pypi dist/$(PACKAGENAME)-* + @echo "$@ done." + +.PHONY: dry-run +dry-run: test clean build + @echo "$@ done." + +.PHONY: dev +dev: instdev test + @echo "$@ done." + +.PHONY: instdev +instdev: + pip install -r dev-requirements.txt + python setup.py develop + @echo "$@ done." + +.PHONY: install +install: + python setup.py install + @echo "$@ done." + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/html + @echo "$@ done; the HTML pages are in $(SPHINXBUILDDIR)/html." + +.PHONY: pdf +pdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/pdf + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(SPHINXBUILDDIR)/pdf all-pdf + @echo "$@ done; the PDF files are in $(SPHINXBUILDDIR)/pdf." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/man + @echo "$@ done; the manual pages are in $(SPHINXBUILDDIR)/man." + +.PHONY: docchanges +docchanges: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/changes + @echo + @echo "$@ done; the doc changes overview file is in $(SPHINXBUILDDIR)/changes." + +.PHONY: doclinkcheck +doclinkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/linkcheck + @echo + @echo "$@ done; look for any errors in the above output " \ + "or in $(SPHINXBUILDDIR)/linkcheck/output.txt." + +.PHONY: doccoverage +doccoverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/coverage + @echo "$@ done; the doc coverage results are in $(SPHINXBUILDDIR)/coverage/python.txt." + +.PHONY: clobber +clobber: clean + rm -rf $(SPHINXBUILDDIR) + @echo "$@ done." diff --git a/third_party/python/distro/PKG-INFO b/third_party/python/distro/PKG-INFO new file mode 100644 --- /dev/null +++ b/third_party/python/distro/PKG-INFO @@ -0,0 +1,168 @@ +Metadata-Version: 2.1 +Name: distro +Version: 1.4.0 +Summary: Distro - an OS platform information API +Home-page: https://github.com/nir0s/distro +Author: Nir Cohen +Author-email: nir36g@gmail.com +License: Apache License, Version 2.0 +Description: Distro - an OS platform information API + ======================================= + + [![Build Status](https://travis-ci.org/nir0s/distro.svg?branch=master)](https://travis-ci.org/nir0s/distro) + [![Build status](https://ci.appveyor.com/api/projects/status/e812qjk1gf0f74r5/branch/master?svg=true)](https://ci.appveyor.com/project/nir0s/distro/branch/master) + [![PyPI version](http://img.shields.io/pypi/v/distro.svg)](https://pypi.python.org/pypi/distro) + [![Supported Python Versions](https://img.shields.io/pypi/pyversions/distro.svg)](https://img.shields.io/pypi/pyversions/distro.svg) + [![Requirements Status](https://requires.io/github/nir0s/distro/requirements.svg?branch=master)](https://requires.io/github/nir0s/distro/requirements/?branch=master) + [![Code Coverage](https://codecov.io/github/nir0s/distro/coverage.svg?branch=master)](https://codecov.io/github/nir0s/distro?branch=master) + [![Code Quality](https://landscape.io/github/nir0s/distro/master/landscape.svg?style=flat)](https://landscape.io/github/nir0s/distro) + [![Is Wheel](https://img.shields.io/pypi/wheel/distro.svg?style=flat)](https://pypi.python.org/pypi/distro) + [![Latest Github Release](https://readthedocs.org/projects/distro/badge/?version=stable)](http://distro.readthedocs.io/en/latest/) + [![Join the chat at https://gitter.im/nir0s/distro](https://badges.gitter.im/nir0s/distro.svg)](https://gitter.im/nir0s/distro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + + `distro` provides information about the + OS distribution it runs on, such as a reliable machine-readable ID, or + version information. + + It is the recommended replacement for Python's original + [`platform.linux_distribution`](https://docs.python.org/3.7/library/platform.html#platform.linux_distribution) + function (which will be removed in Python 3.8). + It also provides much more functionality which isn't necessarily Python bound, + like a command-line interface. + + Distro currently supports Linux and BSD based systems but [Windows and OS X support](https://github.com/nir0s/distro/issues/177) is also planned. + + For Python 2.6 support, see https://github.com/nir0s/distro/tree/python2.6-support + + ## Installation + + Installation of the latest released version from PyPI: + + ```shell + pip install distro + ``` + + Installation of the latest development version: + + ```shell + pip install https://github.com/nir0s/distro/archive/master.tar.gz + ``` + + + ## Usage + + ```bash + $ distro + Name: Antergos Linux + Version: 2015.10 (ISO-Rolling) + Codename: ISO-Rolling + + $ distro -j + { + "codename": "ISO-Rolling", + "id": "antergos", + "like": "arch", + "version": "16.9", + "version_parts": { + "build_number": "", + "major": "16", + "minor": "9" + } + } + + + $ python + >>> import distro + >>> distro.linux_distribution(full_distribution_name=False) + ('centos', '7.1.1503', 'Core') + ``` + + + ## Documentation + + On top of the aforementioned API, several more functions are available. For a complete description of the + API, see the [latest API documentation](http://distro.readthedocs.org/en/latest/). + + ## Background + + An alternative implementation became necessary because Python 3.5 deprecated + this function, and Python 3.8 will remove it altogether. + Its predecessor function `platform.dist` was already deprecated since + Python 2.6 and will also be removed in Python 3.8. + Still, there are many cases in which access to that information is needed. + See [Python issue 1322](https://bugs.python.org/issue1322) for more + information. + + The `distro` package implements a robust and inclusive way of retrieving the + information about a distribution based on new standards and old methods, + namely from these data sources (from high to low precedence): + + * The os-release file `/etc/os-release`, if present. + * The output of the `lsb_release` command, if available. + * The distro release file (`/etc/*(-|_)(release|version)`), if present. + * The `uname` command for BSD based distrubtions. + + + ## Python and Distribution Support + + `distro` is supported and tested on Python 2.7, 3.4+ and PyPy and on + any distribution that provides one or more of the data sources + covered. + + This package is tested with test data that mimics the exact behavior of the data sources of [a number of Linux distributions](https://github.com/nir0s/distro/tree/master/tests/resources/distros). + + + ## Testing + + ```shell + git clone git@github.com:nir0s/distro.git + cd distro + pip install tox + tox + ``` + + + ## Contributions + + Pull requests are always welcome to deal with specific distributions or just + for general merriment. + + See [CONTRIBUTIONS](https://github.com/nir0s/distro/blob/master/CONTRIBUTING.md) for contribution info. + + Reference implementations for supporting additional distributions and file + formats can be found here: + + * https://github.com/saltstack/salt/blob/develop/salt/grains/core.py#L1172 + * https://github.com/chef/ohai/blob/master/lib/ohai/plugins/linux/platform.rb + * https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts/system/distribution.py + * https://github.com/puppetlabs/facter/blob/master/lib/src/facts/linux/os_linux.cc + + ## Package manager distributions + + * https://src.fedoraproject.org/rpms/python-distro + * https://www.archlinux.org/packages/community/any/python-distro/ + * https://launchpad.net/ubuntu/+source/python-distro + * https://packages.debian.org/sid/python-distro + * https://packages.gentoo.org/packages/dev-python/distro + * https://pkgs.org/download/python2-distro + * https://slackbuilds.org/repository/14.2/python/python-distro/ + +Platform: All +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: POSIX :: BSD +Classifier: Operating System :: POSIX :: BSD :: FreeBSD +Classifier: Operating System :: POSIX :: BSD :: NetBSD +Classifier: Operating System :: POSIX :: BSD :: OpenBSD +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Operating System +Description-Content-Type: text/markdown diff --git a/third_party/python/distro/README.md b/third_party/python/distro/README.md new file mode 100644 --- /dev/null +++ b/third_party/python/distro/README.md @@ -0,0 +1,140 @@ +Distro - an OS platform information API +======================================= + +[![Build Status](https://travis-ci.org/nir0s/distro.svg?branch=master)](https://travis-ci.org/nir0s/distro) +[![Build status](https://ci.appveyor.com/api/projects/status/e812qjk1gf0f74r5/branch/master?svg=true)](https://ci.appveyor.com/project/nir0s/distro/branch/master) +[![PyPI version](http://img.shields.io/pypi/v/distro.svg)](https://pypi.python.org/pypi/distro) +[![Supported Python Versions](https://img.shields.io/pypi/pyversions/distro.svg)](https://img.shields.io/pypi/pyversions/distro.svg) +[![Requirements Status](https://requires.io/github/nir0s/distro/requirements.svg?branch=master)](https://requires.io/github/nir0s/distro/requirements/?branch=master) +[![Code Coverage](https://codecov.io/github/nir0s/distro/coverage.svg?branch=master)](https://codecov.io/github/nir0s/distro?branch=master) +[![Code Quality](https://landscape.io/github/nir0s/distro/master/landscape.svg?style=flat)](https://landscape.io/github/nir0s/distro) +[![Is Wheel](https://img.shields.io/pypi/wheel/distro.svg?style=flat)](https://pypi.python.org/pypi/distro) +[![Latest Github Release](https://readthedocs.org/projects/distro/badge/?version=stable)](http://distro.readthedocs.io/en/latest/) +[![Join the chat at https://gitter.im/nir0s/distro](https://badges.gitter.im/nir0s/distro.svg)](https://gitter.im/nir0s/distro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +`distro` provides information about the +OS distribution it runs on, such as a reliable machine-readable ID, or +version information. + +It is the recommended replacement for Python's original +[`platform.linux_distribution`](https://docs.python.org/3.7/library/platform.html#platform.linux_distribution) +function (which will be removed in Python 3.8). +It also provides much more functionality which isn't necessarily Python bound, +like a command-line interface. + +Distro currently supports Linux and BSD based systems but [Windows and OS X support](https://github.com/nir0s/distro/issues/177) is also planned. + +For Python 2.6 support, see https://github.com/nir0s/distro/tree/python2.6-support + +## Installation + +Installation of the latest released version from PyPI: + +```shell +pip install distro +``` + +Installation of the latest development version: + +```shell +pip install https://github.com/nir0s/distro/archive/master.tar.gz +``` + + +## Usage + +```bash +$ distro +Name: Antergos Linux +Version: 2015.10 (ISO-Rolling) +Codename: ISO-Rolling + +$ distro -j +{ + "codename": "ISO-Rolling", + "id": "antergos", + "like": "arch", + "version": "16.9", + "version_parts": { + "build_number": "", + "major": "16", + "minor": "9" + } +} + + +$ python +>>> import distro +>>> distro.linux_distribution(full_distribution_name=False) +('centos', '7.1.1503', 'Core') +``` + + +## Documentation + +On top of the aforementioned API, several more functions are available. For a complete description of the +API, see the [latest API documentation](http://distro.readthedocs.org/en/latest/). + +## Background + +An alternative implementation became necessary because Python 3.5 deprecated +this function, and Python 3.8 will remove it altogether. +Its predecessor function `platform.dist` was already deprecated since +Python 2.6 and will also be removed in Python 3.8. +Still, there are many cases in which access to that information is needed. +See [Python issue 1322](https://bugs.python.org/issue1322) for more +information. + +The `distro` package implements a robust and inclusive way of retrieving the +information about a distribution based on new standards and old methods, +namely from these data sources (from high to low precedence): + +* The os-release file `/etc/os-release`, if present. +* The output of the `lsb_release` command, if available. +* The distro release file (`/etc/*(-|_)(release|version)`), if present. +* The `uname` command for BSD based distrubtions. + + +## Python and Distribution Support + +`distro` is supported and tested on Python 2.7, 3.4+ and PyPy and on +any distribution that provides one or more of the data sources +covered. + +This package is tested with test data that mimics the exact behavior of the data sources of [a number of Linux distributions](https://github.com/nir0s/distro/tree/master/tests/resources/distros). + + +## Testing + +```shell +git clone git@github.com:nir0s/distro.git +cd distro +pip install tox +tox +``` + + +## Contributions + +Pull requests are always welcome to deal with specific distributions or just +for general merriment. + +See [CONTRIBUTIONS](https://github.com/nir0s/distro/blob/master/CONTRIBUTING.md) for contribution info. + +Reference implementations for supporting additional distributions and file +formats can be found here: + +* https://github.com/saltstack/salt/blob/develop/salt/grains/core.py#L1172 +* https://github.com/chef/ohai/blob/master/lib/ohai/plugins/linux/platform.rb +* https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts/system/distribution.py +* https://github.com/puppetlabs/facter/blob/master/lib/src/facts/linux/os_linux.cc + +## Package manager distributions + +* https://src.fedoraproject.org/rpms/python-distro +* https://www.archlinux.org/packages/community/any/python-distro/ +* https://launchpad.net/ubuntu/+source/python-distro +* https://packages.debian.org/sid/python-distro +* https://packages.gentoo.org/packages/dev-python/distro +* https://pkgs.org/download/python2-distro +* https://slackbuilds.org/repository/14.2/python/python-distro/ diff --git a/third_party/python/distro/dev-requirements.txt b/third_party/python/distro/dev-requirements.txt new file mode 100644 --- /dev/null +++ b/third_party/python/distro/dev-requirements.txt @@ -0,0 +1,3 @@ +pytest +pytest-cov +sphinx>=1.1 \ No newline at end of file diff --git a/third_party/python/distro/distro.py b/third_party/python/distro/distro.py new file mode 100755 --- /dev/null +++ b/third_party/python/distro/distro.py @@ -0,0 +1,1216 @@ +# Copyright 2015,2016,2017 Nir Cohen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +The ``distro`` package (``distro`` stands for Linux Distribution) provides +information about the Linux distribution it runs on, such as a reliable +machine-readable distro ID, or version information. + +It is the recommended replacement for Python's original +:py:func:`platform.linux_distribution` function, but it provides much more +functionality. An alternative implementation became necessary because Python +3.5 deprecated this function, and Python 3.8 will remove it altogether. +Its predecessor function :py:func:`platform.dist` was already +deprecated since Python 2.6 and will also be removed in Python 3.8. +Still, there are many cases in which access to OS distribution information +is needed. See `Python issue 1322 `_ for +more information. +""" + +import os +import re +import sys +import json +import shlex +import logging +import argparse +import subprocess + + +_UNIXCONFDIR = os.environ.get('UNIXCONFDIR', '/etc') +_OS_RELEASE_BASENAME = 'os-release' + +#: Translation table for normalizing the "ID" attribute defined in os-release +#: files, for use by the :func:`distro.id` method. +#: +#: * Key: Value as defined in the os-release file, translated to lower case, +#: with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_OS_ID = { + 'ol': 'oracle', # Oracle Enterprise Linux +} + +#: Translation table for normalizing the "Distributor ID" attribute returned by +#: the lsb_release command, for use by the :func:`distro.id` method. +#: +#: * Key: Value as returned by the lsb_release command, translated to lower +#: case, with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_LSB_ID = { + 'enterpriseenterprise': 'oracle', # Oracle Enterprise Linux + 'redhatenterpriseworkstation': 'rhel', # RHEL 6, 7 Workstation + 'redhatenterpriseserver': 'rhel', # RHEL 6, 7 Server +} + +#: Translation table for normalizing the distro ID derived from the file name +#: of distro release files, for use by the :func:`distro.id` method. +#: +#: * Key: Value as derived from the file name of a distro release file, +#: translated to lower case, with blanks translated to underscores. +#: +#: * Value: Normalized value. +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 *)?(.+)') + +# Pattern for base file name of distro release file +_DISTRO_RELEASE_BASENAME_PATTERN = re.compile( + r'(\w+)[-_](release|version)$') + +# Base file names to be ignored when searching for distro release file +_DISTRO_RELEASE_IGNORE_BASENAMES = ( + 'debian_version', + 'lsb-release', + 'oem-release', + _OS_RELEASE_BASENAME, + 'system-release' +) + + +def linux_distribution(full_distribution_name=True): + """ + Return information about the current OS distribution as a tuple + ``(id_name, version, codename)`` with items as follows: + + * ``id_name``: If *full_distribution_name* is false, the result of + :func:`distro.id`. Otherwise, the result of :func:`distro.name`. + + * ``version``: The result of :func:`distro.version`. + + * ``codename``: 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 + its parameters. + + The data it returns may not exactly be the same, because it uses more data + sources than the original function, and that may lead to different data if + the OS distribution is not consistent across multiple data sources it + provides (there are indeed such distributions ...). + + Another reason for differences is the fact that the :func:`distro.id` + method normalizes the distro ID string to a reliable machine-readable value + for a number of popular OS distributions. + """ + return _distro.linux_distribution(full_distribution_name) + + +def id(): + """ + Return the distro ID of the current distribution, as a + machine-readable string. + + For a number of OS distributions, the returned distro ID value is + *reliable*, in the sense that it is documented and that it does not change + across releases of the distribution. + + This package maintains the following reliable distro ID values: + + ============== ========================================= + Distro ID Distribution + ============== ========================================= + "ubuntu" Ubuntu + "debian" Debian + "rhel" RedHat Enterprise Linux + "centos" CentOS + "fedora" Fedora + "sles" SUSE Linux Enterprise Server + "opensuse" openSUSE + "amazon" Amazon Linux + "arch" Arch Linux + "cloudlinux" CloudLinux OS + "exherbo" Exherbo Linux + "gentoo" GenToo Linux + "ibm_powerkvm" IBM PowerKVM + "kvmibm" KVM for IBM z Systems + "linuxmint" Linux Mint + "mageia" Mageia + "mandriva" Mandriva Linux + "parallels" Parallels + "pidora" Pidora + "raspbian" Raspbian + "oracle" Oracle Linux (and Oracle Enterprise Linux) + "scientific" Scientific Linux + "slackware" Slackware + "xenserver" XenServer + "openbsd" OpenBSD + "netbsd" NetBSD + "freebsd" FreeBSD + ============== ========================================= + + If you have a need to get distros for reliable IDs added into this set, + or if you find that the :func:`distro.id` function returns a different + distro ID for one of the listed distros, please create an issue in the + `distro issue tracker`_. + + **Lookup hierarchy and transformations:** + + First, the ID is obtained from the following sources, in the specified + order. The first available and non-empty value is used: + + * the value of the "ID" attribute of the os-release file, + + * the value of the "Distributor ID" attribute returned by the lsb_release + command, + + * the first part of the file name of the distro release file, + + The so determined ID value then passes the following transformations, + before it is returned by this method: + + * it is translated to lower case, + + * blanks (which should not be there anyway) are translated to underscores, + + * a normalization of the ID is performed, based upon + `normalization tables`_. The purpose of this normalization is to ensure + that the ID is as reliable as possible, even across incompatible changes + in the OS distributions. A common reason for an incompatible change is + the addition of an os-release file, or the addition of the lsb_release + command, with ID values that differ from what was previously determined + from the distro release file name. + """ + return _distro.id() + + +def name(pretty=False): + """ + Return the name of the current OS distribution, as a human-readable + string. + + If *pretty* is false, the name is returned without version or codename. + (e.g. "CentOS Linux") + + If *pretty* is true, the version and codename are appended. + (e.g. "CentOS Linux 7.1.1503 (Core)") + + **Lookup hierarchy:** + + The name is obtained from the following sources, in the specified order. + The first available and non-empty value is used: + + * If *pretty* is false: + + - the value of the "NAME" attribute of the os-release file, + + - the value of the "Distributor ID" attribute returned by the lsb_release + command, + + - the value of the "" field of the distro release file. + + * If *pretty* is true: + + - the value of the "PRETTY_NAME" attribute of the os-release file, + + - the value of the "Description" attribute returned by the lsb_release + command, + + - the value of the "" field of the distro release file, appended + with the value of the pretty version ("" and "" + fields) of the distro release file, if available. + """ + return _distro.name(pretty) + + +def version(pretty=False, best=False): + """ + Return the version of the current OS distribution, as a human-readable + string. + + If *pretty* is false, the version is returned without codename (e.g. + "7.0"). + + If *pretty* is true, the codename in parenthesis is appended, if the + codename is non-empty (e.g. "7.0 (Maipo)"). + + Some distributions provide version numbers with different precisions in + the different sources of distribution information. Examining the different + sources in a fixed priority order does not always yield the most precise + version (e.g. for Debian 8.2, or CentOS 7.1). + + The *best* parameter can be used to control the approach for the returned + version: + + If *best* is false, the first non-empty version number in priority order of + the examined sources is returned. + + If *best* is true, the most precise version number out of all examined + sources is returned. + + **Lookup hierarchy:** + + In all cases, the version number is obtained from the following sources. + If *best* is false, this order represents the priority order: + + * the value of the "VERSION_ID" attribute of the os-release file, + * the value of the "Release" attribute returned by the lsb_release + command, + * the version number parsed from the "" field of the first line + of the distro release file, + * the version number parsed from the "PRETTY_NAME" attribute of the + os-release file, if it follows the format of the distro release files. + * the version number parsed from the "Description" attribute returned by + the lsb_release command, if it follows the format of the distro release + files. + """ + return _distro.version(pretty, best) + + +def version_parts(best=False): + """ + Return the version of the current OS distribution as a tuple + ``(major, minor, build_number)`` with items as follows: + + * ``major``: The result of :func:`distro.major_version`. + + * ``minor``: The result of :func:`distro.minor_version`. + + * ``build_number``: The result of :func:`distro.build_number`. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.version_parts(best) + + +def major_version(best=False): + """ + Return the major version of the current OS distribution, as a string, + if provided. + Otherwise, the empty string is returned. The major version is the first + part of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.major_version(best) + + +def minor_version(best=False): + """ + Return the minor version of the current OS distribution, as a string, + if provided. + Otherwise, the empty string is returned. The minor version is the second + part of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.minor_version(best) + + +def build_number(best=False): + """ + Return the build number of the current OS distribution, as a string, + if provided. + Otherwise, the empty string is returned. The build number is the third part + of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.build_number(best) + + +def like(): + """ + Return a space-separated list of distro IDs of distributions that are + closely related to the current OS distribution in regards to packaging + and programming interfaces, for example distributions the current + distribution is a derivative from. + + **Lookup hierarchy:** + + This information item is only provided by the os-release file. + For details, see the description of the "ID_LIKE" attribute in the + `os-release man page + `_. + """ + return _distro.like() + + +def codename(): + """ + Return the codename for the release of the current OS distribution, + as a string. + + If the distribution does not have a codename, an empty string is returned. + + Note that the returned codename is not always really a codename. For + example, openSUSE returns "x86_64". This function does not handle such + cases in any special way and just returns the string it finds, if any. + + **Lookup hierarchy:** + + * the codename within the "VERSION" attribute of the os-release file, if + provided, + + * the value of the "Codename" attribute returned by the lsb_release + command, + + * the value of the "" field of the distro release file. + """ + return _distro.codename() + + +def info(pretty=False, best=False): + """ + Return certain machine-readable information items about the current OS + distribution in a dictionary, as shown in the following example: + + .. sourcecode:: python + + { + 'id': 'rhel', + 'version': '7.0', + 'version_parts': { + 'major': '7', + 'minor': '0', + 'build_number': '' + }, + 'like': 'fedora', + 'codename': 'Maipo' + } + + The dictionary structure and keys are always the same, regardless of which + information items are available in the underlying data sources. The values + for the various keys are as follows: + + * ``id``: The result of :func:`distro.id`. + + * ``version``: The result of :func:`distro.version`. + + * ``version_parts -> major``: The result of :func:`distro.major_version`. + + * ``version_parts -> minor``: The result of :func:`distro.minor_version`. + + * ``version_parts -> build_number``: The result of + :func:`distro.build_number`. + + * ``like``: The result of :func:`distro.like`. + + * ``codename``: The result of :func:`distro.codename`. + + For a description of the *pretty* and *best* parameters, see the + :func:`distro.version` method. + """ + return _distro.info(pretty, best) + + +def os_release_info(): + """ + Return a dictionary containing key-value pairs for the information items + from the os-release file data source of the current OS distribution. + + See `os-release file`_ for details about these information items. + """ + return _distro.os_release_info() + + +def lsb_release_info(): + """ + Return a dictionary containing key-value pairs for the information items + from the lsb_release command data source of the current OS distribution. + + See `lsb_release command output`_ for details about these information + items. + """ + return _distro.lsb_release_info() + + +def distro_release_info(): + """ + Return a dictionary containing key-value pairs for the information items + from the distro release file data source of the current OS distribution. + + See `distro release file`_ for details about these information items. + """ + return _distro.distro_release_info() + + +def uname_info(): + """ + Return a dictionary containing key-value pairs for the information items + from the distro release file data source of the current OS distribution. + """ + return _distro.uname_info() + + +def os_release_attr(attribute): + """ + Return a single named information item from the os-release file data source + of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `os-release file`_ for details about these information items. + """ + return _distro.os_release_attr(attribute) + + +def lsb_release_attr(attribute): + """ + Return a single named information item from the lsb_release command output + data source of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `lsb_release command output`_ for details about these information + items. + """ + return _distro.lsb_release_attr(attribute) + + +def distro_release_attr(attribute): + """ + Return a single named information item from the distro release file + data source of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `distro release file`_ for details about these information items. + """ + return _distro.distro_release_attr(attribute) + + +def uname_attr(attribute): + """ + Return a single named information item from the distro release file + data source of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + """ + return _distro.uname_attr(attribute) + + +class cached_property(object): + """A version of @property which caches the value. On access, it calls the + underlying function and sets the value in `__dict__` so future accesses + will not re-call the property. + """ + def __init__(self, f): + self._fname = f.__name__ + self._f = f + + def __get__(self, obj, owner): + assert obj is not None, 'call {} on an instance'.format(self._fname) + ret = obj.__dict__[self._fname] = self._f(obj) + return ret + + +class LinuxDistribution(object): + """ + Provides information about a OS distribution. + + This package creates a private module-global instance of this class with + default initialization arguments, that is used by the + `consolidated accessor functions`_ and `single source accessor functions`_. + By using default initialization arguments, that module-global instance + returns data about the current OS distribution (i.e. the distro this + package runs on). + + Normally, it is not necessary to create additional instances of this class. + However, in situations where control is needed over the exact data sources + that are used, instances of this class can be created with a specific + distro release file, or a specific os-release file, or without invoking the + lsb_release command. + """ + + def __init__(self, + include_lsb=True, + os_release_file='', + distro_release_file='', + include_uname=True): + """ + The initialization method of this class gathers information from the + available data sources, and stores that in private instance attributes. + Subsequent access to the information items uses these private instance + attributes, so that the data sources are read only once. + + Parameters: + + * ``include_lsb`` (bool): Controls whether the + `lsb_release command output`_ is included as a data source. + + If the lsb_release command is not available in the program execution + path, the data source for the lsb_release command will be empty. + + * ``os_release_file`` (string): The path name of the + `os-release file`_ that is to be used as a data source. + + An empty string (the default) will cause the default path name to + be used (see `os-release file`_ for details). + + If the specified or defaulted os-release file does not exist, the + data source for the os-release file will be empty. + + * ``distro_release_file`` (string): The path name of the + `distro release file`_ that is to be used as a data source. + + An empty string (the default) will cause a default search algorithm + to be used (see `distro release file`_ for details). + + If the specified distro release file does not exist, or if no default + distro release file can be found, the data source for the distro + release file will be empty. + + * ``include_name`` (bool): Controls whether uname command output is + included as a data source. If the uname command is not available in + the program execution path the data source for the uname command will + be empty. + + Public instance attributes: + + * ``os_release_file`` (string): The path name of the + `os-release file`_ that is actually used as a data source. The + empty string if no distro release file is used as a data source. + + * ``distro_release_file`` (string): The path name of the + `distro release file`_ that is actually used as a data source. The + empty string if no distro release file is used as a data source. + + * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter. + This controls whether the lsb information will be loaded. + + * ``include_uname`` (bool): The result of the ``include_uname`` + parameter. This controls whether the uname information will + be loaded. + + Raises: + + * :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. + """ + 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.include_lsb = include_lsb + self.include_uname = include_uname + + def __repr__(self): + """Return repr of all info + """ + return \ + "LinuxDistribution(" \ + "os_release_file={self.os_release_file!r}, " \ + "distro_release_file={self.distro_release_file!r}, " \ + "include_lsb={self.include_lsb!r}, " \ + "include_uname={self.include_uname!r}, " \ + "_os_release_info={self._os_release_info!r}, " \ + "_lsb_release_info={self._lsb_release_info!r}, " \ + "_distro_release_info={self._distro_release_info!r}, " \ + "_uname_info={self._uname_info!r})".format( + self=self) + + def linux_distribution(self, full_distribution_name=True): + """ + Return information about the OS distribution that is compatible + with Python's :func:`platform.linux_distribution`, supporting a subset + of its parameters. + + For details, see :func:`distro.linux_distribution`. + """ + return ( + self.name() if full_distribution_name else self.id(), + self.version(), + self.codename() + ) + + def id(self): + """Return the distro ID of the OS 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: + return normalize(distro_id, NORMALIZED_OS_ID) + + distro_id = self.lsb_release_attr('distributor_id') + if distro_id: + return normalize(distro_id, NORMALIZED_LSB_ID) + + distro_id = self.distro_release_attr('id') + if distro_id: + return normalize(distro_id, NORMALIZED_DISTRO_ID) + + distro_id = self.uname_attr('id') + if distro_id: + return normalize(distro_id, NORMALIZED_DISTRO_ID) + + return '' + + def name(self, pretty=False): + """ + Return the name of the OS distribution, as a string. + + For details, see :func:`distro.name`. + """ + name = self.os_release_attr('name') \ + or self.lsb_release_attr('distributor_id') \ + or self.distro_release_attr('name') \ + or self.uname_attr('name') + if pretty: + name = self.os_release_attr('pretty_name') \ + or self.lsb_release_attr('description') + if not name: + name = self.distro_release_attr('name') \ + or self.uname_attr('name') + version = self.version(pretty=True) + if version: + name = name + ' ' + version + return name or '' + + def version(self, pretty=False, best=False): + """ + Return the version of the OS distribution, as a string. + + For details, see :func:`distro.version`. + """ + versions = [ + self.os_release_attr('version_id'), + self.lsb_release_attr('release'), + self.distro_release_attr('version_id'), + self._parse_distro_release_content( + self.os_release_attr('pretty_name')).get('version_id', ''), + self._parse_distro_release_content( + self.lsb_release_attr('description')).get('version_id', ''), + self.uname_attr('release') + ] + version = '' + if best: + # This algorithm uses the last version in priority order that has + # the best precision. If the versions are not in conflict, that + # does not matter; otherwise, using the last one instead of the + # first one might be considered a surprise. + for v in versions: + if v.count(".") > version.count(".") or version == '': + version = v + else: + for v in versions: + if v != '': + version = v + break + if pretty and version and self.codename(): + version = u'{0} ({1})'.format(version, self.codename()) + return version + + def version_parts(self, best=False): + """ + Return the version of the OS distribution, as a tuple of version + numbers. + + For details, see :func:`distro.version_parts`. + """ + version_str = self.version(best=best) + if version_str: + 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 '', '', '' + + def major_version(self, best=False): + """ + Return the major version number of the current distribution. + + For details, see :func:`distro.major_version`. + """ + return self.version_parts(best)[0] + + def minor_version(self, best=False): + """ + Return the minor version number of the current distribution. + + For details, see :func:`distro.minor_version`. + """ + return self.version_parts(best)[1] + + def build_number(self, best=False): + """ + Return the build number of the current distribution. + + For details, see :func:`distro.build_number`. + """ + return self.version_parts(best)[2] + + def like(self): + """ + Return the IDs of distributions that are like the OS distribution. + + For details, see :func:`distro.like`. + """ + return self.os_release_attr('id_like') or '' + + def codename(self): + """ + Return the codename of the OS distribution. + + For details, see :func:`distro.codename`. + """ + try: + # Handle os_release specially since distros might purposefully set + # this to empty string to have no codename + return self._os_release_info['codename'] + except KeyError: + return self.lsb_release_attr('codename') \ + or self.distro_release_attr('codename') \ + or '' + + def info(self, pretty=False, best=False): + """ + Return certain machine-readable information about the OS + distribution. + + For details, see :func:`distro.info`. + """ + return dict( + id=self.id(), + version=self.version(pretty, best), + version_parts=dict( + major=self.major_version(best), + minor=self.minor_version(best), + build_number=self.build_number(best) + ), + like=self.like(), + codename=self.codename(), + ) + + def os_release_info(self): + """ + Return a dictionary containing key-value pairs for the information + items from the os-release file data source of the OS distribution. + + For details, see :func:`distro.os_release_info`. + """ + return self._os_release_info + + def lsb_release_info(self): + """ + Return a dictionary containing key-value pairs for the information + items from the lsb_release command data source of the OS + distribution. + + For details, see :func:`distro.lsb_release_info`. + """ + return self._lsb_release_info + + def distro_release_info(self): + """ + Return a dictionary containing key-value pairs for the information + items from the distro release file data source of the OS + distribution. + + For details, see :func:`distro.distro_release_info`. + """ + return self._distro_release_info + + def uname_info(self): + """ + Return a dictionary containing key-value pairs for the information + items from the uname command data source of the OS distribution. + + For details, see :func:`distro.uname_info`. + """ + return self._uname_info + + def os_release_attr(self, attribute): + """ + Return a single named information item from the os-release file data + source of the OS distribution. + + For details, see :func:`distro.os_release_attr`. + """ + return self._os_release_info.get(attribute, '') + + def lsb_release_attr(self, attribute): + """ + Return a single named information item from the lsb_release command + output data source of the OS distribution. + + For details, see :func:`distro.lsb_release_attr`. + """ + return self._lsb_release_info.get(attribute, '') + + def distro_release_attr(self, attribute): + """ + Return a single named information item from the distro release file + data source of the OS distribution. + + For details, see :func:`distro.distro_release_attr`. + """ + return self._distro_release_info.get(attribute, '') + + def uname_attr(self, attribute): + """ + Return a single named information item from the uname command + output data source of the OS distribution. + + For details, see :func:`distro.uname_release_attr`. + """ + return self._uname_info.get(attribute, '') + + @cached_property + def _os_release_info(self): + """ + Get the information items from the specified os-release file. + + Returns: + A dictionary containing all information items. + """ + if os.path.isfile(self.os_release_file): + with open(self.os_release_file) as release_file: + return self._parse_os_release_content(release_file) + return {} + + @staticmethod + def _parse_os_release_content(lines): + """ + Parse the lines of an os-release file. + + Parameters: + + * lines: Iterable through the lines in the os-release file. + Each line must be a unicode string or a UTF-8 encoded byte + string. + + Returns: + A dictionary containing all information items. + """ + props = {} + lexer = shlex.shlex(lines, posix=True) + lexer.whitespace_split = True + + # The shlex module defines its `wordchars` variable using literals, + # making it dependent on the encoding of the Python source file. + # In Python 2.6 and 2.7, the shlex source file is encoded in + # 'iso-8859-1', and the `wordchars` variable is defined as a byte + # string. This causes a UnicodeDecodeError to be raised when the + # parsed content is a unicode object. The following fix resolves that + # (... but it should be fixed in shlex...): + if sys.version_info[0] == 2 and isinstance(lexer.wordchars, bytes): + lexer.wordchars = lexer.wordchars.decode('iso-8859-1') + + tokens = list(lexer) + for token in tokens: + # At this point, all shell-like parsing has been done (i.e. + # comments processed, quotes and backslash escape sequences + # processed, multi-line values assembled, trailing newlines + # stripped, etc.), so the tokens are now either: + # * variable assignments: var=value + # * commands or their arguments (not allowed in os-release) + if '=' in token: + k, v = token.split('=', 1) + if isinstance(v, bytes): + v = v.decode('utf-8') + props[k.lower()] = v + else: + # Ignore any tokens that are not variable assignments + pass + + if 'version_codename' in props: + # os-release added a version_codename field. Use that in + # preference to anything else Note that some distros purposefully + # do not have code names. They should be setting + # version_codename="" + props['codename'] = props['version_codename'] + 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 + codename = re.search(r'(\(\D+\))|,(\s+)?\D+', props['version']) + if codename: + codename = codename.group() + codename = codename.strip('()') + codename = codename.strip(',') + codename = codename.strip() + # codename appears within paranthese. + props['codename'] = codename + + return props + + @cached_property + def _lsb_release_info(self): + """ + Get the information items from the lsb_release command output. + + Returns: + A dictionary containing all information items. + """ + if not self.include_lsb: + return {} + with open(os.devnull, 'w') as devnull: + try: + cmd = ('lsb_release', '-a') + stdout = subprocess.check_output(cmd, stderr=devnull) + except OSError: # Command not found + return {} + content = stdout.decode(sys.getfilesystemencoding()).splitlines() + return self._parse_lsb_release_content(content) + + @staticmethod + def _parse_lsb_release_content(lines): + """ + Parse the output of the lsb_release command. + + Parameters: + + * lines: Iterable through the lines of the lsb_release output. + Each line must be a unicode string or a UTF-8 encoded byte + string. + + Returns: + A dictionary containing all information items. + """ + props = {} + for line in lines: + kv = line.strip('\n').split(':', 1) + if len(kv) != 2: + # Ignore lines without colon. + continue + k, v = kv + props.update({k.replace(' ', '_').lower(): v.strip()}) + return props + + @cached_property + def _uname_info(self): + with open(os.devnull, 'w') as devnull: + try: + cmd = ('uname', '-rs') + stdout = subprocess.check_output(cmd, stderr=devnull) + except OSError: + return {} + content = stdout.decode(sys.getfilesystemencoding()).splitlines() + return self._parse_uname_content(content) + + @staticmethod + def _parse_uname_content(lines): + props = {} + match = re.search(r'^([^\s]+)\s+([\d\.]+)', lines[0].strip()) + if match: + name, version = match.groups() + + # This is to prevent the Linux kernel version from + # appearing as the 'best' version on otherwise + # identifiable distributions. + if name == 'Linux': + return {} + props['id'] = name.lower() + props['name'] = name + props['release'] = version + return props + + @cached_property + def _distro_release_info(self): + """ + Get the information items from the specified distro release file. + + Returns: + A dictionary containing all information items. + """ + if self.distro_release_file: + # If it was specified, we use it and parse what we can, even if + # its file name or content does not match the expected pattern. + distro_info = self._parse_distro_release_file( + self.distro_release_file) + basename = os.path.basename(self.distro_release_file) + # The file name pattern for user-specified distro release files + # is somewhat more tolerant (compared to when searching for the + # file), because we want to use what was specified as best as + # possible. + match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) + if 'name' in distro_info \ + and 'cloudlinux' in distro_info['name'].lower(): + distro_info['id'] = 'cloudlinux' + elif match: + distro_info['id'] = match.group(1) + return distro_info + else: + try: + basenames = os.listdir(_UNIXCONFDIR) + # We sort for repeatability in cases where there are multiple + # distro specific files; e.g. CentOS, Oracle, Enterprise all + # containing `redhat-release` on top of their own. + basenames.sort() + except OSError: + # This may occur when /etc is not readable but we can't be + # sure about the *-release files. Check common entries of + # /etc for information. If they turn out to not be there the + # error is handled in `_parse_distro_release_file()`. + basenames = ['SuSE-release', + 'arch-release', + 'base-release', + 'centos-release', + 'fedora-release', + 'gentoo-release', + 'mageia-release', + 'mandrake-release', + 'mandriva-release', + 'mandrivalinux-release', + 'manjaro-release', + 'oracle-release', + 'redhat-release', + 'sl-release', + 'slackware-version'] + for basename in basenames: + if basename in _DISTRO_RELEASE_IGNORE_BASENAMES: + continue + match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) + if match: + filepath = os.path.join(_UNIXCONFDIR, basename) + distro_info = self._parse_distro_release_file(filepath) + if 'name' in distro_info: + # The name is always present if the pattern matches + self.distro_release_file = filepath + distro_info['id'] = match.group(1) + if 'cloudlinux' in distro_info['name'].lower(): + distro_info['id'] = 'cloudlinux' + return distro_info + return {} + + def _parse_distro_release_file(self, filepath): + """ + Parse a distro release file. + + Parameters: + + * filepath: Path name of the distro release file. + + Returns: + A dictionary containing all information items. + """ + try: + 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()) + except (OSError, IOError): + # Ignore not being able to read a specific, seemingly version + # related file. + # See https://github.com/nir0s/distro/issues/162 + return {} + + @staticmethod + def _parse_distro_release_content(line): + """ + Parse a line from a distro release file. + + Parameters: + * line: Line from the distro release file. Must be a unicode string + or a UTF-8 encoded byte string. + + Returns: + A dictionary containing all information items. + """ + if isinstance(line, bytes): + line = line.decode('utf-8') + matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match( + line.strip()[::-1]) + distro_info = {} + 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 + + +_distro = LinuxDistribution() + + +def main(): + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + logger.addHandler(logging.StreamHandler(sys.stdout)) + + parser = argparse.ArgumentParser(description="OS 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) + logger.info('Version: %s', distribution_version) + distribution_codename = codename() + logger.info('Codename: %s', distribution_codename) + + +if __name__ == '__main__': + main() diff --git a/third_party/python/distro/docs/conf.py b/third_party/python/distro/docs/conf.py new file mode 100644 --- /dev/null +++ b/third_party/python/distro/docs/conf.py @@ -0,0 +1,342 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for Sphinx builds, created by +# sphinx-quickstart on Wed Mar 2 11:33:06 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import re + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('..')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.1' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +source_encoding = 'utf-8' + +# The master toctree document. +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +if on_rtd: + master_doc = 'index' +else: + master_doc = 'docs/index' + +# General information about the project. +project = u'distro' +copyright = u'2015,2016, Nir Cohen, Andreas Maier' +author = u'Nir Cohen, Andreas Maier' + +# The short description of the package. +_short_description = u'Linux Distribution - a Linux OS platform information API' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + +def parse_version(): + with open('../setup.py', 'r') as _fp: + _lines = _fp.readlines() + for _line in _lines: + m = re.match(r'^package_version *= *[\'"](.+)[\'"].*$', _line) + if m: + break + if m: + return m.group(1) + else: + return 'unknown' + +# The short X.Y version. +# Note: We use the full version in both cases. +version = parse_version() + +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ["tests", ".tox", ".git", "build_docs", "ld.egg-info"] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. +# See http://www.sphinx-doc.org/en/stable/theming.html for built-in themes. +html_theme = "classic" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. +# See http://www.sphinx-doc.org/en/stable/theming.html for the options +# available for built-in themes. +html_theme_options = { +} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If not defined, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = 'distro' + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['html_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +html_extra_path = ['html_extra'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'distro_doc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'ld.tex', _short_description, author, 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'ld', _short_description, [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'LinuxDistribution', _short_description, + author, 'LinuxDistribution', _short_description, + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for autodoc extension ---------------------------------------- +# For documentation, see +# http://www.sphinx-doc.org/en/stable/ext/autodoc.html + +# Selects what content will be inserted into a class description. +# The possible values are: +# "class" - Only the class’ docstring is inserted. This is the default. +# "both" - Both the class’ and the __init__ method’s docstring are +# concatenated and inserted. +# "init" - Only the __init__ method’s docstring is inserted. +autoclass_content = "both" + +# Selects if automatically documented members are sorted alphabetically +# (value 'alphabetical'), by member type (value 'groupwise') or by source +# order (value 'bysource'). The default is alphabetical. +autodoc_member_order = "bysource" + +# -- Options for intersphinx extension ------------------------------------ +# For documentation, see +# http://www.sphinx-doc.org/en/stable/ext/intersphinx.html + +# Defines the prefixes for intersphinx links, and the targets they resolve +# to. Example RST source for 'py' prefix: +# :py:func:`platform.dist` +intersphinx_mapping = { + 'py': ('https://docs.python.org/3.5', None) +} + +intersphinx_cache_limit = 5 diff --git a/third_party/python/distro/docs/index.rst b/third_party/python/distro/docs/index.rst new file mode 100644 --- /dev/null +++ b/third_party/python/distro/docs/index.rst @@ -0,0 +1,476 @@ + +.. _distro official repo: https://github.com/nir0s/distro +.. _distro issue tracker: https://github.com/nir0s/distro/issues +.. _open issues on missing test data: https://github.com/nir0s/distro/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22> + + +**distro** package (Linux Distribution) version |version| +********************************************************* + +Official distro repository: `distro official repo`_ + +Overview and motivation +======================= + +.. automodule:: distro + +If you want to jump into the API description right away, read about the +`consolidated accessor functions`_. + +Compatibility +============= + +The ``distro`` package is supported on Python 2.7, 3.4+ and PyPy, and on +any Linux or *BSD distribution that provides one or more of the `data sources`_ +used by this package. + +This package is tested on Python 2.7, 3.4+ and PyPy, with test data that +mimics the exact behavior of the data sources of +`a number of Linux distributions `_. + +If you want to add test data for more distributions, please +create an issue in the `distro issue tracker`_ +and provide the following information in the issue: + +* The content of the `/etc/os-release` file, if any. +* The file names and content of the `/etc/*release` and `/etc/*version` files, if any. +* The output of the command: `lsb_release -a`, if available. +* The file names and content of any other files you are aware of that provide + useful information about the distro. + +There are already some `open issues on missing test data`_. + + +Data sources +============ + +The ``distro`` package implements a robust and inclusive way of retrieving the +information about a Linux distribution based on new standards and old methods, +namely from these data sources: + +* The `os-release file`_, if present. + +* The `lsb_release command output`_, if the lsb_release command is available. + +* The `distro release file`_, if present. + +* The `uname command output`_, if present. + + +Access to the information +========================= + +This package provides three ways to access the information about a Linux +distribution: + +* `Consolidated accessor functions`_ + + These are module-global functions that take into account all data sources in + a priority order, and that return information about the current Linux + distribution. + + These functions should be the normal way to access the information. + + The precedence of data sources is applied for each information item + separately. Therefore, it is possible that not all information items returned + by these functions come from the same data source. For example, on a + distribution that has an lsb_release command that returns the + "Distributor ID" field but not the "Codename" field, and that has a distro + release file that specifies a codename inside, the distro ID will come from + the lsb_release command (because it has higher precedence), and the codename + will come from the distro release file (because it is not provided by the + lsb_release command). + + Examples: :func:`distro.id` for retrieving + the distro ID, or :func:`ld.info` to get the machine-readable part of the + information in a more aggregated way, or :func:`distro.linux_distribution` with + an interface that is compatible to the original + :py:func:`platform.linux_distribution` function, supporting a subset of its + parameters. + +* `Single source accessor functions`_ + + These are module-global functions that take into account a single data + source, and that return information about the current Linux distribution. + + They are useful for distributions that provide multiple inconsistent data + sources, or for retrieving information items that are not provided by the + consolidated accessor functions. + + Examples: :func:`distro.os_release_attr` for retrieving a single information + item from the os-release data source, or :func:`distro.lsb_release_info` for + retrieving all information items from the lsb_release command output data + source. + +* `LinuxDistribution class`_ + + The :class:`distro.LinuxDistribution` class provides the main code of this + package. + + This package contains a private module-global :class:`distro.LinuxDistribution` + instance with default initialization arguments, that is used by the + consolidated and single source accessor functions. + + A user-defined instance of the :class:`distro.LinuxDistribution` class allows + specifying the path names of the os-release file and distro release file and + whether the lsb_release command should be used or not. That is useful for + example when the distribution information from a chrooted environment + is to be retrieved, or when a distro has multiple distro release files and + the default algorithm uses the wrong one. + + +Consolidated accessor functions +=============================== + +This section describes the consolidated accessor functions. +See `access to the information`_ for a discussion of the different kinds of +accessor functions. + +.. autofunction:: distro.linux_distribution +.. autofunction:: distro.id +.. autofunction:: distro.name +.. autofunction:: distro.version +.. autofunction:: distro.version_parts +.. autofunction:: distro.major_version +.. autofunction:: distro.minor_version +.. autofunction:: distro.build_number +.. autofunction:: distro.like +.. autofunction:: distro.codename +.. autofunction:: distro.info + +Single source accessor functions +================================ + +This section describes the single source accessor functions. +See `access to the information`_ for a discussion of the different kinds of +accessor functions. + +.. autofunction:: distro.os_release_info +.. autofunction:: distro.lsb_release_info +.. autofunction:: distro.distro_release_info +.. autofunction:: distro.os_release_attr +.. autofunction:: distro.lsb_release_attr +.. autofunction:: distro.distro_release_attr + +LinuxDistribution class +======================= + +This section describes the access via the :class:`distro.LinuxDistribution` class. +See `access to the information`_ for a discussion of the different kinds of +accessor functions. + +.. autoclass:: distro.LinuxDistribution + :members: + :undoc-members: + +Normalization tables +==================== + +These translation tables are used to normalize the parsed distro ID values +into reliable IDs. See :func:`distro.id` for details. + +They are documented in order to show for which distros a normalization is +currently defined. + +As a quick fix, these tables can also be extended by the user by appending new +entries, should the need arise. If you have a need to get these tables +extended, please make an according request in the `distro issue tracker`_. + +.. autodata:: distro.NORMALIZED_OS_ID +.. autodata:: distro.NORMALIZED_LSB_ID +.. autodata:: distro.NORMALIZED_DISTRO_ID + +Os-release file +=============== + +The os-release file is looked up using the path name ``/etc/os-release``. Its +optional additional location ``/usr/lib/os-release`` is ignored. + +The os-release file is expected to be encoded in UTF-8. + +It is parsed using the standard Python :py:mod:`shlex` package, which treats it +like a shell script. + +The attribute names found in the file are translated to lower case and then +become the keys of the information items from the os-release file data source. +These keys can be used to retrieve single items with the +:func:`distro.os_release_attr` function, and they are also used as keys in the +dictionary returned by :func:`distro.os_release_info`. + +The attribute values found in the file are processed using shell rules (e.g. +for whitespace, escaping, and quoting) before they become the values of the +information items from the os-release file data source. + +If the attribute "VERSION" is found in the file, the distro codename is +extracted from its value if it can be found there. If a codename is found, it +becomes an additional information item with key "codename". + +See the `os-release man page +`_ +for a list of possible attributes in the file. + +**Examples:** + +1. The following os-release file content: + + .. sourcecode:: shell + + NAME='Ubuntu' + VERSION="14.04.3 LTS, Trusty Tahr" + ID=ubuntu + ID_LIKE=debian + PRETTY_NAME="Ubuntu 14.04.3 LTS" + VERSION_ID="14.04" + HOME_URL="http://www.ubuntu.com/" + SUPPORT_URL="http://help.ubuntu.com/" + BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" + + results in these information items: + + =============================== ========================================== + Key Value + =============================== ========================================== + name "Ubuntu" + version "14.04.3 LTS, Trusty Tahr" + id "ubuntu" + id_like "debian" + pretty_name "Ubuntu 14.04.3 LTS" + version_id "14.04" + home_url "http://www.ubuntu.com/" + support_url "http://help.ubuntu.com/" + bug_report_url "http://bugs.launchpad.net/ubuntu/" + codename "Trusty Tahr" + =============================== ========================================== + +2. The following os-release file content: + + .. sourcecode:: shell + + NAME="Red Hat Enterprise Linux Server" + VERSION="7.0 (Maipo)" + ID="rhel" + ID_LIKE="fedora" + VERSION_ID="7.0" + PRETTY_NAME="Red Hat Enterprise Linux Server 7.0 (Maipo)" + ANSI_COLOR="0;31" + CPE_NAME="cpe:/o:redhat:enterprise_linux:7.0:GA:server" + HOME_URL="https://www.redhat.com/" + BUG_REPORT_URL="https://bugzilla.redhat.com/" + + REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 7" + REDHAT_BUGZILLA_PRODUCT_VERSION=7.0 + REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux" + REDHAT_SUPPORT_PRODUCT_VERSION=7.0 + + results in these information items: + + =============================== ========================================== + Key Value + =============================== ========================================== + name "Red Hat Enterprise Linux Server" + version "7.0 (Maipo)" + id "rhel" + id_like "fedora" + version_id "7.0" + pretty_name "Red Hat Enterprise Linux Server 7.0 (Maipo)" + ansi_color "0;31" + cpe_name "cpe:/o:redhat:enterprise_linux:7.0:GA:server" + home_url "https://www.redhat.com/" + bug_report_url "https://bugzilla.redhat.com/" + redhat_bugzilla_product "Red Hat Enterprise Linux 7" + redhat_bugzilla_product_version "7.0" + redhat_support_product "Red Hat Enterprise Linux" + redhat_support_product_version "7.0" + codename "Maipo" + =============================== ========================================== + +Lsb_release command output +========================== + +The lsb_release command is expected to be in the PATH, and is invoked as +follows: + +.. sourcecode:: shell + + lsb_release -a + +The command output is expected to be encoded in UTF-8. + +Only lines in the command output with the following format will be used: + + ``: `` + +Where: + +* ```` is the name of the attribute, and +* ```` is the attribute value. + +The attribute names are stripped from surrounding blanks, any remaining blanks +are translated to underscores, they are translated to lower case, and then +become the keys of the information items from the lsb_release command output +data source. + +The attribute values are stripped from surrounding blanks, and then become the +values of the information items from the lsb_release command output data +source. + +See the `lsb_release man page +`_ +for a description of standard attributes returned by the lsb_release command. + +**Examples:** + +1. The following lsb_release command output: + + .. sourcecode:: text + + No LSB modules are available. + Distributor ID: Ubuntu + Description: Ubuntu 14.04.3 LTS + Release: 14.04 + Codename: trusty + + results in these information items: + + =============================== ========================================== + Key Value + =============================== ========================================== + distributor_id "Ubuntu" + description "Ubuntu 14.04.3 LTS" + release "14.04" + codename "trusty" + =============================== ========================================== + +2. The following lsb_release command output: + + .. sourcecode:: text + + LSB Version: n/a + Distributor ID: SUSE LINUX + Description: SUSE Linux Enterprise Server 12 SP1 + Release: 12.1 + Codename: n/a + + results in these information items: + + =============================== ========================================== + Key Value + =============================== ========================================== + lsb_version "n/a" + distributor_id "SUSE LINUX" + description "SUSE Linux Enterprise Server 12 SP1" + release "12.1" + codename "n/a" + =============================== ========================================== + +Distro release file +=================== + +Unless specified with a particular path name when using the +:class:`distro.LinuxDistribution` class, the distro release file is found by using +the first match in the alphabetically sorted list of the files matching the +following path name patterns: + +* ``/etc/*-release`` +* ``/etc/*_release`` +* ``/etc/*-version`` +* ``/etc/*_version`` + +where the following special path names are excluded: + +* ``/etc/debian_version`` +* ``/etc/system-release`` +* ``/etc/os-release`` + +and where the first line within the file has the expected format. + +The algorithm to sort the files alphabetically is far from perfect, but the +distro release file has the least priority as a data source, and it is expected +that distributions provide one of the other data sources. + +The distro release file is expected to be encoded in UTF-8. + +Only its first line is used, and it is expected to have the following format: + + `` [[[release] ] ()]`` + +Where: + +* square brackets indicate optionality, +* ```` is the distro name, +* ```` is the distro version, and +* ```` is the distro codename. + +The following information items can be found in a distro release file +(shown with their keys and data types): + +* ``id`` (string): Distro ID, taken from the first part of the file name + before the hyphen (``-``) or underscore (``_``). + + Note that the distro ID is not normalized or translated to lower case at this + point; this happens only for the result of the :func:`distro.id` function. + +* ``name`` (string): Distro name, as found in the first line of the file. + +* ``version_id`` (string): Distro version, as found in the first line of the + file. If not found, this information item will not exist. + +* ``codename`` (string): Distro codename, as found in the first line of the + file. If not found, this information item will not exist. + + Note that the string in the codename field is not always really a + codename. For example, openSUSE returns "x86_64". + +**Examples:** + +1. The following distro release file ``/etc/centos-release``: + + .. sourcecode:: text + + CentOS Linux release 7.1.1503 (Core) + + results in these information items: + + =============================== ========================================== + Key Value + =============================== ========================================== + id "centos" + name "CentOS Linux" + version_id "7.1.1503" + codename "Core" + =============================== ========================================== + +2. The following distro release file ``/etc/oracle-release``: + + .. sourcecode:: text + + Oracle Linux Server release 7.1 + + results in these information items: + + =============================== ========================================== + Key Value + =============================== ========================================== + id "oracle" + name "Oracle Linux Server" + version_id "7.1" + =============================== ========================================== + +3. The following distro release file ``/etc/SuSE-release``: + + .. sourcecode:: text + + openSUSE 42.1 (x86_64) + + results in these information items: + + =============================== ========================================== + Key Value + =============================== ========================================== + id "SuSE" + name "openSUSE" + version_id "42.1" + codename "x86_64" + =============================== ========================================== + diff --git a/third_party/python/distro/query_local_distro.py b/third_party/python/distro/query_local_distro.py new file mode 100755 --- /dev/null +++ b/third_party/python/distro/query_local_distro.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# Copyright 2015,2016 Nir Cohen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function + +from pprint import pformat + +import distro + + +def pprint(obj): + for line in pformat(obj).split('\n'): + print(4 * ' ' + line) + + +print('os_release_info:') +pprint(distro.os_release_info()) +print('lsb_release_info:') +pprint(distro.lsb_release_info()) +print('distro_release_info:') +pprint(distro.distro_release_info()) +print('id: {0}'.format(distro.id())) +print('name: {0}'.format(distro.name())) +print('name_pretty: {0}'.format(distro.name(True))) +print('version: {0}'.format(distro.version())) +print('version_pretty: {0}'.format(distro.version(True))) +print('like: {0}'.format(distro.like())) +print('codename: {0}'.format(distro.codename())) +print('linux_distribution_full: {0}'.format(distro.linux_distribution())) +print('linux_distribution: {0}'.format(distro.linux_distribution(False))) +print('major_version: {0}'.format(distro.major_version())) +print('minor_version: {0}'.format(distro.minor_version())) +print('build_number: {0}'.format(distro.build_number())) diff --git a/third_party/python/distro/setup.cfg b/third_party/python/distro/setup.cfg new file mode 100644 --- /dev/null +++ b/third_party/python/distro/setup.cfg @@ -0,0 +1,10 @@ +[bdist_wheel] +universal = 1 + +[metadata] +license_file = LICENSE + +[egg_info] +tag_build = +tag_date = 0 + diff --git a/third_party/python/distro/setup.py b/third_party/python/distro/setup.py new file mode 100644 --- /dev/null +++ b/third_party/python/distro/setup.py @@ -0,0 +1,67 @@ +# Copyright 2015,2016 Nir Cohen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import codecs +from setuptools import setup + +# The following version is parsed by other parts of this package. +# Don't change the format of the line, or the variable name. +package_version = "1.4.0" + +here = os.path.abspath(os.path.dirname(__file__)) + + +def read(*parts): + # intentionally *not* adding an encoding option to open + return codecs.open(os.path.join(here, *parts), 'r').read() + + +setup( + name='distro', + version=package_version, + url='https://github.com/nir0s/distro', + author='Nir Cohen', + author_email='nir36g@gmail.com', + license='Apache License, Version 2.0', + platforms='All', + description='Distro - an OS platform information API', + long_description=read('README.md'), + long_description_content_type='text/markdown', + py_modules=['distro'], + entry_points={ + 'console_scripts': [ + 'distro = distro:main', + ] + }, + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: POSIX :: Linux', + 'Operating System :: POSIX :: BSD', + 'Operating System :: POSIX :: BSD :: FreeBSD', + 'Operating System :: POSIX :: BSD :: NetBSD', + 'Operating System :: POSIX :: BSD :: OpenBSD', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: System :: Operating System', + ] +) diff --git a/third_party/python/distro/tests/__init__.py b/third_party/python/distro/tests/__init__.py new file mode 100644 diff --git a/third_party/python/distro/tests/resources/distros/__shared__/bin/lsb_release b/third_party/python/distro/tests/resources/distros/__shared__/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/__shared__/bin/lsb_release @@ -0,0 +1,43 @@ +#!/bin/bash +# +# lsb_release command for testing the ld module. +# Only the -a option is supported. +# +# This version of the lsb_release command reads an lsb-release file. +# +# The lsb-release file has the usual format, e.g.: +# DISTRIB_ID=Ubuntu +# DISTRIB_RELEASE=14.04 +# DISTRIB_CODENAME=trusty +# DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS" +# Where each line is optional. If a line is missing, the default value +# will be the empty string. +# + +if [[ "$@" != "-a" ]]; then + echo "Usage: lsb_release -a" + exit 2 +fi + +# Because the PATH is set to just this directory, we cannot use 'dirname' +# or other external programs, but need to use built-in abilities of bash. +LSB_FILE="${0%/*}/../etc/lsb-release" + +if [[ ! -f $LSB_FILE ]]; then + echo "Error: LSB release file does not exist: $LSB_FILE" + exit 1 +fi + +source $LSB_FILE + +if [[ -n $LSB_VERSION ]]; then + echo "LSB Version: $LSB_VERSION" +else + echo "No LSB modules are available." +fi +echo "Distributor ID: ${DISTRIB_ID:-}" +echo "Description: ${DISTRIB_DESCRIPTION:-}" +echo "Release: ${DISTRIB_RELEASE:-}" +echo "Codename: ${DISTRIB_CODENAME:-}" + +exit 0 diff --git a/third_party/python/distro/tests/resources/distros/amazon2014/etc/system-release b/third_party/python/distro/tests/resources/distros/amazon2014/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/amazon2014/etc/system-release @@ -0,0 +1,1 @@ +Amazon Linux AMI release 2014.03 \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/amazon2016/etc/os-release b/third_party/python/distro/tests/resources/distros/amazon2016/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/amazon2016/etc/os-release @@ -0,0 +1,9 @@ +NAME="Amazon Linux AMI" +VERSION="2016.03" +ID="amzn" +ID_LIKE="rhel fedora" +VERSION_ID="2016.03" +PRETTY_NAME="Amazon Linux AMI 2016.03" +ANSI_COLOR="0;33" +CPE_NAME="cpe:/o:amazon:linux:2016.03:ga" +HOME_URL="http://aws.amazon.com/amazon-linux-ami/" diff --git a/third_party/python/distro/tests/resources/distros/amazon2016/etc/system-release b/third_party/python/distro/tests/resources/distros/amazon2016/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/amazon2016/etc/system-release @@ -0,0 +1,1 @@ +Amazon Linux AMI release 2016.03 diff --git a/third_party/python/distro/tests/resources/distros/arch/etc/arch-release b/third_party/python/distro/tests/resources/distros/arch/etc/arch-release new file mode 100644 diff --git a/third_party/python/distro/tests/resources/distros/arch/etc/os-release b/third_party/python/distro/tests/resources/distros/arch/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/arch/etc/os-release @@ -0,0 +1,7 @@ +NAME="Arch Linux" +ID=arch +PRETTY_NAME="Arch Linux" +ANSI_COLOR="0;36" +HOME_URL="https://www.archlinux.org/" +SUPPORT_URL="https://bbs.archlinux.org/" +BUG_REPORT_URL="https://bugs.archlinux.org/" diff --git a/third_party/python/distro/tests/resources/distros/arch/usr/lib/os-release b/third_party/python/distro/tests/resources/distros/arch/usr/lib/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/arch/usr/lib/os-release @@ -0,0 +1,7 @@ +NAME="Arch Linux" +ID=arch +PRETTY_NAME="Arch Linux" +ANSI_COLOR="0;36" +HOME_URL="https://www.archlinux.org/" +SUPPORT_URL="https://bbs.archlinux.org/" +BUG_REPORT_URL="https://bugs.archlinux.org/" diff --git a/third_party/python/distro/tests/resources/distros/centos5/etc/centos-release b/third_party/python/distro/tests/resources/distros/centos5/etc/centos-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/centos5/etc/centos-release @@ -0,0 +1,1 @@ +CentOS release 5.11 (Final) diff --git a/third_party/python/distro/tests/resources/distros/centos5/etc/redhat-release b/third_party/python/distro/tests/resources/distros/centos5/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/centos5/etc/redhat-release @@ -0,0 +1,1 @@ +CentOS release 5.11 (Final) diff --git a/third_party/python/distro/tests/resources/distros/centos5/etc/system-release b/third_party/python/distro/tests/resources/distros/centos5/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/centos5/etc/system-release @@ -0,0 +1,1 @@ +CentOS release 5.11 (Final) diff --git a/third_party/python/distro/tests/resources/distros/centos7/etc/centos-release b/third_party/python/distro/tests/resources/distros/centos7/etc/centos-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/centos7/etc/centos-release @@ -0,0 +1,1 @@ +CentOS Linux release 7.1.1503 (Core) diff --git a/third_party/python/distro/tests/resources/distros/centos7/etc/os-release b/third_party/python/distro/tests/resources/distros/centos7/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/centos7/etc/os-release @@ -0,0 +1,16 @@ +NAME="CentOS Linux" +VERSION="7 (Core)" +ID="centos" +ID_LIKE="rhel fedora" +VERSION_ID="7" +PRETTY_NAME="CentOS Linux 7 (Core)" +ANSI_COLOR="0;31" +CPE_NAME="cpe:/o:centos:centos:7" +HOME_URL="https://www.centos.org/" +BUG_REPORT_URL="https://bugs.centos.org/" + +CENTOS_MANTISBT_PROJECT="CentOS-7" +CENTOS_MANTISBT_PROJECT_VERSION="7" +REDHAT_SUPPORT_PRODUCT="centos" +REDHAT_SUPPORT_PRODUCT_VERSION="7" + diff --git a/third_party/python/distro/tests/resources/distros/centos7/etc/redhat-release b/third_party/python/distro/tests/resources/distros/centos7/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/centos7/etc/redhat-release @@ -0,0 +1,1 @@ +CentOS Linux release 7.1.1503 (Core) diff --git a/third_party/python/distro/tests/resources/distros/centos7/etc/system-release b/third_party/python/distro/tests/resources/distros/centos7/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/centos7/etc/system-release @@ -0,0 +1,1 @@ +CentOS Linux release 7.1.1503 (Core) diff --git a/third_party/python/distro/tests/resources/distros/cloudlinux5/etc/redhat-release b/third_party/python/distro/tests/resources/distros/cloudlinux5/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/cloudlinux5/etc/redhat-release @@ -0,0 +1,1 @@ +CloudLinux Server release 5.11 (Vladislav Volkov) diff --git a/third_party/python/distro/tests/resources/distros/cloudlinux6/etc/redhat-release b/third_party/python/distro/tests/resources/distros/cloudlinux6/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/cloudlinux6/etc/redhat-release @@ -0,0 +1,1 @@ +CloudLinux Server release 6.8 (Oleg Makarov) diff --git a/third_party/python/distro/tests/resources/distros/cloudlinux7/etc/os-release b/third_party/python/distro/tests/resources/distros/cloudlinux7/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/cloudlinux7/etc/os-release @@ -0,0 +1,10 @@ +NAME="CloudLinux" +VERSION="7.3 (Yury Malyshev)" +ID="cloudlinux" +ID_LIKE="rhel fedora centos" +VERSION_ID="7.3" +PRETTY_NAME="CloudLinux 7.3 (Yury Malyshev)" +ANSI_COLOR="0:31" +CPE_NAME="cpe:/o:cloudlinux:cloudlinux:7.3:GA:server" +HOME_URL="https://www.cloudlinux.com/" +BUG_REPORT_URL="https://helpdesk.cloudlinux.com/" diff --git a/third_party/python/distro/tests/resources/distros/cloudlinux7/etc/redhat-release b/third_party/python/distro/tests/resources/distros/cloudlinux7/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/cloudlinux7/etc/redhat-release @@ -0,0 +1,1 @@ +CloudLinux release 7.3 (Yury Malyshev) diff --git a/third_party/python/distro/tests/resources/distros/coreos/etc/oem-release b/third_party/python/distro/tests/resources/distros/coreos/etc/oem-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/coreos/etc/oem-release @@ -0,0 +1,5 @@ +ID=digitalocean +VERSION_ID=0.0.4 +NAME="DigitalOcean" +HOME_URL="https://www.digitalocean.com/" +BUG_REPORT_URL="https://github.com/coreos/bugs/issues" \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/coreos/etc/os-release b/third_party/python/distro/tests/resources/distros/coreos/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/coreos/etc/os-release @@ -0,0 +1,9 @@ +NAME=CoreOS +ID=coreos +VERSION=899.15.0 +VERSION_ID=899.15.0 +BUILD_ID=2016-04-05-1035 +PRETTY_NAME="CoreOS 899.15.0" +ANSI_COLOR="1;32" +HOME_URL="https://coreos.com/" +BUG_REPORT_URL="https://github.com/coreos/bugs/issues" \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/debian8/bin/lsb_release b/third_party/python/distro/tests/resources/distros/debian8/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/debian8/bin/lsb_release @@ -0,0 +1,21 @@ +#!/bin/bash +# +# lsb_release command for testing the ld module. +# Only the -a option is supported. +# +# This version of the lsb_release command works without a corresponding +# etc/lsb-release file. +# + +if [[ "$@" != "-a" ]]; then + echo "Usage: lsb_release -a" + exit 2 +fi + +echo "No LSB modules are available." +echo "Distributor ID: Debian" +echo "Description: Debian GNU/Linux 8.2 (jessie)" +echo "Release: 8.2" +echo "Codename: jessie" + +exit 0 diff --git a/third_party/python/distro/tests/resources/distros/debian8/etc/debian_version b/third_party/python/distro/tests/resources/distros/debian8/etc/debian_version new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/debian8/etc/debian_version @@ -0,0 +1,1 @@ +8.2 \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/debian8/etc/os-release b/third_party/python/distro/tests/resources/distros/debian8/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/debian8/etc/os-release @@ -0,0 +1,8 @@ +PRETTY_NAME="Debian GNU/Linux 8 (jessie)" +NAME="Debian GNU/Linux" +VERSION_ID="8" +VERSION="8 (jessie)" +ID=debian +HOME_URL="http://www.debian.org/" +SUPPORT_URL="http://www.debian.org/support/" +BUG_REPORT_URL="https://bugs.debian.org/" diff --git a/third_party/python/distro/tests/resources/distros/exherbo/etc/os-release b/third_party/python/distro/tests/resources/distros/exherbo/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/exherbo/etc/os-release @@ -0,0 +1,7 @@ +NAME="Exherbo" +PRETTY_NAME="Exherbo Linux" +ID="exherbo" +ANSI_COLOR="0;32" +HOME_URL="https://www.exherbo.org/" +SUPPORT_URL="irc://irc.freenode.net/#exherbo" +BUG_REPORT_URL="https://bugs.exherbo.org/" diff --git a/third_party/python/distro/tests/resources/distros/fedora19/etc/fedora-release b/third_party/python/distro/tests/resources/distros/fedora19/etc/fedora-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora19/etc/fedora-release @@ -0,0 +1,1 @@ +Fedora release 19 (SchrΓΆdinger’s Cat) diff --git a/third_party/python/distro/tests/resources/distros/fedora19/etc/issue b/third_party/python/distro/tests/resources/distros/fedora19/etc/issue new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora19/etc/issue @@ -0,0 +1,3 @@ +Fedora release 19 (SchrΓΆdinger’s Cat) +Kernel \r on an \m (\l) + diff --git a/third_party/python/distro/tests/resources/distros/fedora19/etc/issue.net b/third_party/python/distro/tests/resources/distros/fedora19/etc/issue.net new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora19/etc/issue.net @@ -0,0 +1,2 @@ +Fedora release 19 (SchrΓΆdinger’s Cat) +Kernel \r on an \m (\l) diff --git a/third_party/python/distro/tests/resources/distros/fedora19/etc/os-release b/third_party/python/distro/tests/resources/distros/fedora19/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora19/etc/os-release @@ -0,0 +1,7 @@ +NAME=Fedora +VERSION="19 (SchrΓΆdinger’s Cat)" +ID=fedora +VERSION_ID=19 +PRETTY_NAME="Fedora 19 (SchrΓΆdinger’s Cat)" +ANSI_COLOR="0;34" +CPE_NAME="cpe:/o:fedoraproject:fedora:19" diff --git a/third_party/python/distro/tests/resources/distros/fedora19/etc/redhat-release b/third_party/python/distro/tests/resources/distros/fedora19/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora19/etc/redhat-release @@ -0,0 +1,1 @@ +Fedora release 19 (SchrΓΆdinger’s Cat) diff --git a/third_party/python/distro/tests/resources/distros/fedora19/etc/system-release b/third_party/python/distro/tests/resources/distros/fedora19/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora19/etc/system-release @@ -0,0 +1,1 @@ +Fedora release 19 (SchrΓΆdinger’s Cat) diff --git a/third_party/python/distro/tests/resources/distros/fedora19/etc/system-release-cpe b/third_party/python/distro/tests/resources/distros/fedora19/etc/system-release-cpe new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora19/etc/system-release-cpe @@ -0,0 +1,1 @@ +cpe:/o:fedoraproject:fedora:19 diff --git a/third_party/python/distro/tests/resources/distros/fedora23/etc/fedora-release b/third_party/python/distro/tests/resources/distros/fedora23/etc/fedora-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora23/etc/fedora-release @@ -0,0 +1,1 @@ +Fedora release 23 (Twenty Three) diff --git a/third_party/python/distro/tests/resources/distros/fedora23/etc/os-release b/third_party/python/distro/tests/resources/distros/fedora23/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora23/etc/os-release @@ -0,0 +1,14 @@ +NAME=Fedora +VERSION="23 (Twenty Three)" +ID=fedora +VERSION_ID=23 +PRETTY_NAME="Fedora 23 (Twenty Three)" +ANSI_COLOR="0;34" +CPE_NAME="cpe:/o:fedoraproject:fedora:23" +HOME_URL="https://fedoraproject.org/" +BUG_REPORT_URL="https://bugzilla.redhat.com/" +REDHAT_BUGZILLA_PRODUCT="Fedora" +REDHAT_BUGZILLA_PRODUCT_VERSION=23 +REDHAT_SUPPORT_PRODUCT="Fedora" +REDHAT_SUPPORT_PRODUCT_VERSION=23 +PRIVACY_POLICY_URL=https://fedoraproject.org/wiki/Legal:PrivacyPolicy diff --git a/third_party/python/distro/tests/resources/distros/fedora23/etc/redhat-release b/third_party/python/distro/tests/resources/distros/fedora23/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora23/etc/redhat-release @@ -0,0 +1,1 @@ +Fedora release 23 (Twenty Three) diff --git a/third_party/python/distro/tests/resources/distros/fedora23/etc/system-release b/third_party/python/distro/tests/resources/distros/fedora23/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora23/etc/system-release @@ -0,0 +1,1 @@ +Fedora release 23 (Twenty Three) diff --git a/third_party/python/distro/tests/resources/distros/fedora23/usr/lib/os-release b/third_party/python/distro/tests/resources/distros/fedora23/usr/lib/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora23/usr/lib/os-release @@ -0,0 +1,14 @@ +NAME=Fedora +VERSION="23 (Twenty Three)" +ID=fedora +VERSION_ID=23 +PRETTY_NAME="Fedora 23 (Twenty Three)" +ANSI_COLOR="0;34" +CPE_NAME="cpe:/o:fedoraproject:fedora:23" +HOME_URL="https://fedoraproject.org/" +BUG_REPORT_URL="https://bugzilla.redhat.com/" +REDHAT_BUGZILLA_PRODUCT="Fedora" +REDHAT_BUGZILLA_PRODUCT_VERSION=23 +REDHAT_SUPPORT_PRODUCT="Fedora" +REDHAT_SUPPORT_PRODUCT_VERSION=23 +PRIVACY_POLICY_URL=https://fedoraproject.org/wiki/Legal:PrivacyPolicy diff --git a/third_party/python/distro/tests/resources/distros/fedora30/etc/fedora-release b/third_party/python/distro/tests/resources/distros/fedora30/etc/fedora-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora30/etc/fedora-release @@ -0,0 +1,1 @@ +Fedora release 30 (Thirty) diff --git a/third_party/python/distro/tests/resources/distros/fedora30/etc/os-release b/third_party/python/distro/tests/resources/distros/fedora30/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora30/etc/os-release @@ -0,0 +1,19 @@ +NAME=Fedora +VERSION="30 (Thirty)" +ID=fedora +VERSION_ID=30 +VERSION_CODENAME="" +PLATFORM_ID="platform:f30" +PRETTY_NAME="Fedora 30 (Thirty)" +ANSI_COLOR="0;34" +LOGO=fedora-logo-icon +CPE_NAME="cpe:/o:fedoraproject:fedora:30" +HOME_URL="https://fedoraproject.org/" +DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/30/system-administrators-guide/" +SUPPORT_URL="https://fedoraproject.org/wiki/Communicating_and_getting_help" +BUG_REPORT_URL="https://bugzilla.redhat.com/" +REDHAT_BUGZILLA_PRODUCT="Fedora" +REDHAT_BUGZILLA_PRODUCT_VERSION=30 +REDHAT_SUPPORT_PRODUCT="Fedora" +REDHAT_SUPPORT_PRODUCT_VERSION=30 +PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy" diff --git a/third_party/python/distro/tests/resources/distros/fedora30/etc/redhat-release b/third_party/python/distro/tests/resources/distros/fedora30/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora30/etc/redhat-release @@ -0,0 +1,1 @@ +Fedora release 30 (Thirty) diff --git a/third_party/python/distro/tests/resources/distros/fedora30/etc/system-release b/third_party/python/distro/tests/resources/distros/fedora30/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora30/etc/system-release @@ -0,0 +1,1 @@ +Fedora release 30 (Thirty) diff --git a/third_party/python/distro/tests/resources/distros/fedora30/usr/lib/os-release b/third_party/python/distro/tests/resources/distros/fedora30/usr/lib/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/fedora30/usr/lib/os-release @@ -0,0 +1,19 @@ +NAME=Fedora +VERSION="30 (Thirty)" +ID=fedora +VERSION_ID=30 +VERSION_CODENAME="" +PLATFORM_ID="platform:f30" +PRETTY_NAME="Fedora 30 (Thirty)" +ANSI_COLOR="0;34" +LOGO=fedora-logo-icon +CPE_NAME="cpe:/o:fedoraproject:fedora:30" +HOME_URL="https://fedoraproject.org/" +DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/30/system-administrators-guide/" +SUPPORT_URL="https://fedoraproject.org/wiki/Communicating_and_getting_help" +BUG_REPORT_URL="https://bugzilla.redhat.com/" +REDHAT_BUGZILLA_PRODUCT="Fedora" +REDHAT_BUGZILLA_PRODUCT_VERSION=30 +REDHAT_SUPPORT_PRODUCT="Fedora" +REDHAT_SUPPORT_PRODUCT_VERSION=30 +PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy" diff --git a/third_party/python/distro/tests/resources/distros/freebsd111/bin/uname b/third_party/python/distro/tests/resources/distros/freebsd111/bin/uname new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/freebsd111/bin/uname @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "FreeBSD 11.1-RELEASE" + diff --git a/third_party/python/distro/tests/resources/distros/gentoo/etc/gentoo-release b/third_party/python/distro/tests/resources/distros/gentoo/etc/gentoo-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/gentoo/etc/gentoo-release @@ -0,0 +1,1 @@ +Gentoo Base System release 2.2 \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/gentoo/etc/os-release b/third_party/python/distro/tests/resources/distros/gentoo/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/gentoo/etc/os-release @@ -0,0 +1,7 @@ +NAME=Gentoo +ID=gentoo +PRETTY_NAME="Gentoo/Linux" +ANSI_COLOR="1;32" +HOME_URL="http://www.gentoo.org/" +SUPPORT_URL="http://www.gentoo.org/main/en/support.xml" +BUG_REPORT_URL="https://bugs.gentoo.org/" diff --git a/third_party/python/distro/tests/resources/distros/kali/etc/os-release b/third_party/python/distro/tests/resources/distros/kali/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/kali/etc/os-release @@ -0,0 +1,10 @@ +PRETTY_NAME="Kali GNU/Linux Rolling" +NAME="Kali GNU/Linux" +ID=kali +VERSION="2017.1" +VERSION_ID="2017.1" +ID_LIKE=debian +ANSI_COLOR="1;31" +HOME_URL="http://www.kali.org/" +SUPPORT_URL="http://forums.kali.org/" +BUG_REPORT_URL="http://bugs.kali.org/" diff --git a/third_party/python/distro/tests/resources/distros/kvmibm1/bin/lsb_release b/third_party/python/distro/tests/resources/distros/kvmibm1/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/kvmibm1/bin/lsb_release @@ -0,0 +1,21 @@ +#!/bin/bash +# +# lsb_release command for testing the ld module. +# Only the -a option is supported. +# +# This version of the lsb_release command works without a corresponding +# etc/lsb-release file. +# + +if [[ "$@" != "-a" ]]; then + echo "Usage: lsb_release -a" + exit 2 +fi + +echo "LSB Version: :core-4.1-noarch:core-4.1-s390x" +echo "Distributor ID: kvmibm" +echo "Description: KVM for IBM z Systems release 1.1.1 (Z) " +echo "Release: 1.1.1" +echo "Codename: Z" + +exit 0 diff --git a/third_party/python/distro/tests/resources/distros/kvmibm1/etc/base-release b/third_party/python/distro/tests/resources/distros/kvmibm1/etc/base-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/kvmibm1/etc/base-release @@ -0,0 +1,1 @@ +KVM for IBM z Systems release 1.1.1 (Z) diff --git a/third_party/python/distro/tests/resources/distros/kvmibm1/etc/os-release b/third_party/python/distro/tests/resources/distros/kvmibm1/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/kvmibm1/etc/os-release @@ -0,0 +1,9 @@ +NAME="KVM for IBM z Systems" +VERSION="1.1.1 (Z)" +ID="kvmibm" +ID_LIKE="rhel fedora" +VERSION_ID="1.1.1" +PRETTY_NAME="KVM for IBM z Systems 1.1.1 (Z)" +ANSI_COLOR="0;34" +CPE_NAME="cpe:/o:ibm:kvmibm:1.1.1" +BUILD_ID="20160316" diff --git a/third_party/python/distro/tests/resources/distros/kvmibm1/etc/redhat-release b/third_party/python/distro/tests/resources/distros/kvmibm1/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/kvmibm1/etc/redhat-release @@ -0,0 +1,1 @@ +KVM for IBM z Systems release 1.1.1 (Z) diff --git a/third_party/python/distro/tests/resources/distros/kvmibm1/etc/system-release b/third_party/python/distro/tests/resources/distros/kvmibm1/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/kvmibm1/etc/system-release @@ -0,0 +1,1 @@ +KVM for IBM z Systems release 1.1.1 (Z) diff --git a/third_party/python/distro/tests/resources/distros/linuxmint17/bin/lsb_release b/third_party/python/distro/tests/resources/distros/linuxmint17/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/linuxmint17/bin/lsb_release @@ -0,0 +1,43 @@ +#!/bin/bash +# +# lsb_release command for testing the ld module. +# Only the -a option is supported. +# +# This version of the lsb_release command reads an lsb-release file. +# +# The lsb-release file has the usual format, e.g.: +# DISTRIB_ID=Ubuntu +# DISTRIB_RELEASE=14.04 +# DISTRIB_CODENAME=trusty +# DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS" +# Where each line is optional. If a line is missing, the default value +# will be the empty string. +# + +if [[ "$@" != "-a" ]]; then + echo "Usage: lsb_release -a" + exit 2 +fi + +# Because the PATH is set to just this directory, we cannot use 'dirname' +# or other external programs, but need to use built-in abilities of bash. +LSB_FILE="${0%/*}/../etc/lsb-release" + +if [[ ! -f $LSB_FILE ]]; then + echo "Error: LSB release file does not exist: $LSB_FILE" + exit 1 +fi + +source $LSB_FILE + +if [[ -n $LSB_VERSION ]]; then + echo "LSB Version: $LSB_VERSION" +else + echo "No LSB modules are available." +fi +echo "Distributor ID: ${DISTRIB_ID:-}" +echo "Description: ${DISTRIB_DESCRIPTION:-}" +echo "Release: ${DISTRIB_RELEASE:-}" +echo "Codename: ${DISTRIB_CODENAME:-}" + +exit 0 diff --git a/third_party/python/distro/tests/resources/distros/linuxmint17/etc/debian_version b/third_party/python/distro/tests/resources/distros/linuxmint17/etc/debian_version new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/linuxmint17/etc/debian_version @@ -0,0 +1,1 @@ +jessie/sid diff --git a/third_party/python/distro/tests/resources/distros/linuxmint17/etc/lsb-release b/third_party/python/distro/tests/resources/distros/linuxmint17/etc/lsb-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/linuxmint17/etc/lsb-release @@ -0,0 +1,4 @@ +DISTRIB_ID=LinuxMint +DISTRIB_RELEASE=17.3 +DISTRIB_CODENAME=rosa +DISTRIB_DESCRIPTION="Linux Mint 17.3 Rosa" diff --git a/third_party/python/distro/tests/resources/distros/linuxmint17/etc/os-release b/third_party/python/distro/tests/resources/distros/linuxmint17/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/linuxmint17/etc/os-release @@ -0,0 +1,9 @@ +NAME="Ubuntu" +VERSION="14.04.3 LTS, Trusty Tahr" +ID=ubuntu +ID_LIKE=debian +PRETTY_NAME="Ubuntu 14.04.3 LTS" +VERSION_ID="14.04" +HOME_URL="http://www.ubuntu.com/" +SUPPORT_URL="http://help.ubuntu.com/" +BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" diff --git a/third_party/python/distro/tests/resources/distros/linuxmint17/etc/upstream-release/lsb-release b/third_party/python/distro/tests/resources/distros/linuxmint17/etc/upstream-release/lsb-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/linuxmint17/etc/upstream-release/lsb-release @@ -0,0 +1,4 @@ +DISTRIB_ID=Ubuntu +DISTRIB_RELEASE=14.04 +DISTRIB_CODENAME=trusty +DISTRIB_DESCRIPTION="Ubuntu 14.04 LTS" diff --git a/third_party/python/distro/tests/resources/distros/mageia5/bin/lsb_release b/third_party/python/distro/tests/resources/distros/mageia5/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/bin/lsb_release @@ -0,0 +1,39 @@ +#!/bin/bash +# +# lsb_release command for testing the ld module. +# Only the -a option is supported. +# +# This version of the lsb_release command reads an lsb-release file. +# +# The lsb-release file has the usual format, e.g.: +# DISTRIB_ID=Ubuntu +# DISTRIB_RELEASE=14.04 +# DISTRIB_CODENAME=trusty +# DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS" +# Where each line is optional. If a line is missing, the default value +# will be the empty string. +# + +if [[ "$@" != "-a" ]]; then + echo "Usage: lsb_release -a" + exit 2 +fi + +# Because the PATH is set to just this directory, we cannot use 'dirname' +# or other external programs, but need to use built-in abilities of bash. +LSB_FILE="${0%/*}/../etc/lsb-release" + +if [[ ! -f $LSB_FILE ]]; then + echo "Error: LSB release file does not exist: $LSB_FILE" + exit 1 +fi + +source $LSB_FILE + +echo "LSB Version: ${LSB_VERSION:-*}" +echo "Distributor ID: ${DISTRIB_ID:-}" +echo "Description: ${DISTRIB_DESCRIPTION:-}" +echo "Release: ${DISTRIB_RELEASE:-}" +echo "Codename: ${DISTRIB_CODENAME:-}" + +exit 0 diff --git a/third_party/python/distro/tests/resources/distros/mageia5/etc/lsb-release b/third_party/python/distro/tests/resources/distros/mageia5/etc/lsb-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/etc/lsb-release @@ -0,0 +1,5 @@ +LSB_VERSION= +DISTRIB_ID="Mageia" +DISTRIB_RELEASE=5 +DISTRIB_CODENAME=thornicroft +DISTRIB_DESCRIPTION="Mageia 5" diff --git a/third_party/python/distro/tests/resources/distros/mageia5/etc/mageia-release b/third_party/python/distro/tests/resources/distros/mageia5/etc/mageia-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/etc/mageia-release @@ -0,0 +1,1 @@ +Mageia release 5 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mageia5/etc/mandrake-release b/third_party/python/distro/tests/resources/distros/mageia5/etc/mandrake-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/etc/mandrake-release @@ -0,0 +1,1 @@ +Mageia release 5 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mageia5/etc/mandrakelinux-release b/third_party/python/distro/tests/resources/distros/mageia5/etc/mandrakelinux-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/etc/mandrakelinux-release @@ -0,0 +1,1 @@ +Mageia release 5 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mageia5/etc/mandriva-release b/third_party/python/distro/tests/resources/distros/mageia5/etc/mandriva-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/etc/mandriva-release @@ -0,0 +1,1 @@ +Mageia release 5 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mageia5/etc/os-release b/third_party/python/distro/tests/resources/distros/mageia5/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/etc/os-release @@ -0,0 +1,10 @@ +NAME="Mageia" +VERSION="5" +ID=mageia +VERSION_ID=5 +ID_LIKE="mandriva fedora" +PRETTY_NAME="Mageia 5" +ANSI_COLOR="1;36" +HOME_URL="http://www.mageia.org/" +SUPPORT_URL="http://www.mageia.org/support/" +BUG_REPORT_URL="https://bugs.mageia.org/" diff --git a/third_party/python/distro/tests/resources/distros/mageia5/etc/redhat-release b/third_party/python/distro/tests/resources/distros/mageia5/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/etc/redhat-release @@ -0,0 +1,1 @@ +Mageia release 5 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mageia5/etc/release b/third_party/python/distro/tests/resources/distros/mageia5/etc/release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/etc/release @@ -0,0 +1,1 @@ +Mageia release 5 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mageia5/etc/version b/third_party/python/distro/tests/resources/distros/mageia5/etc/version new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/etc/version @@ -0,0 +1,1 @@ +5 2 official diff --git a/third_party/python/distro/tests/resources/distros/mageia5/usr/lib/os-release b/third_party/python/distro/tests/resources/distros/mageia5/usr/lib/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mageia5/usr/lib/os-release @@ -0,0 +1,10 @@ +NAME="Mageia" +VERSION="5" +ID=mageia +VERSION_ID=5 +ID_LIKE="mandriva fedora" +PRETTY_NAME="Mageia 5" +ANSI_COLOR="1;36" +HOME_URL="http://www.mageia.org/" +SUPPORT_URL="http://www.mageia.org/support/" +BUG_REPORT_URL="https://bugs.mageia.org/" diff --git a/third_party/python/distro/tests/resources/distros/mandriva2011/bin/lsb_release b/third_party/python/distro/tests/resources/distros/mandriva2011/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mandriva2011/bin/lsb_release @@ -0,0 +1,39 @@ +#!/bin/bash +# +# lsb_release command for testing the ld module. +# Only the -a option is supported. +# +# This version of the lsb_release command reads an lsb-release file. +# +# The lsb-release file has the usual format, e.g.: +# DISTRIB_ID=Ubuntu +# DISTRIB_RELEASE=14.04 +# DISTRIB_CODENAME=trusty +# DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS" +# Where each line is optional. If a line is missing, the default value +# will be the empty string. +# + +if [[ "$@" != "-a" ]]; then + echo "Usage: lsb_release -a" + exit 2 +fi + +# Because the PATH is set to just this directory, we cannot use 'dirname' +# or other external programs, but need to use built-in abilities of bash. +LSB_FILE="${0%/*}/../etc/lsb-release" + +if [[ ! -f $LSB_FILE ]]; then + echo "Error: LSB release file does not exist: $LSB_FILE" + exit 1 +fi + +source $LSB_FILE + +echo "LSB Version: ${LSB_VERSION:-*}" +echo "Distributor ID: ${DISTRIB_ID:-}" +echo "Description: ${DISTRIB_DESCRIPTION:-}" +echo "Release: ${DISTRIB_RELEASE:-}" +echo "Codename: ${DISTRIB_CODENAME:-}" + +exit 0 diff --git a/third_party/python/distro/tests/resources/distros/mandriva2011/etc/lsb-release b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/lsb-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/lsb-release @@ -0,0 +1,5 @@ +LSB_VERSION= +DISTRIB_ID=MandrivaLinux +DISTRIB_RELEASE=2011.0 +DISTRIB_CODENAME=turtle +DISTRIB_DESCRIPTION="Mandriva Linux 2011.0" diff --git a/third_party/python/distro/tests/resources/distros/mandriva2011/etc/mandrake-release b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/mandrake-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/mandrake-release @@ -0,0 +1,1 @@ +Mandriva Linux release 2011.0 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mandriva2011/etc/mandrakelinux-release b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/mandrakelinux-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/mandrakelinux-release @@ -0,0 +1,1 @@ +Mandriva Linux release 2011.0 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mandriva2011/etc/mandriva-release b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/mandriva-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/mandriva-release @@ -0,0 +1,1 @@ +Mandriva Linux release 2011.0 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mandriva2011/etc/redhat-release b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/redhat-release @@ -0,0 +1,1 @@ +Mandriva Linux release 2011.0 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mandriva2011/etc/release b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/release @@ -0,0 +1,1 @@ +Mandriva Linux release 2011.0 (Official) for x86_64 diff --git a/third_party/python/distro/tests/resources/distros/mandriva2011/etc/version b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/version new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/mandriva2011/etc/version @@ -0,0 +1,1 @@ +2011.0.0 2 cooker diff --git a/third_party/python/distro/tests/resources/distros/manjaro1512/bin/lsb_release b/third_party/python/distro/tests/resources/distros/manjaro1512/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/manjaro1512/bin/lsb_release @@ -0,0 +1,43 @@ +#!/bin/bash +# +# lsb_release command for testing the ld module. +# Only the -a option is supported. +# +# This version of the lsb_release command reads an lsb-release file. +# +# The lsb-release file has the usual format, e.g.: +# DISTRIB_ID=Ubuntu +# DISTRIB_RELEASE=14.04 +# DISTRIB_CODENAME=trusty +# DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS" +# Where each line is optional. If a line is missing, the default value +# will be the empty string. +# + +if [[ "$@" != "-a" ]]; then + echo "Usage: lsb_release -a" + exit 2 +fi + +# Because the PATH is set to just this directory, we cannot use 'dirname' +# or other external programs, but need to use built-in abilities of bash. +LSB_FILE="${0%/*}/../etc/lsb-release" + +if [[ ! -f $LSB_FILE ]]; then + echo "Error: LSB release file does not exist: $LSB_FILE" + exit 1 +fi + +source $LSB_FILE + +if [[ -n $LSB_VERSION ]]; then + echo "LSB Version: $LSB_VERSION" +else + echo "No LSB modules are available." +fi +echo "Distributor ID: ${DISTRIB_ID:-}" +echo "Description: ${DISTRIB_DESCRIPTION:-}" +echo "Release: ${DISTRIB_RELEASE:-}" +echo "Codename: ${DISTRIB_CODENAME:-}" + +exit 0 diff --git a/third_party/python/distro/tests/resources/distros/manjaro1512/etc/lsb-release b/third_party/python/distro/tests/resources/distros/manjaro1512/etc/lsb-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/manjaro1512/etc/lsb-release @@ -0,0 +1,4 @@ +DISTRIB_ID=ManjaroLinux +DISTRIB_RELEASE=15.12 +DISTRIB_CODENAME=Capella +DISTRIB_DESCRIPTION="Manjaro Linux" diff --git a/third_party/python/distro/tests/resources/distros/manjaro1512/etc/manjaro-release b/third_party/python/distro/tests/resources/distros/manjaro1512/etc/manjaro-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/manjaro1512/etc/manjaro-release @@ -0,0 +1,1 @@ +Manjaro Linux diff --git a/third_party/python/distro/tests/resources/distros/manjaro1512/etc/os-release b/third_party/python/distro/tests/resources/distros/manjaro1512/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/manjaro1512/etc/os-release @@ -0,0 +1,7 @@ +NAME="Manjaro Linux" +ID=manjaro +PRETTY_NAME="Manjaro Linux" +ANSI_COLOR="1;32" +HOME_URL="http://www.manjaro.org/" +SUPPORT_URL="http://www.manjaro.org/" +BUG_REPORT_URL="http://bugs.manjaro.org/" diff --git a/third_party/python/distro/tests/resources/distros/netbsd711/bin/uname b/third_party/python/distro/tests/resources/distros/netbsd711/bin/uname new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/netbsd711/bin/uname @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "NetBSD 7.1.1" + diff --git a/third_party/python/distro/tests/resources/distros/openbsd62/bin/uname b/third_party/python/distro/tests/resources/distros/openbsd62/bin/uname new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/openbsd62/bin/uname @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "OpenBSD 6.2" + diff --git a/third_party/python/distro/tests/resources/distros/openelec6/etc/os-release b/third_party/python/distro/tests/resources/distros/openelec6/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/openelec6/etc/os-release @@ -0,0 +1,9 @@ +NAME="OpenELEC" +VERSION="6.0.3" +ID="openelec" +VERSION_ID="6.0" +PRETTY_NAME="OpenELEC (official) - Version: 6.0.3" +HOME_URL="http://www.openelec.tv" +BUG_REPORT_URL="https://github.com/OpenELEC/OpenELEC.tv" +OPENELEC_ARCH="imx6.arm" +OPENELEC_BUILD="official" \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/opensuse42/etc/SuSE-release b/third_party/python/distro/tests/resources/distros/opensuse42/etc/SuSE-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/opensuse42/etc/SuSE-release @@ -0,0 +1,1 @@ +openSUSE 42.1 (x86_64) \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/opensuse42/etc/os-release b/third_party/python/distro/tests/resources/distros/opensuse42/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/opensuse42/etc/os-release @@ -0,0 +1,10 @@ +NAME="openSUSE Leap" +VERSION="42.1" +VERSION_ID="42.1" +PRETTY_NAME="openSUSE Leap 42.1 (x86_64)" +ID=opensuse +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:opensuse:opensuse:42.1" +BUG_REPORT_URL="https://bugs.opensuse.org" +HOME_URL="https://opensuse.org/" +ID_LIKE="suse" diff --git a/third_party/python/distro/tests/resources/distros/oracle7/etc/oracle-release b/third_party/python/distro/tests/resources/distros/oracle7/etc/oracle-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/oracle7/etc/oracle-release @@ -0,0 +1,1 @@ +Oracle Linux Server release 7.5 \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/oracle7/etc/os-release b/third_party/python/distro/tests/resources/distros/oracle7/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/oracle7/etc/os-release @@ -0,0 +1,14 @@ +NAME="Oracle Linux Server" +VERSION="7.5" +ID="ol" +VERSION_ID="7.5" +PRETTY_NAME="Oracle Linux Server 7.5" +ANSI_COLOR="0;31" +CPE_NAME="cpe:/o:oracle:linux:7:5:server" +HOME_URL="https://linux.oracle.com/" +BUG_REPORT_URL="https://bugzilla.oracle.com/" + +ORACLE_BUGZILLA_PRODUCT="Oracle Linux 7" +ORACLE_BUGZILLA_PRODUCT_VERSION=7.5 +ORACLE_SUPPORT_PRODUCT="Oracle Linux" +ORACLE_SUPPORT_PRODUCT_VERSION=7.5 diff --git a/third_party/python/distro/tests/resources/distros/raspbian7/etc/debian_version b/third_party/python/distro/tests/resources/distros/raspbian7/etc/debian_version new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/raspbian7/etc/debian_version @@ -0,0 +1,1 @@ +7.1 \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/raspbian7/etc/os-release b/third_party/python/distro/tests/resources/distros/raspbian7/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/raspbian7/etc/os-release @@ -0,0 +1,10 @@ +PRETTY_NAME="Raspbian GNU/Linux 7 (wheezy)" +NAME="Raspbian GNU/Linux" +VERSION_ID="7" +VERSION="7 (wheezy)" +ID=raspbian +ID_LIKE=debian +ANSI_COLOR="1;31" +HOME_URL="http://www.raspbian.org/" +SUPPORT_URL="http://www.raspbian.org/RaspbianForums" +BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs" \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/raspbian7/etc/os-release.orig b/third_party/python/distro/tests/resources/distros/raspbian7/etc/os-release.orig new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/raspbian7/etc/os-release.orig @@ -0,0 +1,9 @@ +PRETTY_NAME="Debian #OSNAME# 7 (wheezy)" +NAME="Debian #OSNAME#" +VERSION_ID="7" +VERSION="7 (wheezy)" +ID=debian +ANSI_COLOR="1;31" +HOME_URL="http://www.debian.org/" +SUPPORT_URL="http://www.debian.org/support/" +BUG_REPORT_URL="http://bugs.debian.org/" \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/raspbian8/etc/debian_version b/third_party/python/distro/tests/resources/distros/raspbian8/etc/debian_version new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/raspbian8/etc/debian_version @@ -0,0 +1,1 @@ +8.0 \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/raspbian8/etc/os-release b/third_party/python/distro/tests/resources/distros/raspbian8/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/raspbian8/etc/os-release @@ -0,0 +1,9 @@ +PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)" +NAME="Raspbian GNU/Linux" +VERSION_ID="8" +VERSION="8 (jessie)" +ID=raspbian +ID_LIKE=debian +HOME_URL="http://www.raspbian.org/" +SUPPORT_URL="http://www.raspbian.org/RaspbianForums" +BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs" \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/rhel5/etc/redhat-release b/third_party/python/distro/tests/resources/distros/rhel5/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/rhel5/etc/redhat-release @@ -0,0 +1,1 @@ +Red Hat Enterprise Linux Server release 5.11 (Tikanga) diff --git a/third_party/python/distro/tests/resources/distros/rhel6/etc/redhat-release b/third_party/python/distro/tests/resources/distros/rhel6/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/rhel6/etc/redhat-release @@ -0,0 +1,1 @@ +Red Hat Enterprise Linux Server release 6.5 (Santiago) diff --git a/third_party/python/distro/tests/resources/distros/rhel6/etc/system-release b/third_party/python/distro/tests/resources/distros/rhel6/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/rhel6/etc/system-release @@ -0,0 +1,1 @@ +Red Hat Enterprise Linux Server release 6.5 (Santiago) diff --git a/third_party/python/distro/tests/resources/distros/rhel7/etc/os-release b/third_party/python/distro/tests/resources/distros/rhel7/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/rhel7/etc/os-release @@ -0,0 +1,15 @@ +NAME="Red Hat Enterprise Linux Server" +VERSION="7.0 (Maipo)" +ID="rhel" +ID_LIKE="fedora" +VERSION_ID="7.0" +PRETTY_NAME="Red Hat Enterprise Linux Server 7.0 (Maipo)" +ANSI_COLOR="0;31" +CPE_NAME="cpe:/o:redhat:enterprise_linux:7.0:GA:server" +HOME_URL="https://www.redhat.com/" +BUG_REPORT_URL="https://bugzilla.redhat.com/" + +REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 7" +REDHAT_BUGZILLA_PRODUCT_VERSION=7.0 +REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux" +REDHAT_SUPPORT_PRODUCT_VERSION=7.0 diff --git a/third_party/python/distro/tests/resources/distros/rhel7/etc/redhat-release b/third_party/python/distro/tests/resources/distros/rhel7/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/rhel7/etc/redhat-release @@ -0,0 +1,1 @@ +Red Hat Enterprise Linux Server release 7.0 (Maipo) diff --git a/third_party/python/distro/tests/resources/distros/rhel7/etc/system-release b/third_party/python/distro/tests/resources/distros/rhel7/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/rhel7/etc/system-release @@ -0,0 +1,1 @@ +Red Hat Enterprise Linux Server release 7.0 (Maipo) diff --git a/third_party/python/distro/tests/resources/distros/scientific6/etc/redhat-release b/third_party/python/distro/tests/resources/distros/scientific6/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/scientific6/etc/redhat-release @@ -0,0 +1,1 @@ +Scientific Linux release 6.4 (Carbon) \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/scientific6/etc/system-release b/third_party/python/distro/tests/resources/distros/scientific6/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/scientific6/etc/system-release @@ -0,0 +1,1 @@ +Scientific Linux release 6.4 (Carbon) \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/scientific7/etc/os-release b/third_party/python/distro/tests/resources/distros/scientific7/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/scientific7/etc/os-release @@ -0,0 +1,15 @@ +NAME="Scientific Linux" +VERSION="7.2 (Nitrogen)" +ID="rhel" +ID_LIKE="fedora" +VERSION_ID="7.2" +PRETTY_NAME="Scientific Linux 7.2 (Nitrogen)" +ANSI_COLOR="0;31" +CPE_NAME="cpe:/o:scientificlinux:scientificlinux:7.2:GA" +HOME_URL="http://www.scientificlinux.org//" +BUG_REPORT_URL="mailto:scientific-linux-devel@listserv.fnal.gov" + +REDHAT_BUGZILLA_PRODUCT="Scientific Linux 7" +REDHAT_BUGZILLA_PRODUCT_VERSION=7.2 +REDHAT_SUPPORT_PRODUCT="Scientific Linux" +REDHAT_SUPPORT_PRODUCT_VERSION="7.2" diff --git a/third_party/python/distro/tests/resources/distros/scientific7/etc/redhat-release b/third_party/python/distro/tests/resources/distros/scientific7/etc/redhat-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/scientific7/etc/redhat-release @@ -0,0 +1,1 @@ +Scientific Linux release 7.2 (Nitrogen) \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/scientific7/etc/sl-release b/third_party/python/distro/tests/resources/distros/scientific7/etc/sl-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/scientific7/etc/sl-release @@ -0,0 +1,1 @@ +Scientific Linux release 7.2 (Nitrogen) \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/scientific7/etc/system-release b/third_party/python/distro/tests/resources/distros/scientific7/etc/system-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/scientific7/etc/system-release @@ -0,0 +1,1 @@ +Scientific Linux release 7.2 (Nitrogen) \ No newline at end of file diff --git a/third_party/python/distro/tests/resources/distros/slackware14/etc/os-release b/third_party/python/distro/tests/resources/distros/slackware14/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/slackware14/etc/os-release @@ -0,0 +1,10 @@ +NAME=Slackware +VERSION="14.1" +ID=slackware +VERSION_ID=14.1 +PRETTY_NAME="Slackware 14.1" +ANSI_COLOR="0;34" +CPE_NAME="cpe:/o:slackware:slackware_linux:14.1" +HOME_URL="http://slackware.com/" +SUPPORT_URL="http://www.linuxquestions.org/questions/slackware-14/" +BUG_REPORT_URL="http://www.linuxquestions.org/questions/slackware-14/" diff --git a/third_party/python/distro/tests/resources/distros/slackware14/etc/slackware-version b/third_party/python/distro/tests/resources/distros/slackware14/etc/slackware-version new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/slackware14/etc/slackware-version @@ -0,0 +1,1 @@ +Slackware 14.1 diff --git a/third_party/python/distro/tests/resources/distros/sles12/bin/lsb_release b/third_party/python/distro/tests/resources/distros/sles12/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/sles12/bin/lsb_release @@ -0,0 +1,21 @@ +#!/bin/bash +# +# lsb_release command for testing the ld module. +# Only the -a option is supported. +# +# This version of the lsb_release command works without a corresponding +# etc/lsb-release file. +# + +if [[ "$@" != "-a" ]]; then + echo "Usage: lsb_release -a" + exit 2 +fi + +echo "LSB Version: n/a" +echo "Distributor ID: SUSE LINUX" +echo "Description: SUSE Linux Enterprise Server 12 SP1" +echo "Release: 12.1" +echo "Codename: n/a" + +exit 0 diff --git a/third_party/python/distro/tests/resources/distros/sles12/etc/SuSE-release b/third_party/python/distro/tests/resources/distros/sles12/etc/SuSE-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/sles12/etc/SuSE-release @@ -0,0 +1,5 @@ +SUSE Linux Enterprise Server 12 (s390x) +VERSION = 12 +PATCHLEVEL = 1 +# This file is deprecated and will be removed in a future service pack or release. +# Please check /etc/os-release for details about this release. diff --git a/third_party/python/distro/tests/resources/distros/sles12/etc/os-release b/third_party/python/distro/tests/resources/distros/sles12/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/sles12/etc/os-release @@ -0,0 +1,7 @@ +NAME="SLES" +VERSION="12-SP1" +VERSION_ID="12.1" +PRETTY_NAME="SUSE Linux Enterprise Server 12 SP1" +ID="sles" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:suse:sles:12:sp1" diff --git a/third_party/python/distro/tests/resources/distros/ubuntu14/bin/lsb_release b/third_party/python/distro/tests/resources/distros/ubuntu14/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/ubuntu14/bin/lsb_release @@ -0,0 +1,39 @@ +#!/bin/bash +# +# lsb_release command for testing the ld module. +# Only the -a option is supported. +# +# This version of the lsb_release command reads an lsb-release file. +# +# The lsb-release file has the usual format, e.g.: +# DISTRIB_ID=Ubuntu +# DISTRIB_RELEASE=14.04 +# DISTRIB_CODENAME=trusty +# DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS" +# Where each line is optional. If a line is missing, the default value +# will be the empty string. +# + +if [[ "$@" != "-a" ]]; then + echo "Usage: lsb_release -a" + exit 2 +fi + +# Because the PATH is set to just this directory, we cannot use 'dirname' +# or other external programs, but need to use built-in abilities of bash. +LSB_FILE="${0%/*}/../etc/lsb-release" + +if [[ ! -f $LSB_FILE ]]; then + echo "Error: LSB release file does not exist: $LSB_FILE" + exit 1 +fi + +source $LSB_FILE + +echo "No LSB modules are available." +echo "Distributor ID: ${DISTRIB_ID:-}" +echo "Description: ${DISTRIB_DESCRIPTION:-}" +echo "Release: ${DISTRIB_RELEASE:-}" +echo "Codename: ${DISTRIB_CODENAME:-}" + +exit 0 diff --git a/third_party/python/distro/tests/resources/distros/ubuntu14/etc/debian_version b/third_party/python/distro/tests/resources/distros/ubuntu14/etc/debian_version new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/ubuntu14/etc/debian_version @@ -0,0 +1,1 @@ +jessie/sid diff --git a/third_party/python/distro/tests/resources/distros/ubuntu14/etc/lsb-release b/third_party/python/distro/tests/resources/distros/ubuntu14/etc/lsb-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/ubuntu14/etc/lsb-release @@ -0,0 +1,4 @@ +DISTRIB_ID=Ubuntu +DISTRIB_RELEASE=14.04 +DISTRIB_CODENAME=trusty +DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS" diff --git a/third_party/python/distro/tests/resources/distros/ubuntu14/etc/os-release b/third_party/python/distro/tests/resources/distros/ubuntu14/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/ubuntu14/etc/os-release @@ -0,0 +1,9 @@ +NAME="Ubuntu" +VERSION="14.04.3 LTS, Trusty Tahr" +ID=ubuntu +ID_LIKE=debian +PRETTY_NAME="Ubuntu 14.04.3 LTS" +VERSION_ID="14.04" +HOME_URL="http://www.ubuntu.com/" +SUPPORT_URL="http://help.ubuntu.com/" +BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" diff --git a/third_party/python/distro/tests/resources/distros/ubuntu16/bin/lsb_release b/third_party/python/distro/tests/resources/distros/ubuntu16/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/ubuntu16/bin/lsb_release @@ -0,0 +1,39 @@ +#!/bin/bash +# +# lsb_release command for testing the ld module. +# Only the -a option is supported. +# +# This version of the lsb_release command reads an lsb-release file. +# +# The lsb-release file has the usual format, e.g.: +# DISTRIB_ID=Ubuntu +# DISTRIB_RELEASE=14.04 +# DISTRIB_CODENAME=trusty +# DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS" +# Where each line is optional. If a line is missing, the default value +# will be the empty string. +# + +if [[ "$@" != "-a" ]]; then + echo "Usage: lsb_release -a" + exit 2 +fi + +# Because the PATH is set to just this directory, we cannot use 'dirname' +# or other external programs, but need to use built-in abilities of bash. +LSB_FILE="${0%/*}/../etc/lsb-release" + +if [[ ! -f $LSB_FILE ]]; then + echo "Error: LSB release file does not exist: $LSB_FILE" + exit 1 +fi + +source $LSB_FILE + +echo "No LSB modules are available." +echo "Distributor ID: ${DISTRIB_ID:-}" +echo "Description: ${DISTRIB_DESCRIPTION:-}" +echo "Release: ${DISTRIB_RELEASE:-}" +echo "Codename: ${DISTRIB_CODENAME:-}" + +exit 0 diff --git a/third_party/python/distro/tests/resources/distros/ubuntu16/etc/debian_version b/third_party/python/distro/tests/resources/distros/ubuntu16/etc/debian_version new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/ubuntu16/etc/debian_version @@ -0,0 +1,1 @@ +stretch/sid diff --git a/third_party/python/distro/tests/resources/distros/ubuntu16/etc/lsb-release b/third_party/python/distro/tests/resources/distros/ubuntu16/etc/lsb-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/ubuntu16/etc/lsb-release @@ -0,0 +1,4 @@ +DISTRIB_ID=Ubuntu +DISTRIB_RELEASE=16.04 +DISTRIB_CODENAME=xenial +DISTRIB_DESCRIPTION="Ubuntu 16.04.1 LTS" diff --git a/third_party/python/distro/tests/resources/distros/ubuntu16/etc/os-release b/third_party/python/distro/tests/resources/distros/ubuntu16/etc/os-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/distros/ubuntu16/etc/os-release @@ -0,0 +1,10 @@ +NAME="Ubuntu" +VERSION="16.04.1 LTS (Xenial Xerus)" +ID=ubuntu +ID_LIKE=debian +PRETTY_NAME="Ubuntu 16.04.1 LTS" +VERSION_ID="16.04" +HOME_URL="http://www.ubuntu.com/" +SUPPORT_URL="http://help.ubuntu.com/" +BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" +UBUNTU_CODENAME=xenial diff --git a/third_party/python/distro/tests/resources/special/empty-release b/third_party/python/distro/tests/resources/special/empty-release new file mode 100644 diff --git a/third_party/python/distro/tests/resources/testdistros/distro/baduname/bin/uname b/third_party/python/distro/tests/resources/testdistros/distro/baduname/bin/uname new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/testdistros/distro/baduname/bin/uname @@ -0,0 +1,2 @@ +#!/bin/sh +echo "I'm a bad uname file!" diff --git a/third_party/python/distro/tests/resources/testdistros/distro/unknowndistro/etc/unknowndistro-release b/third_party/python/distro/tests/resources/testdistros/distro/unknowndistro/etc/unknowndistro-release new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/resources/testdistros/distro/unknowndistro/etc/unknowndistro-release @@ -0,0 +1,1 @@ +Unknown Distro release 1.0 (Unknown Codename) diff --git a/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc001/bin/lsb_release b/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc001/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc001/bin/lsb_release @@ -0,0 +1,5 @@ +#!/bin/bash +rc=1 +msg="General error" +echo "Test failure - exiting with $rc ($msg)" +exit $rc diff --git a/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc002/bin/lsb_release b/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc002/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc002/bin/lsb_release @@ -0,0 +1,5 @@ +#!/bin/bash +rc=2 +msg="Misuse of shell builtins, or missing keyword or command" +echo "Test failure - exiting with $rc ($msg)" +exit $rc diff --git a/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc126/bin/lsb_release b/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc126/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc126/bin/lsb_release @@ -0,0 +1,5 @@ +#!/bin/bash +rc=126 +msg="Cannot execute command" +echo "Test failure - exiting with $rc ($msg)" +exit $rc diff --git a/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc130/bin/lsb_release b/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc130/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc130/bin/lsb_release @@ -0,0 +1,5 @@ +#!/bin/bash +rc=130 +msg="Signal 2 - Script terminated with Ctrl-C" +echo "Test failure - exiting with $rc ($msg)" +exit $rc diff --git a/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc255/bin/lsb_release b/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc255/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/testdistros/lsb/lsb_rc255/bin/lsb_release @@ -0,0 +1,5 @@ +#!/bin/bash +rc=255 +msg="Exit code out of range" +echo "Test failure - exiting with $rc ($msg)" +exit $rc diff --git a/third_party/python/distro/tests/resources/testdistros/lsb/ubuntu14_nomodules/bin/lsb_release b/third_party/python/distro/tests/resources/testdistros/lsb/ubuntu14_nomodules/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/testdistros/lsb/ubuntu14_nomodules/bin/lsb_release @@ -0,0 +1,8 @@ +#!/bin/bash +/bin/cat <<'EOT' +No LSB modules are available. +Distributor ID: Ubuntu +Description: Ubuntu 14.04.3 LTS +Release: 14.04 +Codename: trusty +EOT diff --git a/third_party/python/distro/tests/resources/testdistros/lsb/ubuntu14_normal/bin/lsb_release b/third_party/python/distro/tests/resources/testdistros/lsb/ubuntu14_normal/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/testdistros/lsb/ubuntu14_normal/bin/lsb_release @@ -0,0 +1,7 @@ +#!/bin/bash +/bin/cat <<'EOT' +Distributor ID: Ubuntu +Description: Ubuntu 14.04.3 LTS +Release: 14.04 +Codename: trusty +EOT diff --git a/third_party/python/distro/tests/resources/testdistros/lsb/ubuntu14_trailingblanks/bin/lsb_release b/third_party/python/distro/tests/resources/testdistros/lsb/ubuntu14_trailingblanks/bin/lsb_release new file mode 100755 --- /dev/null +++ b/third_party/python/distro/tests/resources/testdistros/lsb/ubuntu14_trailingblanks/bin/lsb_release @@ -0,0 +1,8 @@ +#!/bin/bash +/bin/cat <<'EOT' +No LSB modules are available. +Distributor ID: Ubuntu +Description: Ubuntu 14.04.3 LTS +Release: 14.04 +Codename: trusty +EOT diff --git a/third_party/python/distro/tests/test_distro.py b/third_party/python/distro/tests/test_distro.py new file mode 100644 --- /dev/null +++ b/third_party/python/distro/tests/test_distro.py @@ -0,0 +1,2062 @@ +# Copyright 2015,2016 Nir Cohen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import sys +import ast +import subprocess +try: + from StringIO import StringIO # Python 2.x +except ImportError: + from io import StringIO # Python 3.x + +import pytest + + +BASE = os.path.abspath(os.path.dirname(__file__)) +RESOURCES = os.path.join(BASE, 'resources') +DISTROS_DIR = os.path.join(RESOURCES, 'distros') +TESTDISTROS = os.path.join(RESOURCES, 'testdistros') +SPECIAL = os.path.join(RESOURCES, 'special') +DISTROS = [dist for dist in os.listdir(DISTROS_DIR) if dist != '__shared__'] + + +IS_LINUX = sys.platform.startswith('linux') +if IS_LINUX: + import distro + + RELATIVE_UNIXCONFDIR = distro._UNIXCONFDIR[1:] + MODULE_DISTRO = distro._distro + + +class TestNonLinuxPlatform: + """Obviously, this only tests Windows. Will add OS X tests on Travis + Later + """ + + def test_cant_use_on_windows(self): + try: + import distro # NOQA + except ImportError as ex: + assert 'Unsupported platform' in str(ex) + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestCli: + + def _parse(self, command): + sys.argv = command.split() + distro.main() + + def _run(self, command): + stdout, _ = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate() + # Need to decode or we get bytes in Python 3.x + return stdout.decode('utf-8') + + def test_cli_for_coverage_yuch(self): + self._parse('distro') + self._parse('distro -j') + + def test_cli(self): + command = [sys.executable, '-m', 'distro'] + desired_output = 'Name: ' + distro.name(pretty=True) + distro_version = distro.version(pretty=True) + distro_codename = distro.codename() + desired_output += '\n' + 'Version: ' + distro_version + desired_output += '\n' + 'Codename: ' + distro_codename + desired_output += '\n' + assert self._run(command) == desired_output + + def test_cli_json(self): + command = [sys.executable, '-m', 'distro', '-j'] + assert ast.literal_eval(self._run(command)) == distro.info() + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class DistroTestCase(object): + """A base class for any testcase classes that test the distributions + represented in the `DISTROS` subtree. + """ + + def setup_method(self, test_method): + # The environment stays the same across all testcases, so we + # save and restore the PATH env var in each test case that + # changes it: + self._saved_path = os.environ["PATH"] + self._saved_UNIXCONFDIR = distro._UNIXCONFDIR + + def teardown_method(self, test_method): + os.environ["PATH"] = self._saved_path + distro._UNIXCONFDIR = self._saved_UNIXCONFDIR + + def _setup_for_distro(self, distro_root): + distro_bin = os.path.join(distro_root, 'bin') + # We don't want to pick up a possibly present lsb_release in the + # distro that runs this test, so we use a PATH with only one entry: + os.environ["PATH"] = distro_bin + distro._UNIXCONFDIR = os.path.join(distro_root, RELATIVE_UNIXCONFDIR) + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestOSRelease: + + def setup_method(self, test_method): + dist = test_method.__name__.split('_')[1] + os_release = os.path.join(DISTROS_DIR, dist, 'etc', 'os-release') + self.distro = distro.LinuxDistribution(False, os_release, 'non') + + def _test_outcome(self, outcome): + assert self.distro.id() == outcome.get('id', '') + assert self.distro.name() == outcome.get('name', '') + assert self.distro.name(pretty=True) == outcome.get('pretty_name', '') + assert self.distro.version() == outcome.get('version', '') + assert self.distro.version(pretty=True) == \ + outcome.get('pretty_version', '') + assert self.distro.version(best=True) == \ + outcome.get('best_version', '') + assert self.distro.like() == outcome.get('like', '') + assert self.distro.codename() == outcome.get('codename', '') + + def test_arch_os_release(self): + desired_outcome = { + 'id': 'arch', + 'name': 'Arch Linux', + 'pretty_name': 'Arch Linux', + } + self._test_outcome(desired_outcome) + + def test_kali_os_release(self): + desired_outcome = { + 'id': 'kali', + 'name': 'Kali GNU/Linux', + 'pretty_name': 'Kali GNU/Linux Rolling', + 'version': '2017.1', + 'pretty_version': '2017.1', + 'best_version': '2017.1', + 'like': 'debian' + } + self._test_outcome(desired_outcome) + + def test_centos7_os_release(self): + desired_outcome = { + 'id': 'centos', + 'name': 'CentOS Linux', + 'pretty_name': 'CentOS Linux 7 (Core)', + 'version': '7', + 'pretty_version': '7 (Core)', + 'best_version': '7', + 'like': 'rhel fedora', + 'codename': 'Core' + } + self._test_outcome(desired_outcome) + + def test_coreos_os_release(self): + desired_outcome = { + 'id': 'coreos', + 'name': 'CoreOS', + 'pretty_name': 'CoreOS 899.15.0', + 'version': '899.15.0', + 'pretty_version': '899.15.0', + 'best_version': '899.15.0' + } + self._test_outcome(desired_outcome) + + def test_debian8_os_release(self): + desired_outcome = { + 'id': 'debian', + 'name': 'Debian GNU/Linux', + 'pretty_name': 'Debian GNU/Linux 8 (jessie)', + 'version': '8', + 'pretty_version': '8 (jessie)', + 'best_version': '8', + 'codename': 'jessie' + } + self._test_outcome(desired_outcome) + + def test_fedora19_os_release(self): + desired_outcome = { + 'id': 'fedora', + 'name': 'Fedora', + 'pretty_name': u'Fedora 19 (Schr\u00F6dinger\u2019s Cat)', + 'version': '19', + 'pretty_version': u'19 (Schr\u00F6dinger\u2019s Cat)', + 'best_version': '19', + 'codename': u'Schr\u00F6dinger\u2019s Cat' + } + self._test_outcome(desired_outcome) + + def test_fedora23_os_release(self): + desired_outcome = { + 'id': 'fedora', + 'name': 'Fedora', + 'pretty_name': 'Fedora 23 (Twenty Three)', + 'version': '23', + 'pretty_version': '23 (Twenty Three)', + 'best_version': '23', + 'codename': 'Twenty Three' + } + self._test_outcome(desired_outcome) + + def test_fedora30_os_release(self): + # Fedora 21 and above no longer have code names but the metadata in os-release was only + # changed in a detectable way in Fedora 30+. The piece in parenthesis in the pretty_name + # field contains the VARIANT and differs depending on the variant which was installed. + desired_outcome = { + 'id': 'fedora', + 'name': 'Fedora', + 'pretty_name': 'Fedora 30 (Thirty)', + 'version': '30', + 'pretty_version': '30', + 'best_version': '30', + 'codename': '' + } + self._test_outcome(desired_outcome) + + def test_kvmibm1_os_release(self): + desired_outcome = { + 'id': 'kvmibm', + 'name': 'KVM for IBM z Systems', + 'pretty_name': 'KVM for IBM z Systems 1.1.1 (Z)', + 'version': '1.1.1', + 'pretty_version': '1.1.1 (Z)', + 'best_version': '1.1.1', + 'like': 'rhel fedora', + 'codename': 'Z' + } + self._test_outcome(desired_outcome) + + def test_linuxmint17_os_release(self): + # Note: LinuxMint 17 actually *does* have Ubuntu 14.04 data in its + # os-release file. See discussion in GitHub issue #78. + desired_outcome = { + 'id': 'ubuntu', + 'name': 'Ubuntu', + 'pretty_name': 'Ubuntu 14.04.3 LTS', + 'version': '14.04', + 'pretty_version': '14.04 (Trusty Tahr)', + 'best_version': '14.04.3', + 'like': 'debian', + 'codename': 'Trusty Tahr' + } + self._test_outcome(desired_outcome) + + def test_mageia5_os_release(self): + desired_outcome = { + 'id': 'mageia', + 'name': 'Mageia', + 'pretty_name': 'Mageia 5', + 'version': '5', + 'pretty_version': '5', + 'best_version': '5', + 'like': 'mandriva fedora', + } + self._test_outcome(desired_outcome) + + def test_manjaro1512_os_release(self): + self._test_outcome({ + 'id': 'manjaro', + 'name': 'Manjaro Linux', + 'pretty_name': 'Manjaro Linux', + }) + + def test_opensuse42_os_release(self): + desired_outcome = { + 'id': 'opensuse', + 'name': 'openSUSE Leap', + 'pretty_name': 'openSUSE Leap 42.1 (x86_64)', + 'version': '42.1', + 'pretty_version': '42.1', + 'best_version': '42.1', + 'like': 'suse', + } + self._test_outcome(desired_outcome) + + def test_raspbian7_os_release(self): + desired_outcome = { + 'id': 'raspbian', + 'name': 'Raspbian GNU/Linux', + 'pretty_name': 'Raspbian GNU/Linux 7 (wheezy)', + 'version': '7', + 'pretty_version': '7 (wheezy)', + 'best_version': '7', + 'like': 'debian', + 'codename': 'wheezy' + } + self._test_outcome(desired_outcome) + + def test_raspbian8_os_release(self): + desired_outcome = { + 'id': 'raspbian', + 'name': 'Raspbian GNU/Linux', + 'pretty_name': 'Raspbian GNU/Linux 8 (jessie)', + 'version': '8', + 'pretty_version': '8 (jessie)', + 'best_version': '8', + 'like': 'debian', + 'codename': 'jessie' + } + self._test_outcome(desired_outcome) + + def test_rhel7_os_release(self): + desired_outcome = { + 'id': 'rhel', + 'name': 'Red Hat Enterprise Linux Server', + 'pretty_name': 'Red Hat Enterprise Linux Server 7.0 (Maipo)', + 'version': '7.0', + 'pretty_version': '7.0 (Maipo)', + 'best_version': '7.0', + 'like': 'fedora', + 'codename': 'Maipo' + } + self._test_outcome(desired_outcome) + + def test_slackware14_os_release(self): + desired_outcome = { + 'id': 'slackware', + 'name': 'Slackware', + 'pretty_name': 'Slackware 14.1', + 'version': '14.1', + 'pretty_version': '14.1', + 'best_version': '14.1' + } + self._test_outcome(desired_outcome) + + def test_sles12_os_release(self): + desired_outcome = { + 'id': 'sles', + 'name': 'SLES', + 'pretty_name': 'SUSE Linux Enterprise Server 12 SP1', + 'version': '12.1', + 'pretty_version': '12.1', + 'best_version': '12.1' + } + self._test_outcome(desired_outcome) + + def test_ubuntu14_os_release(self): + desired_outcome = { + 'id': 'ubuntu', + 'name': 'Ubuntu', + 'pretty_name': 'Ubuntu 14.04.3 LTS', + 'version': '14.04', + 'pretty_version': '14.04 (Trusty Tahr)', + 'best_version': '14.04.3', + 'like': 'debian', + 'codename': 'Trusty Tahr' + } + self._test_outcome(desired_outcome) + + def test_ubuntu16_os_release(self): + desired_outcome = { + 'id': 'ubuntu', + 'name': 'Ubuntu', + 'pretty_name': 'Ubuntu 16.04.1 LTS', + 'version': '16.04', + 'pretty_version': '16.04 (xenial)', + 'best_version': '16.04.1', + 'like': 'debian', + 'codename': 'xenial' + } + self._test_outcome(desired_outcome) + + def test_amazon2016_os_release(self): + desired_outcome = { + 'id': 'amzn', + 'name': 'Amazon Linux AMI', + 'pretty_name': 'Amazon Linux AMI 2016.03', + 'version': '2016.03', + 'pretty_version': '2016.03', + 'best_version': '2016.03', + 'like': 'rhel fedora' + } + self._test_outcome(desired_outcome) + + def test_scientific7_os_release(self): + desired_outcome = { + 'id': 'rhel', + 'name': 'Scientific Linux', + 'pretty_name': 'Scientific Linux 7.2 (Nitrogen)', + 'version': '7.2', + 'pretty_version': '7.2 (Nitrogen)', + 'best_version': '7.2', + 'like': 'fedora', + 'codename': 'Nitrogen' + } + self._test_outcome(desired_outcome) + + def test_gentoo_os_release(self): + desired_outcome = { + 'id': 'gentoo', + 'name': 'Gentoo', + 'pretty_name': 'Gentoo/Linux', + } + self._test_outcome(desired_outcome) + + def test_openelec6_os_release(self): + desired_outcome = { + 'id': 'openelec', + 'name': 'OpenELEC', + 'pretty_name': 'OpenELEC (official) - Version: 6.0.3', + 'version': '6.0', + 'pretty_version': '6.0', + 'best_version': '6.0.3', + } + self._test_outcome(desired_outcome) + + def test_cloudlinux7_os_release(self): + desired_outcome = { + 'id': 'cloudlinux', + 'codename': 'Yury Malyshev', + 'name': 'CloudLinux', + 'pretty_name': 'CloudLinux 7.3 (Yury Malyshev)', + 'like': 'rhel fedora centos', + 'version': '7.3', + 'pretty_version': '7.3 (Yury Malyshev)', + 'best_version': '7.3', + 'major_version': '7', + 'minor_version': '3' + } + self._test_outcome(desired_outcome) + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestLSBRelease(DistroTestCase): + + def setup_method(self, test_method): + super(TestLSBRelease, self).setup_method(test_method) + dist = test_method.__name__.split('_')[1] + self._setup_for_distro(os.path.join(DISTROS_DIR, dist)) + self.distro = distro.LinuxDistribution(True, 'non', 'non') + + def _test_outcome(self, outcome): + assert self.distro.id() == outcome.get('id', '') + assert self.distro.name() == outcome.get('name', '') + assert self.distro.name(pretty=True) == outcome.get('pretty_name', '') + assert self.distro.version() == outcome.get('version', '') + assert self.distro.version(pretty=True) == \ + outcome.get('pretty_version', '') + assert self.distro.version(best=True) == \ + outcome.get('best_version', '') + assert self.distro.like() == outcome.get('like', '') + assert self.distro.codename() == outcome.get('codename', '') + + def test_linuxmint17_lsb_release(self): + desired_outcome = { + 'id': 'linuxmint', + 'name': 'LinuxMint', + 'pretty_name': 'Linux Mint 17.3 Rosa', + 'version': '17.3', + 'pretty_version': '17.3 (rosa)', + 'best_version': '17.3', + 'codename': 'rosa' + } + self._test_outcome(desired_outcome) + + def test_manjaro1512_lsb_release(self): + self._test_outcome({ + 'id': 'manjarolinux', + 'name': 'ManjaroLinux', + 'pretty_name': 'Manjaro Linux', + 'version': '15.12', + 'pretty_version': '15.12 (Capella)', + 'best_version': '15.12', + 'codename': 'Capella' + }) + + # @pytest.mark.xfail + # def test_openelec6_lsb_release(self): + # # TODO: This should be fixed as part of #109 when dealing + # # with distro inconsistencies + # desired_outcome = { + # 'id': 'openelec', + # 'name': 'OpenELEC', + # 'pretty_name': 'OpenELEC (official) - Version: 6.0.3', + # 'version': '6.0.3', + # 'pretty_version': '6.0.3', + # 'best_version': '6.0.3', + # } + # self._test_outcome(desired_outcome) + + def test_openbsd62_uname(self): + self._test_outcome({ + 'id': 'openbsd', + 'name': 'OpenBSD', + 'version': '6.2', + 'pretty_name': 'OpenBSD 6.2', + 'pretty_version': '6.2', + 'best_version': '6.2' + }) + + def test_netbsd711_uname(self): + self._test_outcome({ + 'id': 'netbsd', + 'name': 'NetBSD', + 'version': '7.1.1', + 'pretty_name': 'NetBSD 7.1.1', + 'pretty_version': '7.1.1', + 'best_version': '7.1.1' + }) + + def test_freebsd111_uname(self): + self._test_outcome({ + 'id': 'freebsd', + 'name': 'FreeBSD', + 'version': '11.1', + 'pretty_name': 'FreeBSD 11.1', + 'pretty_version': '11.1', + 'best_version': '11.1' + }) + + def test_ubuntu14normal_lsb_release(self): + self._setup_for_distro(os.path.join(TESTDISTROS, 'lsb', + 'ubuntu14_normal')) + + self.distro = distro.LinuxDistribution(True, 'non', 'non') + + desired_outcome = { + 'id': 'ubuntu', + 'name': 'Ubuntu', + 'pretty_name': 'Ubuntu 14.04.3 LTS', + 'version': '14.04', + 'pretty_version': '14.04 (trusty)', + 'best_version': '14.04.3', + 'codename': 'trusty' + } + self._test_outcome(desired_outcome) + + def test_ubuntu14nomodules_lsb_release(self): + self._setup_for_distro(os.path.join(TESTDISTROS, 'lsb', + 'ubuntu14_nomodules')) + + self.distro = distro.LinuxDistribution(True, 'non', 'non') + + desired_outcome = { + 'id': 'ubuntu', + 'name': 'Ubuntu', + 'pretty_name': 'Ubuntu 14.04.3 LTS', + 'version': '14.04', + 'pretty_version': '14.04 (trusty)', + 'best_version': '14.04.3', + 'codename': 'trusty' + } + self._test_outcome(desired_outcome) + + def test_trailingblanks_lsb_release(self): + self._setup_for_distro(os.path.join(TESTDISTROS, 'lsb', + 'ubuntu14_trailingblanks')) + + self.distro = distro.LinuxDistribution(True, 'non', 'non') + + desired_outcome = { + 'id': 'ubuntu', + 'name': 'Ubuntu', + 'pretty_name': 'Ubuntu 14.04.3 LTS', + 'version': '14.04', + 'pretty_version': '14.04 (trusty)', + 'best_version': '14.04.3', + 'codename': 'trusty' + } + self._test_outcome(desired_outcome) + + @pytest.mark.parametrize('errnum', ('001', '002', '126', '130', '255')) + def test_lsb_release_error_level(self, errnum): + self._setup_for_distro(os.path.join( + TESTDISTROS, 'lsb', 'lsb_rc{0}'.format(errnum))) + with pytest.raises(subprocess.CalledProcessError) as excinfo: + distro.LinuxDistribution(True, 'non', 'non')._lsb_release_info + assert excinfo.value.returncode == int(errnum) + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestSpecialRelease(DistroTestCase): + def _test_outcome(self, outcome): + assert self.distro.id() == outcome.get('id', '') + assert self.distro.name() == outcome.get('name', '') + assert self.distro.name(pretty=True) == outcome.get('pretty_name', '') + assert self.distro.version() == outcome.get('version', '') + assert self.distro.version(pretty=True) == \ + outcome.get('pretty_version', '') + assert self.distro.version(best=True) == \ + outcome.get('best_version', '') + assert self.distro.like() == outcome.get('like', '') + assert self.distro.codename() == outcome.get('codename', '') + assert self.distro.major_version() == outcome.get('major_version', '') + assert self.distro.minor_version() == outcome.get('minor_version', '') + assert self.distro.build_number() == outcome.get('build_number', '') + + def test_empty_release(self): + distro_release = os.path.join(SPECIAL, 'empty-release') + self.distro = distro.LinuxDistribution(False, 'non', distro_release) + + desired_outcome = { + 'id': 'empty' + } + self._test_outcome(desired_outcome) + + def test_unknowndistro_release(self): + self._setup_for_distro(os.path.join(TESTDISTROS, 'distro', + 'unknowndistro')) + + self.distro = distro.LinuxDistribution() + + desired_outcome = { + 'id': 'unknowndistro', + 'name': 'Unknown Distro', + 'pretty_name': 'Unknown Distro 1.0 (Unknown Codename)', + 'version': '1.0', + 'pretty_version': '1.0 (Unknown Codename)', + 'best_version': '1.0', + 'codename': 'Unknown Codename', + 'major_version': '1', + 'minor_version': '0' + } + self._test_outcome(desired_outcome) + + def test_bad_uname(self): + self._setup_for_distro(os.path.join(TESTDISTROS, 'distro', + 'baduname')) + self.distro = distro.LinuxDistribution() + + assert self.distro.uname_attr('id') == '' + assert self.distro.uname_attr('name') == '' + assert self.distro.uname_attr('release') == '' + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestDistroRelease: + + def _test_outcome(self, + outcome, + distro_name='', + version='', + release_file_id='', + release_file_suffix='release'): + release_file_id = release_file_id or distro_name + distro_release = os.path.join( + DISTROS_DIR, distro_name + version, 'etc', '{0}-{1}'.format( + release_file_id, release_file_suffix)) + self.distro = distro.LinuxDistribution(False, 'non', distro_release) + + assert self.distro.id() == outcome.get('id', '') + assert self.distro.name() == outcome.get('name', '') + assert self.distro.name(pretty=True) == outcome.get('pretty_name', '') + assert self.distro.version() == outcome.get('version', '') + assert self.distro.version(pretty=True) == \ + outcome.get('pretty_version', '') + assert self.distro.version(best=True) == \ + outcome.get('best_version', '') + assert self.distro.like() == outcome.get('like', '') + assert self.distro.codename() == outcome.get('codename', '') + assert self.distro.major_version() == outcome.get('major_version', '') + assert self.distro.minor_version() == outcome.get('minor_version', '') + assert self.distro.build_number() == outcome.get('build_number', '') + + def test_arch_dist_release(self): + desired_outcome = { + 'id': 'arch' + } + self._test_outcome(desired_outcome, 'arch') + + def test_centos5_dist_release(self): + desired_outcome = { + 'id': 'centos', + 'name': 'CentOS', + 'pretty_name': 'CentOS 5.11 (Final)', + 'version': '5.11', + 'pretty_version': '5.11 (Final)', + 'best_version': '5.11', + 'codename': 'Final', + 'major_version': '5', + 'minor_version': '11' + } + self._test_outcome(desired_outcome, 'centos', '5') + + def test_centos7_dist_release(self): + desired_outcome = { + 'id': 'centos', + 'name': 'CentOS Linux', + 'pretty_name': 'CentOS Linux 7.1.1503 (Core)', + 'version': '7.1.1503', + 'pretty_version': '7.1.1503 (Core)', + 'best_version': '7.1.1503', + 'codename': 'Core', + 'major_version': '7', + 'minor_version': '1', + 'build_number': '1503' + } + self._test_outcome(desired_outcome, 'centos', '7') + + def test_fedora19_dist_release(self): + desired_outcome = { + 'id': 'fedora', + 'name': 'Fedora', + 'pretty_name': u'Fedora 19 (Schr\u00F6dinger\u2019s Cat)', + 'version': '19', + 'pretty_version': u'19 (Schr\u00F6dinger\u2019s Cat)', + 'best_version': '19', + 'codename': u'Schr\u00F6dinger\u2019s Cat', + 'major_version': '19' + } + self._test_outcome(desired_outcome, 'fedora', '19') + + def test_fedora23_dist_release(self): + desired_outcome = { + 'id': 'fedora', + 'name': 'Fedora', + 'pretty_name': 'Fedora 23 (Twenty Three)', + 'version': '23', + 'pretty_version': '23 (Twenty Three)', + 'best_version': '23', + 'codename': 'Twenty Three', + 'major_version': '23' + } + self._test_outcome(desired_outcome, 'fedora', '23') + + def test_fedora30_dist_release(self): + desired_outcome = { + 'id': 'fedora', + 'name': 'Fedora', + 'pretty_name': 'Fedora 30 (Thirty)', + 'version': '30', + 'pretty_version': '30 (Thirty)', + 'best_version': '30', + 'codename': 'Thirty', + 'major_version': '30' + } + self._test_outcome(desired_outcome, 'fedora', '30') + + def test_gentoo_dist_release(self): + desired_outcome = { + 'id': 'gentoo', + 'name': 'Gentoo Base System', + 'pretty_name': 'Gentoo Base System 2.2', + 'version': '2.2', + 'pretty_version': '2.2', + 'best_version': '2.2', + 'major_version': '2', + 'minor_version': '2', + } + self._test_outcome(desired_outcome, 'gentoo') + + def test_kvmibm1_dist_release(self): + desired_outcome = { + 'id': 'base', + 'name': 'KVM for IBM z Systems', + 'pretty_name': 'KVM for IBM z Systems 1.1.1 (Z)', + 'version': '1.1.1', + 'pretty_version': '1.1.1 (Z)', + 'best_version': '1.1.1', + 'codename': 'Z', + 'major_version': '1', + 'minor_version': '1', + 'build_number': '1' + } + self._test_outcome(desired_outcome, 'kvmibm', '1', 'base') + + def test_mageia5_dist_release(self): + desired_outcome = { + 'id': 'mageia', + 'name': 'Mageia', + 'pretty_name': 'Mageia 5 (Official)', + 'version': '5', + 'pretty_version': '5 (Official)', + 'best_version': '5', + 'codename': 'Official', + 'major_version': '5' + } + self._test_outcome(desired_outcome, 'mageia', '5') + + def test_manjaro1512_dist_release(self): + self._test_outcome({ + 'id': 'manjaro', + 'name': 'Manjaro Linux', + 'pretty_name': 'Manjaro Linux', + 'version': '', + 'codename': '' + }, 'manjaro', '1512') + + def test_opensuse42_dist_release(self): + desired_outcome = { + 'id': 'suse', + 'name': 'openSUSE', + 'pretty_name': 'openSUSE 42.1 (x86_64)', + 'version': '42.1', + 'pretty_version': '42.1 (x86_64)', + 'best_version': '42.1', + 'codename': 'x86_64', + 'major_version': '42', + 'minor_version': '1' + } + self._test_outcome(desired_outcome, 'opensuse', '42', 'SuSE') + + def test_oracle7_dist_release(self): + desired_outcome = { + 'id': 'oracle', + 'name': 'Oracle Linux Server', + 'pretty_name': 'Oracle Linux Server 7.5', + 'version': '7.5', + 'pretty_version': '7.5', + 'best_version': '7.5', + 'major_version': '7', + 'minor_version': '5' + } + self._test_outcome(desired_outcome, 'oracle', '7') + + def test_rhel6_dist_release(self): + desired_outcome = { + 'id': 'rhel', + 'name': 'Red Hat Enterprise Linux Server', + 'pretty_name': 'Red Hat Enterprise Linux Server 6.5 (Santiago)', + 'version': '6.5', + 'pretty_version': '6.5 (Santiago)', + 'best_version': '6.5', + 'codename': 'Santiago', + 'major_version': '6', + 'minor_version': '5' + } + self._test_outcome(desired_outcome, 'rhel', '6', 'redhat') + + def test_rhel7_dist_release(self): + desired_outcome = { + 'id': 'rhel', + 'name': 'Red Hat Enterprise Linux Server', + 'pretty_name': 'Red Hat Enterprise Linux Server 7.0 (Maipo)', + 'version': '7.0', + 'pretty_version': '7.0 (Maipo)', + 'best_version': '7.0', + 'codename': 'Maipo', + 'major_version': '7', + 'minor_version': '0' + } + self._test_outcome(desired_outcome, 'rhel', '7', 'redhat') + + def test_slackware14_dist_release(self): + desired_outcome = { + 'id': 'slackware', + 'name': 'Slackware', + 'pretty_name': 'Slackware 14.1', + 'version': '14.1', + 'pretty_version': '14.1', + 'best_version': '14.1', + 'major_version': '14', + 'minor_version': '1' + } + self._test_outcome( + desired_outcome, + 'slackware', + '14', + release_file_suffix='version') + + def test_sles12_dist_release(self): + desired_outcome = { + 'id': 'suse', + 'name': 'SUSE Linux Enterprise Server', + 'pretty_name': 'SUSE Linux Enterprise Server 12 (s390x)', + 'version': '12', + 'pretty_version': '12 (s390x)', + 'best_version': '12', + 'major_version': '12', + 'codename': 's390x' + } + self._test_outcome(desired_outcome, 'sles', '12', 'SuSE') + + def test_cloudlinux5_dist_release(self): + # Uses redhat-release only to get information. + # The id of 'rhel' can only be fixed with issue #109. + desired_outcome = { + 'id': 'cloudlinux', + 'codename': 'Vladislav Volkov', + 'name': 'CloudLinux Server', + 'pretty_name': 'CloudLinux Server 5.11 (Vladislav Volkov)', + 'version': '5.11', + 'pretty_version': '5.11 (Vladislav Volkov)', + 'best_version': '5.11', + 'major_version': '5', + 'minor_version': '11' + } + self._test_outcome(desired_outcome, 'cloudlinux', '5', 'redhat') + + def test_cloudlinux6_dist_release(self): + # Same as above, only has redhat-release. + desired_outcome = { + 'id': 'cloudlinux', + 'codename': 'Oleg Makarov', + 'name': 'CloudLinux Server', + 'pretty_name': 'CloudLinux Server 6.8 (Oleg Makarov)', + 'version': '6.8', + 'pretty_version': '6.8 (Oleg Makarov)', + 'best_version': '6.8', + 'major_version': '6', + 'minor_version': '8' + } + self._test_outcome(desired_outcome, 'cloudlinux', '6', 'redhat') + + def test_cloudlinux7_dist_release(self): + desired_outcome = { + 'id': 'cloudlinux', + 'codename': 'Yury Malyshev', + 'name': 'CloudLinux', + 'pretty_name': 'CloudLinux 7.3 (Yury Malyshev)', + 'version': '7.3', + 'pretty_version': '7.3 (Yury Malyshev)', + 'best_version': '7.3', + 'major_version': '7', + 'minor_version': '3' + } + self._test_outcome(desired_outcome, 'cloudlinux', '7', 'redhat') + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestOverall(DistroTestCase): + """Test a LinuxDistribution object created with default arguments. + + The direct accessor functions on that object are tested (e.g. `id()`); they + implement the precedence between the different sources of information. + + In addition, because the distro release file is searched when not + specified, the information resulting from the distro release file is also + tested. The LSB and os-release sources are not tested again, because their + test is already done in TestLSBRelease and TestOSRelease, and their + algorithm does not depend on whether or not the file is specified. + + TODO: This class should have testcases for all distros that are claimed + to be reliably maintained w.r.t. to their ID (see `id()`). Testcases for + the following distros are still missing: + * `amazon` - Amazon Linux + * `gentoo` - GenToo Linux + * `ibm_powerkvm` - IBM PowerKVM + * `parallels` - Parallels + * `pidora` - Pidora (Fedora remix for Raspberry Pi) + * `raspbian` - Raspbian + * `scientific` - Scientific Linux + * `xenserver` - XenServer + """ + + def setup_method(self, test_method): + super(TestOverall, self).setup_method(test_method) + dist = test_method.__name__.split('_')[1] + self._setup_for_distro(os.path.join(DISTROS_DIR, dist)) + self.distro = distro.LinuxDistribution() + + def _test_outcome(self, outcome): + assert self.distro.id() == outcome.get('id', '') + assert self.distro.name() == outcome.get('name', '') + assert self.distro.name(pretty=True) == outcome.get('pretty_name', '') + assert self.distro.version() == outcome.get('version', '') + assert self.distro.version(pretty=True) == \ + outcome.get('pretty_version', '') + assert self.distro.version(best=True) == \ + outcome.get('best_version', '') + assert self.distro.like() == outcome.get('like', '') + assert self.distro.codename() == outcome.get('codename', '') + assert self.distro.major_version() == outcome.get('major_version', '') + assert self.distro.minor_version() == outcome.get('minor_version', '') + assert self.distro.build_number() == outcome.get('build_number', '') + + def _test_non_existing_release_file(self): + # Test the info from the searched distro release file + # does not have one. + assert self.distro.distro_release_file == '' + assert len(self.distro.distro_release_info()) == 0 + + def _test_release_file_info(self, filename, outcome): + # Test the info from the searched distro release file + assert os.path.basename(self.distro.distro_release_file) == filename + distro_info = self.distro.distro_release_info() + for key, value in outcome.items(): + assert distro_info[key] == value + return distro_info + + def test_arch_release(self): + desired_outcome = { + 'id': 'arch', + 'name': 'Arch Linux', + 'pretty_name': 'Arch Linux', + } + self._test_outcome(desired_outcome) + + # Test the info from the searched distro release file + # Does not have one; The empty /etc/arch-release file is not + # considered a valid distro release file: + self._test_non_existing_release_file() + + def test_centos5_release(self): + desired_outcome = { + 'id': 'centos', + 'name': 'CentOS', + 'pretty_name': 'CentOS 5.11 (Final)', + 'version': '5.11', + 'pretty_version': '5.11 (Final)', + 'best_version': '5.11', + 'codename': 'Final', + 'major_version': '5', + 'minor_version': '11' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'centos', + 'name': 'CentOS', + 'version_id': '5.11', + 'codename': 'Final' + } + self._test_release_file_info('centos-release', desired_info) + + def test_centos7_release(self): + desired_outcome = { + 'id': 'centos', + 'name': 'CentOS Linux', + 'pretty_name': 'CentOS Linux 7 (Core)', + 'version': '7', + 'pretty_version': '7 (Core)', + 'best_version': '7.1.1503', + 'like': 'rhel fedora', + 'codename': 'Core', + 'major_version': '7' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'centos', + 'name': 'CentOS Linux', + 'version_id': '7.1.1503', + 'codename': 'Core' + } + self._test_release_file_info('centos-release', desired_info) + + def test_coreos_release(self): + desired_outcome = { + 'id': 'coreos', + 'name': 'CoreOS', + 'pretty_name': 'CoreOS 899.15.0', + 'version': '899.15.0', + 'pretty_version': '899.15.0', + 'best_version': '899.15.0', + 'major_version': '899', + 'minor_version': '15', + 'build_number': '0' + } + self._test_outcome(desired_outcome) + self._test_non_existing_release_file() + + def test_debian8_release(self): + desired_outcome = { + 'id': 'debian', + 'name': 'Debian GNU/Linux', + 'pretty_name': 'Debian GNU/Linux 8 (jessie)', + 'version': '8', + 'pretty_version': '8 (jessie)', + 'best_version': '8.2', + 'codename': 'jessie', + 'major_version': '8' + } + self._test_outcome(desired_outcome) + self._test_non_existing_release_file() + + def test_exherbo_release(self): + desired_outcome = { + 'id': 'exherbo', + 'name': 'Exherbo', + 'pretty_name': 'Exherbo Linux', + } + self._test_outcome(desired_outcome) + + def test_fedora19_release(self): + desired_outcome = { + 'id': 'fedora', + 'name': 'Fedora', + 'pretty_name': u'Fedora 19 (Schr\u00F6dinger\u2019s Cat)', + 'version': '19', + 'pretty_version': u'19 (Schr\u00F6dinger\u2019s Cat)', + 'best_version': '19', + 'codename': u'Schr\u00F6dinger\u2019s Cat', + 'major_version': '19' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'fedora', + 'name': 'Fedora', + 'version_id': '19', + 'codename': u'Schr\u00F6dinger\u2019s Cat' + } + self._test_release_file_info('fedora-release', desired_info) + + def test_fedora23_release(self): + desired_outcome = { + 'id': 'fedora', + 'name': 'Fedora', + 'pretty_name': 'Fedora 23 (Twenty Three)', + 'version': '23', + 'pretty_version': '23 (Twenty Three)', + 'best_version': '23', + 'codename': 'Twenty Three', + 'major_version': '23' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'fedora', + 'name': 'Fedora', + 'version_id': '23', + 'codename': 'Twenty Three' + } + self._test_release_file_info('fedora-release', desired_info) + + def test_fedora30_release(self): + desired_outcome = { + 'id': 'fedora', + 'name': 'Fedora', + 'pretty_name': 'Fedora 30 (Thirty)', + 'version': '30', + 'pretty_version': '30', + 'best_version': '30', + 'codename': '', + 'major_version': '30' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'fedora', + 'name': 'Fedora', + 'version_id': '30', + 'codename': 'Thirty' + } + self._test_release_file_info('fedora-release', desired_info) + + def test_kvmibm1_release(self): + desired_outcome = { + 'id': 'kvmibm', + 'name': 'KVM for IBM z Systems', + 'pretty_name': 'KVM for IBM z Systems 1.1.1 (Z)', + 'version': '1.1.1', + 'pretty_version': '1.1.1 (Z)', + 'best_version': '1.1.1', + 'like': 'rhel fedora', + 'codename': 'Z', + 'major_version': '1', + 'minor_version': '1', + 'build_number': '1' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'base', + 'name': 'KVM for IBM z Systems', + 'version_id': '1.1.1', + 'codename': 'Z' + } + self._test_release_file_info('base-release', desired_info) + + def test_linuxmint17_release(self): + desired_outcome = { + 'id': 'ubuntu', + 'name': 'Ubuntu', + 'pretty_name': 'Ubuntu 14.04.3 LTS', + 'version': '14.04', + 'pretty_version': '14.04 (Trusty Tahr)', + 'best_version': '14.04.3', + 'like': 'debian', + 'codename': 'Trusty Tahr', + 'major_version': '14', + 'minor_version': '04' + } + self._test_outcome(desired_outcome) + self._test_non_existing_release_file() + + def test_mageia5_release(self): + desired_outcome = { + 'id': 'mageia', + 'name': 'Mageia', + 'pretty_name': 'Mageia 5', + 'version': '5', + 'pretty_version': '5 (thornicroft)', + 'best_version': '5', + 'like': 'mandriva fedora', + # TODO: Codename differs between distro release and lsb_release. + 'codename': 'thornicroft', + 'major_version': '5' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'mageia', + 'name': 'Mageia', + 'version_id': '5', + 'codename': 'Official' + } + self._test_release_file_info('mageia-release', desired_info) + + def test_manjaro1512_release(self): + self._test_outcome({ + 'id': 'manjaro', + 'name': 'Manjaro Linux', + 'pretty_name': 'Manjaro Linux', + 'version': '15.12', + 'pretty_version': '15.12 (Capella)', + 'best_version': '15.12', + 'major_version': '15', + 'minor_version': '12', + 'codename': 'Capella' + }) + + self._test_release_file_info( + 'manjaro-release', + {'id': 'manjaro', + 'name': 'Manjaro Linux'}) + + def test_opensuse42_release(self): + desired_outcome = { + 'id': 'opensuse', + 'name': 'openSUSE Leap', + 'pretty_name': 'openSUSE Leap 42.1 (x86_64)', + 'version': '42.1', + 'pretty_version': '42.1 (x86_64)', + 'best_version': '42.1', + 'like': 'suse', + 'codename': 'x86_64', + 'major_version': '42', + 'minor_version': '1' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'SuSE', + 'name': 'openSUSE', + 'version_id': '42.1', + 'codename': 'x86_64' + } + self._test_release_file_info('SuSE-release', desired_info) + + def test_oracle7_release(self): + desired_outcome = { + 'id': 'oracle', + 'name': 'Oracle Linux Server', + 'pretty_name': 'Oracle Linux Server 7.5', + 'version': '7.5', + 'pretty_version': '7.5', + 'best_version': '7.5', + 'major_version': '7', + 'minor_version': '5' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'oracle', + 'name': 'Oracle Linux Server', + 'version_id': '7.5', + } + distro_info = self._test_release_file_info( + 'oracle-release', desired_info) + assert 'codename' not in distro_info + + def test_raspbian7_release(self): + desired_outcome = { + 'id': 'raspbian', + 'name': 'Raspbian GNU/Linux', + 'pretty_name': 'Raspbian GNU/Linux 7 (wheezy)', + 'version': '7', + 'pretty_version': '7 (wheezy)', + 'best_version': '7', + 'like': 'debian', + 'codename': 'wheezy', + 'major_version': '7', + } + self._test_outcome(desired_outcome) + self._test_non_existing_release_file() + + def test_raspbian8_release(self): + desired_outcome = { + 'id': 'raspbian', + 'name': 'Raspbian GNU/Linux', + 'pretty_name': 'Raspbian GNU/Linux 8 (jessie)', + 'version': '8', + 'pretty_version': '8 (jessie)', + 'best_version': '8', + 'like': 'debian', + 'codename': 'jessie', + 'major_version': '8', + } + self._test_outcome(desired_outcome) + self._test_non_existing_release_file() + + def test_rhel5_release(self): + desired_outcome = { + 'id': 'rhel', + 'name': 'Red Hat Enterprise Linux Server', + 'pretty_name': 'Red Hat Enterprise Linux Server 5.11 (Tikanga)', + 'version': '5.11', + 'pretty_version': '5.11 (Tikanga)', + 'best_version': '5.11', + 'codename': 'Tikanga', + 'major_version': '5', + 'minor_version': '11' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'redhat', + 'name': 'Red Hat Enterprise Linux Server', + 'version_id': '5.11', + 'codename': 'Tikanga' + } + self._test_release_file_info('redhat-release', desired_info) + + def test_rhel6_release(self): + desired_outcome = { + 'id': 'rhel', + 'name': 'Red Hat Enterprise Linux Server', + 'pretty_name': 'Red Hat Enterprise Linux Server 6.5 (Santiago)', + 'version': '6.5', + 'pretty_version': '6.5 (Santiago)', + 'best_version': '6.5', + 'codename': 'Santiago', + 'major_version': '6', + 'minor_version': '5' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'redhat', + 'name': 'Red Hat Enterprise Linux Server', + 'version_id': '6.5', + 'codename': 'Santiago' + } + self._test_release_file_info('redhat-release', desired_info) + + def test_rhel7_release(self): + desired_outcome = { + 'id': 'rhel', + 'name': 'Red Hat Enterprise Linux Server', + 'pretty_name': 'Red Hat Enterprise Linux Server 7.0 (Maipo)', + 'version': '7.0', + 'pretty_version': '7.0 (Maipo)', + 'best_version': '7.0', + 'like': 'fedora', + 'codename': 'Maipo', + 'major_version': '7', + 'minor_version': '0' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'redhat', + 'name': 'Red Hat Enterprise Linux Server', + 'version_id': '7.0', + 'codename': 'Maipo' + } + self._test_release_file_info('redhat-release', desired_info) + + def test_slackware14_release(self): + desired_outcome = { + 'id': 'slackware', + 'name': 'Slackware', + 'pretty_name': 'Slackware 14.1', + 'version': '14.1', + 'pretty_version': '14.1', + 'best_version': '14.1', + 'major_version': '14', + 'minor_version': '1' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'slackware', + 'name': 'Slackware', + 'version_id': '14.1', + } + distro_info = self._test_release_file_info( + 'slackware-version', desired_info) + assert 'codename' not in distro_info + + def test_sles12_release(self): + desired_outcome = { + 'id': 'sles', + 'name': 'SLES', + 'pretty_name': 'SUSE Linux Enterprise Server 12 SP1', + 'version': '12.1', + 'pretty_version': '12.1 (n/a)', + 'best_version': '12.1', + 'codename': 'n/a', + 'major_version': '12', + 'minor_version': '1' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'SuSE', + 'name': 'SUSE Linux Enterprise Server', + 'version_id': '12', + 'codename': 's390x' + } + self._test_release_file_info('SuSE-release', desired_info) + + def test_ubuntu14_release(self): + desired_outcome = { + 'id': 'ubuntu', + 'name': 'Ubuntu', + 'pretty_name': 'Ubuntu 14.04.3 LTS', + 'version': '14.04', + 'pretty_version': '14.04 (Trusty Tahr)', + 'best_version': '14.04.3', + 'like': 'debian', + 'codename': 'Trusty Tahr', + 'major_version': '14', + 'minor_version': '04' + } + self._test_outcome(desired_outcome) + + # Test the info from the searched distro release file + # Does not have one; /etc/debian_version is not considered a distro + # release file: + self._test_non_existing_release_file() + + def test_ubuntu16_release(self): + desired_outcome = { + 'id': 'ubuntu', + 'name': 'Ubuntu', + 'pretty_name': 'Ubuntu 16.04.1 LTS', + 'version': '16.04', + 'pretty_version': '16.04 (xenial)', + 'best_version': '16.04.1', + 'like': 'debian', + 'codename': 'xenial', + 'major_version': '16', + 'minor_version': '04' + } + self._test_outcome(desired_outcome) + + # Test the info from the searched distro release file + # Does not have one; /etc/debian_version is not considered a distro + # release file: + self._test_non_existing_release_file() + + def test_amazon2016_release(self): + desired_outcome = { + 'id': 'amzn', + 'name': 'Amazon Linux AMI', + 'pretty_name': 'Amazon Linux AMI 2016.03', + 'version': '2016.03', + 'pretty_version': '2016.03', + 'best_version': '2016.03', + 'like': 'rhel fedora', + 'major_version': '2016', + 'minor_version': '03' + } + self._test_outcome(desired_outcome) + + def test_amazon2014_release(self): + # Amazon Linux 2014 only contains a system-release file. + # distro doesn't currently handle it. + desired_outcome = {} + self._test_outcome(desired_outcome) + + def test_scientific6_release(self): + desired_outcome = { + 'id': 'rhel', + 'name': 'Scientific Linux', + 'pretty_name': 'Scientific Linux 6.4 (Carbon)', + 'version': '6.4', + 'pretty_version': '6.4 (Carbon)', + 'best_version': '6.4', + 'codename': 'Carbon', + 'major_version': '6', + 'minor_version': '4', + + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'redhat', + 'name': 'Scientific Linux', + 'version_id': '6.4', + 'codename': 'Carbon' + } + self._test_release_file_info('redhat-release', desired_info) + + def test_scientific7_release(self): + desired_outcome = { + 'id': 'rhel', + 'name': 'Scientific Linux', + 'pretty_name': 'Scientific Linux 7.2 (Nitrogen)', + 'version': '7.2', + 'pretty_version': '7.2 (Nitrogen)', + 'best_version': '7.2', + 'like': 'fedora', + 'codename': 'Nitrogen', + 'major_version': '7', + 'minor_version': '2', + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'redhat', + 'name': 'Scientific Linux', + 'version_id': '7.2', + 'codename': 'Nitrogen' + } + self._test_release_file_info('redhat-release', desired_info) + + def test_gentoo_release(self): + desired_outcome = { + 'id': 'gentoo', + 'name': 'Gentoo', + 'pretty_name': 'Gentoo/Linux', + 'version': '2.2', + 'pretty_version': '2.2', + 'best_version': '2.2', + 'major_version': '2', + 'minor_version': '2', + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'gentoo', + 'name': 'Gentoo Base System', + 'version_id': '2.2', + } + self._test_release_file_info('gentoo-release', desired_info) + + def test_openelec6_release(self): + desired_outcome = { + 'id': 'openelec', + 'name': 'OpenELEC', + 'pretty_name': 'OpenELEC (official) - Version: 6.0.3', + 'version': '6.0', + 'pretty_version': '6.0', + 'best_version': '6.0.3', + 'major_version': '6', + 'minor_version': '0', + } + self._test_outcome(desired_outcome) + + def test_mandriva2011_release(self): + desired_outcome = { + 'id': 'mandrivalinux', + 'name': 'MandrivaLinux', + 'pretty_name': 'Mandriva Linux 2011.0', + 'version': '2011.0', + 'pretty_version': '2011.0 (turtle)', + 'best_version': '2011.0', + 'major_version': '2011', + 'minor_version': '0', + 'codename': 'turtle' + } + self._test_outcome(desired_outcome) + + desired_info = { + 'id': 'mandrake', + 'name': 'Mandriva Linux', + 'version_id': '2011.0', + } + self._test_release_file_info('mandrake-release', desired_info) + + def test_cloudlinux5_release(self): + # Uses redhat-release only to get information. + # The id of 'rhel' can only be fixed with issue #109. + desired_outcome = { + 'id': 'cloudlinux', + 'codename': 'Vladislav Volkov', + 'name': 'CloudLinux Server', + 'pretty_name': 'CloudLinux Server 5.11 (Vladislav Volkov)', + 'version': '5.11', + 'pretty_version': '5.11 (Vladislav Volkov)', + 'best_version': '5.11', + 'major_version': '5', + 'minor_version': '11' + } + self._test_outcome(desired_outcome) + + def test_cloudlinux6_release(self): + # Same as above, only has redhat-release. + desired_outcome = { + 'id': 'cloudlinux', + 'codename': 'Oleg Makarov', + 'name': 'CloudLinux Server', + 'pretty_name': 'CloudLinux Server 6.8 (Oleg Makarov)', + 'version': '6.8', + 'pretty_version': '6.8 (Oleg Makarov)', + 'best_version': '6.8', + 'major_version': '6', + 'minor_version': '8' + } + self._test_outcome(desired_outcome) + + def test_cloudlinux7_release(self): + desired_outcome = { + 'id': 'cloudlinux', + 'codename': 'Yury Malyshev', + 'name': 'CloudLinux', + 'pretty_name': 'CloudLinux 7.3 (Yury Malyshev)', + 'like': 'rhel fedora centos', + 'version': '7.3', + 'pretty_version': '7.3 (Yury Malyshev)', + 'best_version': '7.3', + 'major_version': '7', + 'minor_version': '3' + } + self._test_outcome(desired_outcome) + + +def _bad_os_listdir(path='.'): + """ This function is used by TestOverallWithEtcNotReadable to simulate + a folder that cannot be called with os.listdir() but files are still + readable. Forces distro to guess which *-release files are available. """ + raise OSError() + + +@pytest.mark.skipIf(not IS_LINUX, reason='Irrelevant on non-linx') +class TestOverallWithEtcNotReadable(TestOverall): + def setup_method(self, test_method): + self._old_listdir = os.listdir + os.listdir = _bad_os_listdir + super(TestOverallWithEtcNotReadable, self).setup_method(test_method) + + def teardown_method(self, test_method): + super(TestOverallWithEtcNotReadable, self).teardown_method(test_method) + if os.listdir is _bad_os_listdir: + os.listdir = self._old_listdir + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestGetAttr(DistroTestCase): + """Test the consistency between the results of + `{source}_release_attr()` and `{source}_release_info()` for all + distros in `DISTROS`. + """ + + def _test_attr(self, info_method, attr_method): + for dist in DISTROS: + self._setup_for_distro(os.path.join(DISTROS_DIR, dist)) + _distro = distro.LinuxDistribution() + info = getattr(_distro, info_method)() + for key in info.keys(): + try: + assert info[key] == getattr(_distro, attr_method)(key) + except AssertionError: + print("distro: {0}, key: {1}".format(dist, key)) + + def test_os_release_attr(self): + self._test_attr('os_release_info', 'os_release_attr') + + def test_lsb_release_attr(self): + self._test_attr('lsb_release_info', 'lsb_release_attr') + + def test_distro_release_attr(self): + self._test_attr('distro_release_info', 'distro_release_attr') + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestInfo(DistroTestCase): + + def setup_method(self, test_method): + super(TestInfo, self).setup_method(test_method) + self.ubuntu14_os_release = os.path.join( + DISTROS_DIR, 'ubuntu14', 'etc', 'os-release') + + def test_info(self): + _distro = distro.LinuxDistribution( + False, self.ubuntu14_os_release, 'non') + + desired_info = { + 'id': 'ubuntu', + 'version': '14.04', + 'like': 'debian', + 'version_parts': { + 'major': '14', + 'minor': '04', + 'build_number': '' + }, + 'codename': 'Trusty Tahr' + } + + info = _distro.info() + assert info == desired_info + + desired_info_diff = { + 'version': '14.04 (Trusty Tahr)' + } + desired_info.update(desired_info_diff) + info = _distro.info(pretty=True) + assert info == desired_info + + desired_info_diff = { + 'version': '14.04.3', + 'version_parts': { + 'major': '14', + 'minor': '04', + 'build_number': '3' + } + } + desired_info.update(desired_info_diff) + info = _distro.info(best=True) + assert info == desired_info + + desired_info_diff = { + 'version': '14.04.3 (Trusty Tahr)' + } + desired_info.update(desired_info_diff) + info = _distro.info(pretty=True, best=True) + assert info == desired_info + + def test_none(self): + + def _test_none(info): + assert info['id'] == '' + assert info['version'] == '' + assert info['like'] == '' + assert info['version_parts']['major'] == '' + assert info['version_parts']['minor'] == '' + assert info['version_parts']['build_number'] == '' + assert info['codename'] == '' + + _distro = distro.LinuxDistribution(False, 'non', 'non') + + info = _distro.info() + _test_none(info) + + info = _distro.info(best=True) + _test_none(info) + + info = _distro.info(pretty=True) + _test_none(info) + + info = _distro.info(pretty=True, best=True) + _test_none(info) + + def test_linux_distribution(self): + _distro = distro.LinuxDistribution(False, self.ubuntu14_os_release) + i = _distro.linux_distribution() + assert i == ('Ubuntu', '14.04', 'Trusty Tahr') + + def test_linux_distribution_full_false(self): + _distro = distro.LinuxDistribution(False, self.ubuntu14_os_release) + i = _distro.linux_distribution(full_distribution_name=False) + assert i == ('ubuntu', '14.04', 'Trusty Tahr') + + def test_all(self): + """Test info() by comparing its results with the results of specific + consolidated accessor functions. + """ + def _test_all(info, best=False, pretty=False): + assert info['id'] == _distro.id() + assert info['version'] == _distro.version(pretty=pretty, best=best) + assert info['version_parts']['major'] == \ + _distro.major_version(best=best) + assert info['version_parts']['minor'] == \ + _distro.minor_version(best=best) + assert info['version_parts']['build_number'] == \ + _distro.build_number(best=best) + assert info['like'] == _distro.like() + assert info['codename'] == _distro.codename() + assert len(info['version_parts']) == 3 + assert len(info) == 5 + + for dist in DISTROS: + self._setup_for_distro(os.path.join(DISTROS_DIR, dist)) + + _distro = distro.LinuxDistribution() + + info = _distro.info() + _test_all(info) + + info = _distro.info(best=True) + _test_all(info, best=True) + + info = _distro.info(pretty=True) + _test_all(info, pretty=True) + + info = _distro.info(pretty=True, best=True) + _test_all(info, pretty=True, best=True) + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestOSReleaseParsing: + """Test the parsing of os-release files. + """ + + def setup_method(self, test_method): + self.distro = distro.LinuxDistribution(False, None, None) + self.distro.debug = True + + def _get_props(self, input): + return self.distro._parse_os_release_content(StringIO( + input, + )) + + def _test_zero_length_props(self, input): + props = self._get_props(input) + assert len(props) == 0 + + def _test_empty_value(self, input): + props = self._get_props(input) + assert props.get('key', None) == '' + + def _test_parsed_value(self, input): + props = self._get_props(input) + assert props.get('key', None) == 'value' + + def test_kv_01_empty_file(self): + self._test_zero_length_props('') + + def test_kv_02_empty_line(self): + self._test_zero_length_props('\n') + + def test_kv_03_empty_line_with_crlf(self): + self._test_zero_length_props('\r\n') + + def test_kv_04_empty_line_with_just_cr(self): + self._test_zero_length_props('\r') + + def test_kv_05_comment(self): + self._test_zero_length_props('# KEY=value\n') + + def test_kv_06_empty_value(self): + self._test_empty_value('KEY=\n') + + def test_kv_07_empty_value_single_quoted(self): + self._test_empty_value('KEY=\'\'\n') + + def test_kv_08_empty_value_double_quoted(self): + self._test_empty_value('KEY=""\n') + + def test_kv_09_word(self): + self._test_parsed_value('KEY=value\n') + + def test_kv_10_word_no_newline(self): + self._test_parsed_value('KEY=value') + + def test_kv_11_word_with_crlf(self): + self._test_parsed_value('KEY=value\r\n') + + def test_kv_12_word_with_just_cr(self): + self._test_parsed_value('KEY=value\r') + + def test_kv_13_word_with_multi_blanks(self): + self._test_empty_value('KEY= cmd \n') + # Note: Without quotes, this assigns the empty string, and 'cmd' is + # a separate token that is being ignored (it would be a command + # in the shell). + + def test_kv_14_unquoted_words(self): + self._test_parsed_value('KEY=value cmd\n') + + def test_kv_15_double_quoted_words(self): + props = self._get_props('KEY="a simple value" cmd\n') + assert props.get('key', None) == 'a simple value' + + def test_kv_16_double_quoted_words_with_multi_blanks(self): + props = self._get_props('KEY=" a simple value "\n') + assert props.get('key', None) == ' a simple value ' + + def test_kv_17_double_quoted_word_with_single_quote(self): + props = self._get_props('KEY="it\'s value"\n') + assert props.get('key', None) == 'it\'s value' + + def test_kv_18_double_quoted_word_with_double_quote(self): + props = self._get_props('KEY="a \\"bold\\" move"\n') + assert props.get('key', None) == 'a "bold" move' + + def test_kv_19_single_quoted_words(self): + props = self._get_props('KEY=\'a simple value\'\n') + assert props.get('key', None) == 'a simple value' + + def test_kv_20_single_quoted_words_with_multi_blanks(self): + props = self._get_props('KEY=\' a simple value \'\n') + assert props.get('key', None) == ' a simple value ' + + def test_kv_21_single_quoted_word_with_double_quote(self): + props = self._get_props('KEY=\'a "bold" move\'\n') + assert props.get('key', None) == 'a "bold" move' + + def test_kv_22_quoted_unicode_wordchar(self): + # "wordchar" means it is in the shlex.wordchars variable. + props = self._get_props(u'KEY="wordchar: \u00CA (E accent grave)"\n') + assert props.get('key', None) == u'wordchar: \u00CA (E accent grave)' + + def test_kv_23_quoted_unicode_non_wordchar(self): + # "non-wordchar" means it is not in the shlex.wordchars variable. + props = self._get_props( + u'KEY="non-wordchar: \u00A1 (inverted exclamation mark)"\n') + assert (props.get('key', None) == + u'non-wordchar: \u00A1 (inverted exclamation mark)') + + def test_kv_24_double_quoted_entire_single_quoted_word(self): + props = self._get_props('KEY="\'value\'"\n') + assert props.get('key', None) == "'value'" + + def test_kv_25_single_quoted_entire_double_quoted_word(self): + props = self._get_props('KEY=\'"value"\'\n') + assert props.get('key', None) == '"value"' + + def test_kv_26_double_quoted_multiline(self): + props = self.distro._parse_os_release_content(StringIO( + 'KEY="a multi\n' + 'line value"\n' + )) + assert props.get('key', None) == 'a multi\nline value' + # TODO: Find out why the result is not 'a multi line value' + + def test_kv_27_double_quoted_multiline_2(self): + props = self._get_props('KEY=\' a simple value \'\n') + props = self.distro._parse_os_release_content(StringIO( + 'KEY="a multi\n' + 'line=value"\n' + )) + assert props.get('key', None) == 'a multi\nline=value' + # TODO: Find out why the result is not 'a multi line=value' + + def test_kv_28_double_quoted_word_with_equal(self): + props = self._get_props('KEY="var=value"\n') + assert props.get('key', None) == 'var=value' + + def test_kv_29_single_quoted_word_with_equal(self): + props = self._get_props('KEY=\'var=value\'\n') + assert props.get('key', None) == 'var=value' + + def test_kx_01(self): + props = self.distro._parse_os_release_content(StringIO( + 'KEY1=value1\n' + 'KEY2="value 2"\n' + )) + assert props.get('key1', None) == 'value1' + assert props.get('key2', None) == 'value 2' + + def test_kx_02(self): + props = self.distro._parse_os_release_content(StringIO( + '# KEY1=value1\n' + 'KEY2="value 2"\n' + )) + assert props.get('key1', None) is None + assert props.get('key2', None) == 'value 2' + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestGlobal: + """Test the global module-level functions, and default values of their + arguments. + """ + + def setup_method(self, test_method): + pass + + def test_global(self): + # Because the module-level functions use the module-global + # LinuxDistribution instance, it would influence the tested + # code too much if we mocked that in order to use the distro + # specific release files. Instead, we let the functions use + # the release files of the distro this test runs on, and + # compare the result of the global functions with the result + # of the methods on the global LinuxDistribution object. + + def _test_consistency(function, kwargs=None): + kwargs = kwargs or {} + method_result = getattr(MODULE_DISTRO, function)(**kwargs) + function_result = getattr(distro, function)(**kwargs) + assert method_result == function_result + + kwargs = {'full_distribution_name': True} + _test_consistency('linux_distribution', kwargs) + kwargs = {'full_distribution_name': False} + _test_consistency('linux_distribution', kwargs) + + kwargs = {'pretty': False} + _test_consistency('name', kwargs) + _test_consistency('version', kwargs) + _test_consistency('info', kwargs) + + kwargs = {'pretty': True} + _test_consistency('name', kwargs) + _test_consistency('version', kwargs) + _test_consistency('info', kwargs) + + kwargs = {'best': False} + _test_consistency('version', kwargs) + _test_consistency('version_parts', kwargs) + _test_consistency('major_version', kwargs) + _test_consistency('minor_version', kwargs) + _test_consistency('build_number', kwargs) + _test_consistency('info', kwargs) + + kwargs = {'best': True} + _test_consistency('version', kwargs) + _test_consistency('version_parts', kwargs) + _test_consistency('major_version', kwargs) + _test_consistency('minor_version', kwargs) + _test_consistency('build_number', kwargs) + _test_consistency('info', kwargs) + + _test_consistency('id') + _test_consistency('like') + _test_consistency('codename') + _test_consistency('info') + + _test_consistency('os_release_info') + _test_consistency('lsb_release_info') + _test_consistency('distro_release_info') + _test_consistency('uname_info') + + os_release_keys = [ + 'name', + 'version', + 'id', + 'id_like', + 'pretty_name', + 'version_id', + 'codename', + ] + for key in os_release_keys: + _test_consistency('os_release_attr', {'attribute': key}) + + lsb_release_keys = [ + 'distributor_id', + 'description', + 'release', + 'codename', + ] + for key in lsb_release_keys: + _test_consistency('lsb_release_attr', {'attribute': key}) + + distro_release_keys = [ + 'id', + 'name', + 'version_id', + 'codename', + ] + for key in distro_release_keys: + _test_consistency('distro_release_attr', {'attribute': key}) + + uname_keys = [ + 'id', + 'name', + 'release' + ] + for key in uname_keys: + _test_consistency('uname_attr', {'attribute': key}) + + +@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux') +class TestRepr: + """Test the __repr__() method. + """ + + def test_repr(self): + # We test that the class name and the names of all instance attributes + # show up in the repr() string. + repr_str = repr(distro._distro) + assert "LinuxDistribution" in repr_str + for attr in MODULE_DISTRO.__dict__.keys(): + assert attr + '=' in repr_str diff --git a/third_party/python/enum34/enum/doc/enum.pdf b/third_party/python/enum34/enum/doc/enum.pdf --- a/third_party/python/enum34/enum/doc/enum.pdf +++ b/third_party/python/enum34/enum/doc/enum.pdf @@ -1,10 +1,10 @@ %PDF-1.4 -%東京 ReportLab Generated PDF document http://www.reportlab.com +%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com 1 0 obj << /F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R /F5 8 0 R /F6 15 0 R >> endobj 2 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj 3 0 obj << /BaseFont /Courier-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >> diff --git a/third_party/python/psutil/psutil/_pslinux.py b/third_party/python/psutil/psutil/_pslinux.py --- a/third_party/python/psutil/psutil/_pslinux.py +++ b/third_party/python/psutil/psutil/_pslinux.py @@ -1046,30 +1046,28 @@ def disk_io_counters(): # On Linux 2.4 each line has always 15 fields, e.g.: # "3 0 8 hda 8 8 8 8 8 8 8 8 8 8 8" # On Linux 2.6+ each line *usually* has 14 fields, and the disk # name is in another position, like this: # "3 0 hda 8 8 8 8 8 8 8 8 8 8 8" # ...unless (Linux 2.6) the line refers to a partition instead # of a disk, in which case the line has less fields (7): # "3 1 hda1 8 8 8 8" - # 4.18+ has 4 fields added: - # "3 0 hda 8 8 8 8 8 8 8 8 8 8 8 0 0 0 0" # See: # https://www.kernel.org/doc/Documentation/iostats.txt # https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats fields = line.split() fields_len = len(fields) if fields_len == 15: # Linux 2.4 name = fields[3] reads = int(fields[2]) (reads_merged, rbytes, rtime, writes, writes_merged, wbytes, wtime, _, busy_time, _) = map(int, fields[4:14]) - elif fields_len == 14 or fields_len == 18: + elif fields_len == 14: # Linux 2.6+, line referring to a disk name = fields[2] (reads, reads_merged, rbytes, rtime, writes, writes_merged, wbytes, wtime, _, busy_time, _) = map(int, fields[3:14]) elif fields_len == 7: # Linux 2.6+, line referring to a partition name = fields[2] reads, rbytes, writes, wbytes = map(int, fields[3:]) diff --git a/third_party/python/requirements.in b/third_party/python/requirements.in --- a/third_party/python/requirements.in +++ b/third_party/python/requirements.in @@ -1,11 +1,12 @@ attrs==18.1.0 biplist==1.0.3 blessings==1.7 +distro==1.4.0 jsmin==2.1.0 json-e==2.7.0 mozilla-version==0.3.0 pathlib2==2.3.2 pip-tools==3.0.0 pipenv==2018.5.18 psutil==5.4.3 pytest==3.6.2 diff --git a/third_party/python/requirements.txt b/third_party/python/requirements.txt --- a/third_party/python/requirements.txt +++ b/third_party/python/requirements.txt @@ -14,16 +14,19 @@ blessings==1.7 \ certifi==2018.4.16 \ --hash=sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7 \ --hash=sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0 \ # via pipenv click==7.0 \ --hash=sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13 \ --hash=sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7 \ # via pip-tools +distro==1.4.0 \ + --hash=sha256:362dde65d846d23baee4b5c058c8586f219b5a54be1cf5fc6ff55c4578392f57 \ + --hash=sha256:eedf82a470ebe7d010f1872c17237c79ab04097948800029994fa458e52fb4b4 enum34==1.1.6 \ --hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \ --hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \ --hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \ --hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1 \ # via mozilla-version funcsigs==1.0.2 \ --hash=sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca \