├── .gitattributes ├── .github └── workflows │ ├── docs-ci.yml │ └── pypi-release.yml ├── .gitignore ├── .readthedocs.yml ├── AUTHORS.rst ├── CHANGELOG.rst ├── CODE_OF_CONDUCT.rst ├── MANIFEST.in ├── Makefile ├── NOTICE ├── README.rst ├── apache-2.0.LICENSE ├── azure-pipelines.yml ├── bsd-new.LICENSE ├── configure ├── configure.bat ├── conftest.py ├── default.nix ├── docs ├── Makefile ├── make.bat ├── scripts │ ├── doc8_style_check.sh │ └── sphinx_build_link_check.sh └── source │ ├── _static │ └── theme_overrides.css │ ├── conf.py │ ├── contribute │ └── contrib_doc.rst │ ├── index.rst │ └── skeleton-usage.rst ├── etc ├── ci │ ├── azure-container-deb.yml │ ├── azure-container-rpm.yml │ ├── azure-posix.yml │ ├── azure-win.yml │ ├── install_sudo.sh │ ├── macports-ci │ ├── macports-ci.ABOUT │ └── mit.LICENSE └── scripts │ ├── README.rst │ ├── check_thirdparty.py │ ├── fetch_thirdparty.py │ ├── gen_pypi_simple.py │ ├── gen_pypi_simple.py.ABOUT │ ├── gen_pypi_simple.py.NOTICE │ ├── gen_requirements.py │ ├── gen_requirements_dev.py │ ├── requirements.txt │ ├── test_utils_pip_compatibility_tags.py │ ├── test_utils_pip_compatibility_tags.py.ABOUT │ ├── test_utils_pypi_supported_tags.py │ ├── test_utils_pypi_supported_tags.py.ABOUT │ ├── utils_dejacode.py │ ├── utils_pip_compatibility_tags.py │ ├── utils_pip_compatibility_tags.py.ABOUT │ ├── utils_pypi_supported_tags.py │ ├── utils_pypi_supported_tags.py.ABOUT │ ├── utils_requirements.py │ ├── utils_thirdparty.py │ └── utils_thirdparty.py.ABOUT ├── flake.lock ├── flake.nix ├── mit.LICENSE ├── overlay.nix ├── pyproject.toml ├── requirements-dev.txt ├── requirements.txt ├── setup.cfg ├── setup.py ├── shell.nix ├── src └── univers │ ├── __init__.py │ ├── arch.py │ ├── arch.py.ABOUT │ ├── arch.py.NOTICE │ ├── bsd-new.LICENSE │ ├── conan │ ├── __init__.py │ ├── errors.py │ ├── errors.py.ABOUT │ ├── errors.py.NOTICE │ ├── version.py │ ├── version.py.ABOUT │ ├── version.py.NOTICE │ ├── version_range.py │ ├── version_range.py.ABOUT │ └── version_range.py.NOTICE │ ├── debian.py │ ├── debian.py.ABOUT │ ├── debian.py.NOTICE │ ├── gem.py │ ├── gem.py.ABOUT │ ├── gem.py.NOTICE │ ├── gentoo.py │ ├── gentoo.py.ABOUT │ ├── gentoo.py.NOTICE │ ├── maven.py │ ├── maven.py.ABOUT │ ├── maven.py.NOTICE │ ├── nuget.py │ ├── nuget.py.ABOUT │ ├── nuget.py.NOTICE │ ├── rpm.py │ ├── rpm.py.ABOUT │ ├── rpm.py.NOTICE │ ├── rpm.py.README │ ├── rpm.py.antlir.ABOUT │ ├── rpm.py.antlir.LICENSE │ ├── rpm.py.antlir.NOTICE │ ├── univers_semver.py │ ├── utils.py │ ├── version_constraint.py │ ├── version_range.py │ └── versions.py └── tests ├── apache-2.0.LICENSE ├── bsd-new.LICENSE ├── data ├── alpine_test.txt ├── alpine_test.txt.ABOUT ├── alpine_test.txt.NOTICE ├── apache-2.0.LICENSE ├── composer_gitlab.json ├── conan_advisory.json ├── gem_gitlab.json ├── go_gitlab.json ├── gpl-2.0.LICENSE ├── npm_advisory.json ├── npm_gitlab.json ├── openssl │ ├── openssl_all_versions.txt │ └── openssl_versort_expected.json ├── pypi_gitlab.json ├── rpmvercmp.at ├── rpmvercmp.at.ABOUT ├── rpmvercmp.at.NOTICE └── test-suite-data.json ├── gpl-2.0.LICENSE ├── nuget ├── test_nuget_floating_range.py ├── test_nuget_semver_201_spec.py ├── test_nuget_version.py ├── test_nuget_version_comparer.py ├── test_nuget_version_parsing.py ├── test_nuget_version_range.py ├── test_nuget_version_range_float_parsing.py └── test_nuget_version_range_operation.py ├── nuget_versioning_tests.ABOUT ├── nuget_versioning_tests.NOTICE ├── nuget_versioning_tests.README.md ├── test_alpine.py ├── test_bundler_version_ranges_spec.py ├── test_bundler_version_ranges_spec.py.ABOUT ├── test_bundler_version_ranges_spec.py.NOTICE ├── test_codestyle.py ├── test_conan_version_bump.py ├── test_conan_version_bump.py.ABOUT ├── test_conan_version_bump.py.NOTICE ├── test_conan_version_comparison.py ├── test_conan_version_comparison.py.ABOUT ├── test_conan_version_comparison.py.NOTICE ├── test_conan_version_range.py ├── test_conan_version_range.py.ABOUT ├── test_conan_version_range.py.NOTICE ├── test_debian_version.py ├── test_debian_version.py.ABOUT ├── test_debian_version.py.NOTICE ├── test_debian_version_python_deb_pkg_tools.py ├── test_debian_version_python_deb_pkg_tools.py.ABOUT ├── test_gem.py ├── test_gem.py.ABOUT ├── test_gem.py.NOTICE ├── test_gentoo.py ├── test_gentoo.py.ABOUT ├── test_gentoo.py.NOTICE ├── test_gentoo_pkgcore.py ├── test_gentoo_pkgcore.py.ABOUT ├── test_gentoo_pkgcore.py.NOTICE ├── test_maven_version.py ├── test_maven_version.py.ABOUT ├── test_maven_version.py.NOTICE ├── test_maven_version_range.py ├── test_nuget.py ├── test_nuget.py.ABOUT ├── test_nuget.py.NOTICE ├── test_openssl_vercmp.py ├── test_openssl_versort.py ├── test_pacman_vercmp.py ├── test_pacman_vercmp.py.ABOUT ├── test_pacman_vercmp.py.NOTICE ├── test_pypi_version.py ├── test_python_semver.py ├── test_rpm.py ├── test_rpm.py.antlir.ABOUT ├── test_rpm.py.mit.NOTICE ├── test_rpm_vercmp.py ├── test_rpm_vercmp.py.ABOUT ├── test_rpm_vercmp.py.NOTICE ├── test_rubygems_gem_requirement.py ├── test_rubygems_gem_requirement.py.ABOUT ├── test_rubygems_gem_requirement.py.NOTICE ├── test_rubygems_gem_version.py ├── test_rubygems_gem_version.py.ABOUT ├── test_rubygems_gem_version.py.NOTICE ├── test_skeleton_codestyle.py ├── test_vers.py ├── test_version_comparison.py ├── test_version_constraint.py ├── test_version_range.py ├── test_versions.py └── util_tests.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Ignore all Git auto CR/LF line endings conversions 2 | * -text 3 | pyproject.toml export-subst 4 | -------------------------------------------------------------------------------- /.github/workflows/docs-ci.yml: -------------------------------------------------------------------------------- 1 | name: CI Documentation 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-22.04 8 | 9 | strategy: 10 | max-parallel: 4 11 | matrix: 12 | python-version: [3.9] 13 | 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v3 17 | 18 | - name: Set up Python ${{ matrix.python-version }} 19 | uses: actions/setup-python@v4 20 | with: 21 | python-version: ${{ matrix.python-version }} 22 | 23 | - name: Install Dependencies 24 | run: pip install -e .[docs] 25 | 26 | - name: Check Sphinx Documentation build minimally 27 | working-directory: ./docs 28 | run: sphinx-build -E -W source build 29 | 30 | - name: Check for documentation style errors 31 | working-directory: ./docs 32 | run: ./scripts/doc8_style_check.sh 33 | 34 | 35 | -------------------------------------------------------------------------------- /.github/workflows/pypi-release.yml: -------------------------------------------------------------------------------- 1 | name: Release library as a PyPI wheel and sdist on tag 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | build-and-publish-to-pypi: 9 | name: Build and publish library to PyPI 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@master 13 | - name: Set up Python 14 | uses: actions/setup-python@v1 15 | with: 16 | python-version: 3.9 17 | - name: Install pypa/build 18 | run: python -m pip install build --user 19 | - name: Build a binary wheel and a source tarball 20 | run: python -m build --sdist --wheel --outdir dist/ 21 | . 22 | - name: Publish distribution to PyPI 23 | if: startsWith(github.ref, 'refs/tags') 24 | uses: pypa/gh-action-pypi-publish@master 25 | with: 26 | password: ${{ secrets.PYPI_API_TOKEN }} 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python compiled files 2 | *.py[cod] 3 | 4 | # virtualenv and other misc bits 5 | /src/*.egg-info 6 | *.egg-info 7 | /dist 8 | /build 9 | /bin 10 | /lib 11 | /scripts 12 | /Scripts 13 | /Lib 14 | /pip-selfcheck.json 15 | /tmp 16 | /venv 17 | .Python 18 | /include 19 | /Include 20 | /local 21 | */local/* 22 | /local/ 23 | /share/ 24 | /tcl/ 25 | /.eggs/ 26 | 27 | # Installer logs 28 | pip-log.txt 29 | 30 | # Unit test / coverage reports 31 | .cache 32 | .coverage 33 | .coverage.* 34 | nosetests.xml 35 | htmlcov 36 | 37 | # Translations 38 | *.mo 39 | 40 | # IDEs 41 | .project 42 | .pydevproject 43 | .idea 44 | org.eclipse.core.resources.prefs 45 | .vscode 46 | .vs 47 | 48 | # Sphinx 49 | docs/_build 50 | docs/bin 51 | docs/build 52 | docs/include 53 | docs/Lib 54 | doc/pyvenv.cfg 55 | pyvenv.cfg 56 | 57 | # Various junk and temp files 58 | .DS_Store 59 | *~ 60 | .*.sw[po] 61 | .build 62 | .ve 63 | *.bak 64 | /.cache/ 65 | 66 | # pyenv 67 | /.python-version 68 | /man/ 69 | /.pytest_cache/ 70 | lib64 71 | tcl 72 | 73 | # Ignore Jupyter Notebook related temp files 74 | .ipynb_checkpoints/ 75 | 76 | # Nix 77 | /result* 78 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build in latest ubuntu/python 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | 14 | # Build PDF & ePub 15 | formats: 16 | - epub 17 | - pdf 18 | 19 | # Where the Sphinx conf.py file is located 20 | sphinx: 21 | configuration: docs/source/conf.py 22 | 23 | # Setting the python version and doc build requirements 24 | python: 25 | install: 26 | - method: pip 27 | path: . 28 | extra_requirements: 29 | - docs 30 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | The following organizations or individuals have contributed to this repo: 2 | 3 | - Shivam Sandbhor @sbs2001 4 | - Philippe Ombredanne @pombredanne 5 | - Hritik Vijay @Hritik14 6 | - Tushar Goel @TG1999 7 | - Keshav Priyadarshi @keshav-space 8 | - Chin-Yeung Li @chinyeungli 9 | - Ayan Sinha Mahapatra @AyanSinhaMahapatra 10 | - Jono Yang @JonoYang 11 | 12 | Plus 100+ contributors that created the underlying and bundled version handling 13 | utilities. -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | Version v30.12.1 5 | ---------------- 6 | 7 | - Update link references of ownership from nexB to aboutcode-org. https://github.com/aboutcode-org/univers/issues/140 8 | 9 | 10 | Version v30.12.0 11 | ---------------- 12 | 13 | - Support VersionRange normalization using known versions. https://github.com/nexB/univers/pull/108 14 | - Fix the edge case resulting in incorrect ``contains`` resolution in VersionRange. https://github.com/nexB/univers/issues/137 https://github.com/nexB/univers/pull/108 15 | - Use native impl to parse Maven and NuGet range expression in ``from_gitlab_native``. https://github.com/nexB/univers/issues/136 https://github.com/nexB/univers/pull/108 16 | - Fix incorrect parsing of composer range in ``from_gitlab_native``. https://github.com/nexB/univers/issues/136 https://github.com/nexB/univers/pull/108 17 | 18 | 19 | Version v30.11.0 20 | ---------------- 21 | 22 | - Use proper exception subclass for invalid constraints error. 23 | 24 | 25 | Version v30.10.1 26 | ---------------- 27 | 28 | - Add Nix flake as a build system. 29 | - Refactor gem and make nuget hashable. 30 | - Update skeleton. 31 | - Handle NoneType in VersionRange.from_string. 32 | - Handle npm prerelease caret range expression. 33 | 34 | 35 | Version v30.10.0 36 | ---------------- 37 | 38 | - Add support for conan version and version range. 39 | - Fix version comparison for all the versions. 40 | 41 | 42 | Version v30.9.2 43 | ---------------- 44 | 45 | - Fix unhashable error in GemVersion. 46 | 47 | 48 | Version v30.9.1 49 | ---------------- 50 | 51 | - Add invert function to VersionRange. 52 | 53 | 54 | Version v30.9.0 55 | ---------------- 56 | 57 | - Change type of archlinux version ranges to alpm. 58 | 59 | 60 | Version v30.8.0 61 | ---------------- 62 | 63 | - Fix npm version ranges 64 | 65 | 66 | Version v30.7.0 67 | ---------------- 68 | 69 | - Add composer and golang versions and also support gitlab native ranges for them 70 | 71 | 72 | Version v30.6.0 73 | ---------------- 74 | 75 | - Add support for gitlab in pypi, npm, gem version ranges 76 | - Subclass semver for nginx 77 | 78 | 79 | Version v30.5.1 80 | ---------------- 81 | 82 | - Fix Nuget string representation 83 | - Test sorting of all the OpenSSL versions ever released 84 | 85 | 86 | Version v30.5.0 87 | ---------------- 88 | 89 | - Add version range support for maven 90 | - Remove unsupported characters in Pypi from_native implementation 91 | - Add Nuget Version support in Univers 92 | 93 | 94 | Version v30.4.0 95 | ---------------- 96 | 97 | - Add support for forming VersionRange from a list of versions.Thank you 98 | to Keshav Priyadarshi @keshav-space for this. 99 | 100 | 101 | Version v30.3.1 102 | ---------------- 103 | 104 | - Change equal comparator for github native ranges 105 | 106 | 107 | Version v30.3.0 108 | ---------------- 109 | 110 | - New support for native GitHub version ranges. GitHub native version range is different from 111 | other native ranges. For example: 112 | Maven native version range looks like: 113 | `[1.0.0,1.0.1)` 114 | Github native version range looks like: 115 | `>= 1.0.0, < 1.0.1` 116 | 117 | 118 | Version v30.2.0 119 | ---------------- 120 | 121 | - New support for OpenSSL version(s). These are peculiar because there are two 122 | epochs in the versioning: the versioning scheme is custom before version 3 123 | and is based on semver from version 3 onwards. Thank you to Keshav Priyadarshi 124 | @keshav-space for this. 125 | 126 | 127 | Version v30.1.0 128 | ----------------- 129 | 130 | - New support for Alpine package versions. These are based loosely on Gentoo 131 | versions with some variations. We do not support all the version styles yet. 132 | The unit tests are based on the upstream apk-tools tests and this brings in 133 | 700 new unit tests. 134 | - Fix handling of caret and tilde version in npm version ranges. 135 | - Enable automated build of wheels on release 136 | - Adopt latest skeleton, droping support for tests on macOS 10.14 137 | 138 | 139 | Version v30.0.0 140 | ----------------- 141 | 142 | - Implement the new "vers" spec. This is a major incomplatible change. 143 | - Add support for nginx version scheme 144 | - Switching back to semver 145 | - Improve origin and license documentation 146 | - Add tests for carets in RPMs 147 | - Format, streamline and refactor code 148 | - Improve testing 149 | 150 | 151 | Version v21.4.9 152 | ----------------- 153 | 154 | - Add support Gentoo style versions. 155 | 156 | 157 | Version v21.4.8 158 | ----------------- 159 | 160 | - Add support for more package types. 161 | - Version classes are now hashable and frozen 162 | 163 | 164 | Version v21.4.6 165 | ----------------- 166 | 167 | - Initial Release 168 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.rst: -------------------------------------------------------------------------------- 1 | Contributor Covenant Code of Conduct 2 | ==================================== 3 | 4 | Our Pledge 5 | ---------- 6 | 7 | In the interest of fostering an open and welcoming environment, we as 8 | contributors and maintainers pledge to making participation in our 9 | project and our community a harassment-free experience for everyone, 10 | regardless of age, body size, disability, ethnicity, gender identity and 11 | expression, level of experience, education, socio-economic status, 12 | nationality, personal appearance, race, religion, or sexual identity and 13 | orientation. 14 | 15 | Our Standards 16 | ------------- 17 | 18 | Examples of behavior that contributes to creating a positive environment 19 | include: 20 | 21 | - Using welcoming and inclusive language 22 | - Being respectful of differing viewpoints and experiences 23 | - Gracefully accepting constructive criticism 24 | - Focusing on what is best for the community 25 | - Showing empathy towards other community members 26 | 27 | Examples of unacceptable behavior by participants include: 28 | 29 | - The use of sexualized language or imagery and unwelcome sexual 30 | attention or advances 31 | - Trolling, insulting/derogatory comments, and personal or political 32 | attacks 33 | - Public or private harassment 34 | - Publishing others’ private information, such as a physical or 35 | electronic address, without explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | Our Responsibilities 40 | -------------------- 41 | 42 | Project maintainers are responsible for clarifying the standards of 43 | acceptable behavior and are expected to take appropriate and fair 44 | corrective action in response to any instances of unacceptable behavior. 45 | 46 | Project maintainers have the right and responsibility to remove, edit, 47 | or reject comments, commits, code, wiki edits, issues, and other 48 | contributions that are not aligned to this Code of Conduct, or to ban 49 | temporarily or permanently any contributor for other behaviors that they 50 | deem inappropriate, threatening, offensive, or harmful. 51 | 52 | Scope 53 | ----- 54 | 55 | This Code of Conduct applies both within project spaces and in public 56 | spaces when an individual is representing the project or its community. 57 | Examples of representing a project or community include using an 58 | official project e-mail address, posting via an official social media 59 | account, or acting as an appointed representative at an online or 60 | offline event. Representation of a project may be further defined and 61 | clarified by project maintainers. 62 | 63 | Enforcement 64 | ----------- 65 | 66 | Instances of abusive, harassing, or otherwise unacceptable behavior may 67 | be reported by contacting the project team at pombredanne@gmail.com 68 | or on the Gitter chat channel at https://gitter.im/aboutcode-org/discuss . 69 | All complaints will be reviewed and investigated and will result in a 70 | response that is deemed necessary and appropriate to the circumstances. 71 | The project team is obligated to maintain confidentiality with regard to 72 | the reporter of an incident. Further details of specific enforcement 73 | policies may be posted separately. 74 | 75 | Project maintainers who do not follow or enforce the Code of Conduct in 76 | good faith may face temporary or permanent repercussions as determined 77 | by other members of the project’s leadership. 78 | 79 | Attribution 80 | ----------- 81 | 82 | This Code of Conduct is adapted from the `Contributor Covenant`_ , 83 | version 1.4, available at 84 | https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 85 | 86 | .. _Contributor Covenant: https://www.contributor-covenant.org 87 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft src 2 | 3 | include *.LICENSE 4 | include NOTICE 5 | include *.ABOUT 6 | include *.toml 7 | include *.yml 8 | include *.rst 9 | include setup.* 10 | include configure* 11 | include requirements* 12 | include .git* 13 | 14 | global-exclude *.py[co] __pycache__ *.*~ 15 | 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # 3 | # Copyright (c) nexB Inc. and others. All rights reserved. 4 | # ScanCode is a trademark of nexB Inc. 5 | # SPDX-License-Identifier: Apache-2.0 6 | # See http://www.apache.org/licenses/LICENSE-2.0 for the license text. 7 | # See https://github.com/aboutcode-org/skeleton for support or download. 8 | # See https://aboutcode.org for more information about nexB OSS projects. 9 | # 10 | 11 | # Python version can be specified with `$ PYTHON_EXE=python3.x make conf` 12 | PYTHON_EXE?=python3 13 | VENV=venv 14 | ACTIVATE?=. ${VENV}/bin/activate; 15 | 16 | dev: 17 | @echo "-> Configure the development envt." 18 | ./configure --dev 19 | 20 | isort: 21 | @echo "-> Apply isort changes to ensure proper imports ordering" 22 | ${VENV}/bin/isort --sl -l 100 src tests setup.py 23 | 24 | black: 25 | @echo "-> Apply black code formatter" 26 | ${VENV}/bin/black -l 100 src tests setup.py 27 | 28 | doc8: 29 | @echo "-> Run doc8 validation" 30 | @${ACTIVATE} doc8 --max-line-length 100 --ignore-path docs/_build/ --quiet docs/ 31 | 32 | valid: isort black 33 | 34 | check: 35 | @echo "-> Run pycodestyle (PEP8) validation" 36 | @${ACTIVATE} pycodestyle --max-line-length=100 --exclude=.eggs,venv,lib,thirdparty,docs,migrations,settings.py,.cache . 37 | @echo "-> Run isort imports ordering validation" 38 | @${ACTIVATE} isort --sl --check-only -l 100 setup.py src tests . 39 | @echo "-> Run black validation" 40 | @${ACTIVATE} black --check --check -l 100 src tests setup.py 41 | 42 | clean: 43 | @echo "-> Clean the Python env" 44 | ./configure --clean 45 | 46 | test: 47 | @echo "-> Run the test suite" 48 | ${VENV}/bin/pytest -vvs 49 | 50 | docs: 51 | rm -rf docs/_build/ 52 | @${ACTIVATE} sphinx-build docs/ docs/_build/ 53 | 54 | .PHONY: conf dev check valid black isort clean test docs 55 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/vulnerablecode 6 | # for support and download. 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | 2 | ################################################################################ 3 | # We use Azure to run the full tests suites on multiple Python 3.x 4 | # on multiple Windows, macOS and Linux versions all on 64 bits 5 | # These jobs are using VMs with Azure-provided Python builds 6 | ################################################################################ 7 | 8 | jobs: 9 | 10 | - template: etc/ci/azure-posix.yml 11 | parameters: 12 | job_name: ubuntu20_cpython 13 | image_name: ubuntu-20.04 14 | python_versions: ['3.8', '3.9', '3.10', '3.11', '3.12'] 15 | test_suites: 16 | all: | 17 | source venv/bin/activate 18 | pytest -n 2 -vvs 19 | 20 | - template: etc/ci/azure-posix.yml 21 | parameters: 22 | job_name: ubuntu22_cpython 23 | image_name: ubuntu-22.04 24 | python_versions: ['3.8', '3.9', '3.10', '3.11', '3.12'] 25 | test_suites: 26 | all: | 27 | source venv/bin/activate 28 | pytest -n 2 -vvs 29 | 30 | - template: etc/ci/azure-posix.yml 31 | parameters: 32 | job_name: macos12_cpython 33 | image_name: macOS-12 34 | python_versions: ['3.8', '3.9', '3.10', '3.11', '3.12'] 35 | test_suites: 36 | all: | 37 | source venv/bin/activate 38 | pytest -n 2 -vvs 39 | 40 | - template: etc/ci/azure-posix.yml 41 | parameters: 42 | job_name: macos13_cpython 43 | image_name: macOS-13 44 | python_versions: ['3.8', '3.9', '3.10', '3.11', '3.12'] 45 | test_suites: 46 | all: venv/bin/pytest -n 2 -vvs 47 | 48 | - template: etc/ci/azure-posix.yml 49 | parameters: 50 | job_name: macos14_cpython_arm64 51 | image_name: macOS-14 52 | python_versions: ['3.8', '3.9', '3.10', '3.11', '3.12'] 53 | test_suites: 54 | all: venv/bin/pytest -n 2 -vvs 55 | 56 | - template: etc/ci/azure-win.yml 57 | parameters: 58 | job_name: win2019_cpython 59 | image_name: windows-2019 60 | python_versions: ['3.8', '3.9', '3.10', '3.11', '3.12'] 61 | test_suites: 62 | all: | 63 | call venv\Scripts\activate.bat 64 | pytest -n 2 -vvs 65 | 66 | - template: etc/ci/azure-win.yml 67 | parameters: 68 | job_name: win2022_cpython 69 | image_name: windows-2022 70 | python_versions: ['3.8', '3.9', '3.10', '3.11', '3.12'] 71 | test_suites: 72 | all: | 73 | call venv\Scripts\activate.bat 74 | pytest -n 2 -vvs 75 | -------------------------------------------------------------------------------- /bsd-new.LICENSE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without modification, 2 | are permitted provided that the following conditions are met: 3 | 4 | Redistributions of source code must retain the above copyright notice, this list 5 | of conditions and the following disclaimer. 6 | 7 | Redistributions in binary form must reproduce the above copyright notice, this 8 | list of conditions and the following disclaimer in the documentation and/or 9 | other materials provided with the distribution. 10 | 11 | Neither the name of the ORGANIZATION nor the names of its contributors may be 12 | used to endorse or promote products derived from this software without specific 13 | prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 19 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 21 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 24 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /conftest.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | collect_ignore = ["setup.py"] 8 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | (import (fetchTarball https://github.com/edolstra/flake-compat/archive/b4a34015c698c7793d592d66adbab377907a2be8.tar.gz) { 2 | src = builtins.fetchGit ./.; 3 | }).defaultNix 4 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SPHINXAUTOBUILD = sphinx-autobuild 9 | SOURCEDIR = source 10 | BUILDDIR = build 11 | 12 | # Put it first so that "make" without argument is like "make help". 13 | help: 14 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 15 | 16 | .PHONY: help Makefile 17 | 18 | # Run the development server using sphinx-autobuild 19 | docs: 20 | @echo 21 | @echo "Starting up the docs server..." 22 | @echo 23 | $(SPHINXAUTOBUILD) --port 8000 --watch ${SOURCEDIR} $(SOURCEDIR) "$(BUILDDIR)/html" $(SPHINXOPTS) $(O) 24 | 25 | # Catch-all target: route all unknown targets to Sphinx using the new 26 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 27 | %: Makefile 28 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 29 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | if "%SPHINXAUTOBUILD%" == "" ( 11 | set SPHINXAUTOBUILD=sphinx-autobuild 12 | ) 13 | set SOURCEDIR=source 14 | set BUILDDIR=build 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "docs" goto docs 19 | 20 | %SPHINXBUILD% >NUL 2>NUL 21 | if errorlevel 9009 ( 22 | echo. 23 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 24 | echo.installed, then set the SPHINXBUILD environment variable to point 25 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 26 | echo.may add the Sphinx directory to PATH. 27 | echo. 28 | echo.If you don't have Sphinx installed, grab it from 29 | echo.http://sphinx-doc.org/ 30 | exit /b 1 31 | ) 32 | 33 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 34 | goto end 35 | 36 | :docs 37 | @echo 38 | @echo Starting up the docs server... 39 | @echo 40 | %SPHINXAUTOBUILD% --port 8000 --watch %SOURCEDIR% %SOURCEDIR% %BUILDDIR%\html %SPHINXOPTS% %O% 41 | goto end 42 | 43 | :help 44 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 45 | 46 | :end 47 | popd 48 | -------------------------------------------------------------------------------- /docs/scripts/doc8_style_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # halt script on error 3 | set -e 4 | # Check for Style Code Violations 5 | doc8 --max-line-length 100 source --ignore D000 --quiet -------------------------------------------------------------------------------- /docs/scripts/sphinx_build_link_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # halt script on error 3 | set -e 4 | # Build locally, and then check links 5 | sphinx-build -E -W -b linkcheck source build -------------------------------------------------------------------------------- /docs/source/_static/theme_overrides.css: -------------------------------------------------------------------------------- 1 | /* this is the container for the pages */ 2 | .wy-nav-content { 3 | max-width: 100%; 4 | padding: 0px 40px 0px 0px; 5 | margin-top: 0px; 6 | } 7 | 8 | .wy-nav-content-wrap { 9 | border-right: solid 1px; 10 | } 11 | 12 | div.rst-content { 13 | max-width: 1300px; 14 | border: 0; 15 | padding: 10px 80px 10px 80px; 16 | margin-left: 50px; 17 | } 18 | 19 | @media (max-width: 768px) { 20 | div.rst-content { 21 | max-width: 1300px; 22 | border: 0; 23 | padding: 0px 10px 10px 10px; 24 | margin-left: 0px; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = "nexb-skeleton" 21 | copyright = "nexB Inc. and others." 22 | author = "AboutCode.org authors and contributors" 23 | 24 | 25 | # -- General configuration --------------------------------------------------- 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be 28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 29 | # ones. 30 | extensions = [ 31 | "sphinx.ext.intersphinx", 32 | "sphinx_reredirects", 33 | "sphinx_rtd_theme", 34 | "sphinx_rtd_dark_mode", 35 | "sphinx.ext.extlinks", 36 | "sphinx_copybutton", 37 | ] 38 | 39 | 40 | # Redirects for olds pages 41 | # See https://documatt.gitlab.io/sphinx-reredirects/usage.html 42 | redirects = {} 43 | 44 | # This points to aboutcode.readthedocs.io 45 | # In case of "undefined label" ERRORS check docs on intersphinx to troubleshoot 46 | # Link was created at commit - https://github.com/aboutcode-org/aboutcode/commit/faea9fcf3248f8f198844fe34d43833224ac4a83 47 | 48 | intersphinx_mapping = { 49 | "aboutcode": ("https://aboutcode.readthedocs.io/en/latest/", None), 50 | "scancode-workbench": ( 51 | "https://scancode-workbench.readthedocs.io/en/develop/", 52 | None, 53 | ), 54 | } 55 | 56 | 57 | # Add any paths that contain templates here, relative to this directory. 58 | templates_path = ["_templates"] 59 | 60 | # List of patterns, relative to source directory, that match files and 61 | # directories to ignore when looking for source files. 62 | # This pattern also affects html_static_path and html_extra_path. 63 | exclude_patterns = [] 64 | 65 | 66 | # -- Options for HTML output ------------------------------------------------- 67 | 68 | # The theme to use for HTML and HTML Help pages. See the documentation for 69 | # a list of builtin themes. 70 | # 71 | html_theme = "sphinx_rtd_theme" 72 | 73 | # Add any paths that contain custom static files (such as style sheets) here, 74 | # relative to this directory. They are copied after the builtin static files, 75 | # so a file named "default.css" will overwrite the builtin "default.css". 76 | html_static_path = ["_static"] 77 | 78 | master_doc = "index" 79 | 80 | html_context = { 81 | "display_github": True, 82 | "github_user": "nexB", 83 | "github_repo": "nexb-skeleton", 84 | "github_version": "develop", # branch 85 | "conf_py_path": "/docs/source/", # path in the checkout to the docs root 86 | } 87 | 88 | html_css_files = [ 89 | "theme_overrides.css", 90 | ] 91 | 92 | 93 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 94 | html_show_sphinx = True 95 | 96 | # Define CSS and HTML abbreviations used in .rst files. These are examples. 97 | # .. role:: is used to refer to styles defined in _static/theme_overrides.css and is used like this: :red:`text` 98 | rst_prolog = """ 99 | .. |psf| replace:: Python Software Foundation 100 | 101 | .. # define a hard line break for HTML 102 | .. |br| raw:: html 103 | 104 |
105 | 106 | .. role:: red 107 | 108 | .. role:: img-title 109 | 110 | .. role:: img-title-para 111 | 112 | """ 113 | 114 | # -- Options for LaTeX output ------------------------------------------------- 115 | 116 | latex_elements = {"classoptions": ",openany,oneside"} 117 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to nexb-skeleton's documentation! 2 | ========================================= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | skeleton-usage 9 | contribute/contrib_doc 10 | 11 | Indices and tables 12 | ================== 13 | 14 | * :ref:`genindex` 15 | * :ref:`modindex` 16 | * :ref:`search` 17 | -------------------------------------------------------------------------------- /docs/source/skeleton-usage.rst: -------------------------------------------------------------------------------- 1 | Usage 2 | ===== 3 | A brand new project 4 | ------------------- 5 | .. code-block:: bash 6 | 7 | git init my-new-repo 8 | cd my-new-repo 9 | git pull git@github.com:nexB/skeleton 10 | 11 | # Create the new repo on GitHub, then update your remote 12 | git remote set-url origin git@github.com:nexB/your-new-repo.git 13 | 14 | From here, you can make the appropriate changes to the files for your specific project. 15 | 16 | Update an existing project 17 | --------------------------- 18 | .. code-block:: bash 19 | 20 | cd my-existing-project 21 | git remote add skeleton git@github.com:nexB/skeleton 22 | git fetch skeleton 23 | git merge skeleton/main --allow-unrelated-histories 24 | 25 | This is also the workflow to use when updating the skeleton files in any given repository. 26 | 27 | Customizing 28 | ----------- 29 | 30 | You typically want to perform these customizations: 31 | 32 | - remove or update the src/README.rst and tests/README.rst files 33 | - set project info and dependencies in setup.cfg 34 | - check the configure and configure.bat defaults 35 | 36 | Initializing a project 37 | ---------------------- 38 | 39 | All projects using the skeleton will be expected to pull all of it dependencies 40 | from thirdparty.aboutcode.org/pypi or the local thirdparty directory, using 41 | requirements.txt and/or requirements-dev.txt to determine what version of a 42 | package to collect. By default, PyPI will not be used to find and collect 43 | packages from. 44 | 45 | In the case where we are starting a new project where we do not have 46 | requirements.txt and requirements-dev.txt and whose dependencies are not yet on 47 | thirdparty.aboutcode.org/pypi, we run the following command after adding and 48 | customizing the skeleton files to your project: 49 | 50 | .. code-block:: bash 51 | 52 | ./configure 53 | 54 | This will initialize the virtual environment for the project, pull in the 55 | dependencies from PyPI and add them to the virtual environment. 56 | 57 | 58 | Generating requirements.txt and requirements-dev.txt 59 | ---------------------------------------------------- 60 | 61 | After the project has been initialized, we can generate the requirements.txt and 62 | requirements-dev.txt files. 63 | 64 | Ensure the virtual environment is enabled. 65 | 66 | .. code-block:: bash 67 | 68 | source venv/bin/activate 69 | 70 | To generate requirements.txt: 71 | 72 | .. code-block:: bash 73 | 74 | python etc/scripts/gen_requirements.py -s venv/lib/python/site-packages/ 75 | 76 | Replace \ with the version number of the Python being used, for example: 77 | ``venv/lib/python3.6/site-packages/`` 78 | 79 | To generate requirements-dev.txt after requirements.txt has been generated: 80 | 81 | .. code-block:: bash 82 | 83 | ./configure --dev 84 | python etc/scripts/gen_requirements_dev.py -s venv/lib/python/site-packages/ 85 | 86 | Note: on Windows, the ``site-packages`` directory is located at ``venv\Lib\site-packages\`` 87 | 88 | .. code-block:: bash 89 | 90 | python .\\etc\\scripts\\gen_requirements.py -s .\\venv\\Lib\\site-packages\\ 91 | .\configure --dev 92 | python .\\etc\\scripts\\gen_requirements_dev.py -s .\\venv\\Lib\\site-packages\\ 93 | 94 | 95 | Collecting and generating ABOUT files for dependencies 96 | ------------------------------------------------------ 97 | 98 | Ensure that the dependencies used by ``etc/scripts/fetch_thirdparty.py`` are installed: 99 | 100 | .. code-block:: bash 101 | 102 | pip install -r etc/scripts/requirements.txt 103 | 104 | Once we have requirements.txt and requirements-dev.txt, we can fetch the project 105 | dependencies as wheels and generate ABOUT files for them: 106 | 107 | .. code-block:: bash 108 | 109 | python etc/scripts/fetch_thirdparty.py -r requirements.txt -r requirements-dev.txt 110 | 111 | There may be issues with the generated ABOUT files, which will have to be 112 | corrected. You can check to see if your corrections are valid by running: 113 | 114 | .. code-block:: bash 115 | 116 | python etc/scripts/check_thirdparty.py -d thirdparty 117 | 118 | Once the wheels are collected and the ABOUT files are generated and correct, 119 | upload them to thirdparty.aboutcode.org/pypi by placing the wheels and ABOUT 120 | files from the thirdparty directory to the pypi directory at 121 | https://github.com/aboutcode-org/thirdparty-packages 122 | 123 | 124 | Usage after project initialization 125 | ---------------------------------- 126 | 127 | Once the ``requirements.txt`` and ``requirements-dev.txt`` have been generated 128 | and the project dependencies and their ABOUT files have been uploaded to 129 | thirdparty.aboutcode.org/pypi, you can configure the project as needed, typically 130 | when you update dependencies or use a new checkout. 131 | 132 | If the virtual env for the project becomes polluted, or you would like to remove 133 | it, use the ``--clean`` option: 134 | 135 | .. code-block:: bash 136 | 137 | ./configure --clean 138 | 139 | Then you can run ``./configure`` again to set up the project virtual environment. 140 | 141 | To set up the project for development use: 142 | 143 | .. code-block:: bash 144 | 145 | ./configure --dev 146 | 147 | To update the project dependencies (adding, removing, updating packages, etc.), 148 | update the dependencies in ``setup.cfg``, then run: 149 | 150 | .. code-block:: bash 151 | 152 | ./configure --clean # Remove existing virtual environment 153 | source venv/bin/activate # Ensure virtual environment is activated 154 | python etc/scripts/gen_requirements.py -s venv/lib/python/site-packages/ # Regenerate requirements.txt 155 | python etc/scripts/gen_requirements_dev.py -s venv/lib/python/site-packages/ # Regenerate requirements-dev.txt 156 | pip install -r etc/scripts/requirements.txt # Install dependencies needed by etc/scripts/bootstrap.py 157 | python etc/scripts/fetch_thirdparty.py -r requirements.txt -r requirements-dev.txt # Collect dependency wheels and their ABOUT files 158 | 159 | Ensure that the generated ABOUT files are valid, then take the dependency wheels 160 | and ABOUT files and upload them to thirdparty.aboutcode.org/pypi. 161 | -------------------------------------------------------------------------------- /etc/ci/azure-container-deb.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | job_name: '' 3 | container: '' 4 | python_path: '' 5 | python_version: '' 6 | package_manager: apt-get 7 | install_python: '' 8 | install_packages: | 9 | set -e -x 10 | sudo apt-get -y update 11 | sudo apt-get -y install \ 12 | build-essential \ 13 | xz-utils zlib1g bzip2 libbz2-1.0 tar \ 14 | sqlite3 libxml2-dev libxslt1-dev \ 15 | software-properties-common openssl 16 | test_suite: '' 17 | test_suite_label: '' 18 | 19 | 20 | jobs: 21 | - job: ${{ parameters.job_name }} 22 | 23 | pool: 24 | vmImage: 'ubuntu-16.04' 25 | 26 | container: 27 | image: ${{ parameters.container }} 28 | options: '--name ${{ parameters.job_name }} -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 -v /usr/bin/docker:/tmp/docker:ro' 29 | 30 | steps: 31 | - checkout: self 32 | fetchDepth: 10 33 | 34 | - script: /tmp/docker exec -t -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 -u 0 ${{ parameters.job_name }} $(Build.SourcesDirectory)/etc/ci/install_sudo.sh ${{ parameters.package_manager }} 35 | displayName: Install sudo 36 | 37 | - script: ${{ parameters.install_packages }} 38 | displayName: Install required packages 39 | 40 | - script: ${{ parameters.install_python }} 41 | displayName: 'Install Python ${{ parameters.python_version }}' 42 | 43 | - script: ${{ parameters.python_path }} --version 44 | displayName: 'Show Python version' 45 | 46 | - script: PYTHON_EXE=${{ parameters.python_path }} ./configure --dev 47 | displayName: 'Run Configure' 48 | 49 | - script: ${{ parameters.test_suite }} 50 | displayName: 'Run ${{ parameters.test_suite_label }} tests with py${{ parameters.python_version }} on ${{ parameters.job_name }}' 51 | -------------------------------------------------------------------------------- /etc/ci/azure-container-rpm.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | job_name: '' 3 | image_name: 'ubuntu-16.04' 4 | container: '' 5 | python_path: '' 6 | python_version: '' 7 | package_manager: yum 8 | install_python: '' 9 | install_packages: | 10 | set -e -x 11 | sudo yum groupinstall -y "Development Tools" 12 | sudo yum install -y \ 13 | openssl openssl-devel \ 14 | sqlite-devel zlib-devel xz-devel bzip2-devel \ 15 | bzip2 tar unzip zip \ 16 | libxml2-devel libxslt-devel 17 | test_suite: '' 18 | test_suite_label: '' 19 | 20 | 21 | jobs: 22 | - job: ${{ parameters.job_name }} 23 | 24 | pool: 25 | vmImage: ${{ parameters.image_name }} 26 | 27 | container: 28 | image: ${{ parameters.container }} 29 | options: '--name ${{ parameters.job_name }} -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 -v /usr/bin/docker:/tmp/docker:ro' 30 | 31 | steps: 32 | - checkout: self 33 | fetchDepth: 10 34 | 35 | - script: /tmp/docker exec -t -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 -u 0 ${{ parameters.job_name }} $(Build.SourcesDirectory)/etc/ci/install_sudo.sh ${{ parameters.package_manager }} 36 | displayName: Install sudo 37 | 38 | - script: ${{ parameters.install_packages }} 39 | displayName: Install required packages 40 | 41 | - script: ${{ parameters.install_python }} 42 | displayName: 'Install Python ${{ parameters.python_version }}' 43 | 44 | - script: ${{ parameters.python_path }} --version 45 | displayName: 'Show Python version' 46 | 47 | - script: PYTHON_EXE=${{ parameters.python_path }} ./configure --dev 48 | displayName: 'Run Configure' 49 | 50 | - script: ${{ parameters.test_suite }} 51 | displayName: 'Run ${{ parameters.test_suite_label }} tests with py${{ parameters.python_version }} on ${{ parameters.job_name }}' 52 | -------------------------------------------------------------------------------- /etc/ci/azure-posix.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | job_name: '' 3 | image_name: '' 4 | python_versions: [] 5 | test_suites: {} 6 | python_architecture: x64 7 | 8 | jobs: 9 | - job: ${{ parameters.job_name }} 10 | 11 | pool: 12 | vmImage: ${{ parameters.image_name }} 13 | 14 | strategy: 15 | matrix: 16 | ${{ each tsuite in parameters.test_suites }}: 17 | ${{ tsuite.key }}: 18 | test_suite_label: ${{ tsuite.key }} 19 | test_suite: ${{ tsuite.value }} 20 | 21 | steps: 22 | - checkout: self 23 | fetchDepth: 10 24 | 25 | - ${{ each pyver in parameters.python_versions }}: 26 | - task: UsePythonVersion@0 27 | inputs: 28 | versionSpec: '${{ pyver }}' 29 | architecture: '${{ parameters.python_architecture }}' 30 | displayName: '${{ pyver }} - Install Python' 31 | 32 | - script: | 33 | python${{ pyver }} --version 34 | echo "python${{ pyver }}" > PYTHON_EXECUTABLE 35 | ./configure --clean && ./configure --dev 36 | displayName: '${{ pyver }} - Configure' 37 | 38 | - script: $(test_suite) 39 | displayName: '${{ pyver }} - $(test_suite_label) on ${{ parameters.job_name }}' 40 | -------------------------------------------------------------------------------- /etc/ci/azure-win.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | job_name: '' 3 | image_name: '' 4 | python_versions: [] 5 | test_suites: {} 6 | python_architecture: x64 7 | 8 | jobs: 9 | - job: ${{ parameters.job_name }} 10 | 11 | pool: 12 | vmImage: ${{ parameters.image_name }} 13 | 14 | strategy: 15 | matrix: 16 | ${{ each tsuite in parameters.test_suites }}: 17 | ${{ tsuite.key }}: 18 | test_suite_label: ${{ tsuite.key }} 19 | test_suite: ${{ tsuite.value }} 20 | 21 | steps: 22 | - checkout: self 23 | fetchDepth: 10 24 | 25 | - ${{ each pyver in parameters.python_versions }}: 26 | - task: UsePythonVersion@0 27 | inputs: 28 | versionSpec: '${{ pyver }}' 29 | architecture: '${{ parameters.python_architecture }}' 30 | displayName: '${{ pyver }} - Install Python' 31 | 32 | - script: | 33 | python --version 34 | echo | set /p=python> PYTHON_EXECUTABLE 35 | configure --clean && configure --dev 36 | displayName: '${{ pyver }} - Configure' 37 | 38 | - script: $(test_suite) 39 | displayName: '${{ pyver }} - $(test_suite_label) on ${{ parameters.job_name }}' 40 | -------------------------------------------------------------------------------- /etc/ci/install_sudo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | 5 | if [[ "$1" == "apt-get" ]]; then 6 | apt-get update -y 7 | apt-get -o DPkg::Options::="--force-confold" install -y sudo 8 | 9 | elif [[ "$1" == "yum" ]]; then 10 | yum install -y sudo 11 | 12 | elif [[ "$1" == "dnf" ]]; then 13 | dnf install -y sudo 14 | 15 | fi 16 | -------------------------------------------------------------------------------- /etc/ci/macports-ci.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: macports-ci 2 | name: macports-ci 3 | version: c9676e67351a3a519e37437e196cd0ee9c2180b8 4 | download_url: https://raw.githubusercontent.com/GiovanniBussi/macports-ci/c9676e67351a3a519e37437e196cd0ee9c2180b8/macports-ci 5 | description: Simplify MacPorts setup on Travis-CI 6 | homepage_url: https://github.com/GiovanniBussi/macports-ci 7 | license_expression: mit 8 | copyright: Copyright (c) Giovanni Bussi 9 | attribute: yes 10 | checksum_md5: 5d31d479132502f80acdaed78bed9e23 11 | checksum_sha1: 74b15643bd1a528d91b4a7c2169c6fc656f549c2 12 | package_url: pkg:github/giovannibussi/macports-ci@c9676e67351a3a519e37437e196cd0ee9c2180b8#macports-ci 13 | licenses: 14 | - key: mit 15 | name: MIT License 16 | file: mit.LICENSE 17 | -------------------------------------------------------------------------------- /etc/ci/mit.LICENSE: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 2 | 3 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /etc/scripts/README.rst: -------------------------------------------------------------------------------- 1 | This directory contains the tools to manage a directory of thirdparty Python 2 | package source, wheels and metadata pin, build, update, document and publish to 3 | a PyPI-like repo (GitHub release). 4 | 5 | NOTE: These are tested to run ONLY on Linux. 6 | 7 | 8 | Thirdparty packages management scripts 9 | ====================================== 10 | 11 | Pre-requisites 12 | -------------- 13 | 14 | * There are two run "modes": 15 | 16 | * To generate or update pip requirement files, you need to start with a clean 17 | virtualenv as instructed below (This is to avoid injecting requirements 18 | specific to the tools used here in the main requirements). 19 | 20 | * For other usages, the tools here can run either in their own isolated 21 | virtualenv or in the the main configured development virtualenv. 22 | These requireements need to be installed:: 23 | 24 | pip install --requirement etc/scripts/requirements.txt 25 | 26 | TODO: we need to pin the versions of these tools 27 | 28 | 29 | 30 | Generate or update pip requirement files 31 | ---------------------------------------- 32 | 33 | Scripts 34 | ~~~~~~~ 35 | 36 | **gen_requirements.py**: create/update requirements files from currently 37 | installed requirements. 38 | 39 | **gen_requirements_dev.py** does the same but can subtract the main requirements 40 | to get extra requirements used in only development. 41 | 42 | 43 | Usage 44 | ~~~~~ 45 | 46 | The sequence of commands to run are: 47 | 48 | 49 | * Start with these to generate the main pip requirements file:: 50 | 51 | ./configure --clean 52 | ./configure 53 | python etc/scripts/gen_requirements.py --site-packages-dir 54 | 55 | * You can optionally install or update extra main requirements after the 56 | ./configure step such that these are included in the generated main requirements. 57 | 58 | * Optionally, generate a development pip requirements file by running these:: 59 | 60 | ./configure --clean 61 | ./configure --dev 62 | python etc/scripts/gen_requirements_dev.py --site-packages-dir 63 | 64 | * You can optionally install or update extra dev requirements after the 65 | ./configure step such that these are included in the generated dev 66 | requirements. 67 | 68 | Notes: we generate development requirements after the main as this step requires 69 | the main requirements.txt to be up-to-date first. See **gen_requirements.py and 70 | gen_requirements_dev.py** --help for details. 71 | 72 | Note: this does NOT hash requirements for now. 73 | 74 | Note: Be aware that if you are using "conditional" requirements (e.g. only for 75 | OS or Python versions) in setup.py/setp.cfg/requirements.txt as these are NOT 76 | yet supported. 77 | 78 | 79 | Populate a thirdparty directory with wheels, sources, .ABOUT and license files 80 | ------------------------------------------------------------------------------ 81 | 82 | Scripts 83 | ~~~~~~~ 84 | 85 | * **fetch_thirdparty.py** will fetch package wheels, source sdist tarballs 86 | and their ABOUT, LICENSE and NOTICE files to populate a local directory from 87 | a list of PyPI simple URLs (typically PyPI.org proper and our self-hosted PyPI) 88 | using pip requirements file(s), specifiers or pre-existing packages files. 89 | Fetch wheels for specific python version and operating system combinations. 90 | 91 | * **check_thirdparty.py** will check a thirdparty directory for errors. 92 | 93 | 94 | Upgrade virtualenv app 95 | ---------------------- 96 | 97 | The bundled virtualenv.pyz has to be upgraded by hand and is stored under 98 | etc/thirdparty 99 | 100 | * Fetch https://github.com/pypa/get-virtualenv/raw//public/virtualenv.pyz 101 | for instance https://github.com/pypa/get-virtualenv/raw/20.2.2/public/virtualenv.pyz 102 | and save to thirdparty and update the ABOUT and LICENSE files as needed. 103 | 104 | * This virtualenv app contains also bundled pip, wheel and setuptools that are 105 | essential for the installation to work. 106 | 107 | 108 | Other files 109 | =========== 110 | 111 | The other files and scripts are test, support and utility modules used by the 112 | main scripts documented here. 113 | -------------------------------------------------------------------------------- /etc/scripts/check_thirdparty.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) nexB Inc. and others. All rights reserved. 5 | # ScanCode is a trademark of nexB Inc. 6 | # SPDX-License-Identifier: Apache-2.0 7 | # See http://www.apache.org/licenses/LICENSE-2.0 for the license text. 8 | # See https://github.com/aboutcode-org/skeleton for support or download. 9 | # See https://aboutcode.org for more information about nexB OSS projects. 10 | # 11 | import click 12 | 13 | import utils_thirdparty 14 | 15 | 16 | @click.command() 17 | @click.option( 18 | "-d", 19 | "--dest", 20 | type=click.Path(exists=True, readable=True, 21 | path_type=str, file_okay=False), 22 | required=True, 23 | help="Path to the thirdparty directory to check.", 24 | ) 25 | @click.option( 26 | "-w", 27 | "--wheels", 28 | is_flag=True, 29 | help="Check missing wheels.", 30 | ) 31 | @click.option( 32 | "-s", 33 | "--sdists", 34 | is_flag=True, 35 | help="Check missing source sdists tarballs.", 36 | ) 37 | @click.help_option("-h", "--help") 38 | def check_thirdparty_dir( 39 | dest, 40 | wheels, 41 | sdists, 42 | ): 43 | """ 44 | Check a thirdparty directory for problems and print these on screen. 45 | """ 46 | # check for problems 47 | print(f"==> CHECK FOR PROBLEMS") 48 | utils_thirdparty.find_problems( 49 | dest_dir=dest, 50 | report_missing_sources=sdists, 51 | report_missing_wheels=wheels, 52 | ) 53 | 54 | 55 | if __name__ == "__main__": 56 | check_thirdparty_dir() 57 | -------------------------------------------------------------------------------- /etc/scripts/gen_pypi_simple.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: gen_pypi_simple.py 2 | name: gen_pypi_simple.py 3 | license_expression: bsd-2-clause-views and mit 4 | copyright: Copyright (c) nexB Inc. 5 | Copyright (c) 2010 David Wolever 6 | Copyright (c) The pip developers 7 | notes: Originally from https://github.com/wolever/pip2pi and modified extensivley 8 | Also partially derived from pip code 9 | -------------------------------------------------------------------------------- /etc/scripts/gen_pypi_simple.py.NOTICE: -------------------------------------------------------------------------------- 1 | SPDX-License-Identifier: BSD-2-Clause-Views AND mit 2 | 3 | Copyright (c) nexB Inc. 4 | Copyright (c) 2010 David Wolever 5 | Copyright (c) The pip developers 6 | 7 | 8 | Original code: copyright 2010 David Wolever . All rights reserved. 9 | 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | 13 | 1. Redistributions of source code must retain the above copyright notice, 14 | this list of conditions and the following disclaimer. 15 | 16 | 2. Redistributions in binary form must reproduce the above copyright notice, 17 | this list of conditions and the following disclaimer in the documentation 18 | and/or other materials provided with the distribution. 19 | 20 | THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR 21 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 23 | EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 24 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 28 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | The views and conclusions contained in the software and documentation are those 32 | of the authors and should not be interpreted as representing official policies, 33 | either expressed or implied, of David Wolever. 34 | 35 | 36 | Original code: Copyright (c) 2008-2020 The pip developers 37 | 38 | Permission is hereby granted, free of charge, to any person obtaining 39 | a copy of this software and associated documentation files (the 40 | "Software"), to deal in the Software without restriction, including 41 | without limitation the rights to use, copy, modify, merge, publish, 42 | distribute, sublicense, and/or sell copies of the Software, and to 43 | permit persons to whom the Software is furnished to do so, subject to 44 | the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be 47 | included in all copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 50 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 51 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 52 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 53 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 54 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 55 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 56 | 57 | -------------------------------------------------------------------------------- /etc/scripts/gen_requirements.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) nexB Inc. and others. All rights reserved. 5 | # ScanCode is a trademark of nexB Inc. 6 | # SPDX-License-Identifier: Apache-2.0 7 | # See http://www.apache.org/licenses/LICENSE-2.0 for the license text. 8 | # See https://github.com/aboutcode-org/skeleton for support or download. 9 | # See https://aboutcode.org for more information about nexB OSS projects. 10 | # 11 | import argparse 12 | import pathlib 13 | 14 | import utils_requirements 15 | 16 | """ 17 | Utilities to manage requirements files. 18 | NOTE: this should use ONLY the standard library and not import anything else 19 | because this is used for boostrapping with no requirements installed. 20 | """ 21 | 22 | 23 | def gen_requirements(): 24 | description = """ 25 | Create or replace the `--requirements-file` file FILE requirements file with all 26 | locally installed Python packages.all Python packages found installed in `--site-packages-dir` 27 | """ 28 | parser = argparse.ArgumentParser(description=description) 29 | 30 | parser.add_argument( 31 | "-s", 32 | "--site-packages-dir", 33 | dest="site_packages_dir", 34 | type=pathlib.Path, 35 | required=True, 36 | metavar="DIR", 37 | help="Path to the 'site-packages' directory where wheels are installed such as lib/python3.6/site-packages", 38 | ) 39 | parser.add_argument( 40 | "-r", 41 | "--requirements-file", 42 | type=pathlib.Path, 43 | metavar="FILE", 44 | default="requirements.txt", 45 | help="Path to the requirements file to update or create.", 46 | ) 47 | 48 | args = parser.parse_args() 49 | 50 | utils_requirements.lock_requirements( 51 | site_packages_dir=args.site_packages_dir, 52 | requirements_file=args.requirements_file, 53 | ) 54 | 55 | 56 | if __name__ == "__main__": 57 | gen_requirements() 58 | -------------------------------------------------------------------------------- /etc/scripts/gen_requirements_dev.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) nexB Inc. and others. All rights reserved. 5 | # ScanCode is a trademark of nexB Inc. 6 | # SPDX-License-Identifier: Apache-2.0 7 | # See http://www.apache.org/licenses/LICENSE-2.0 for the license text. 8 | # See https://github.com/aboutcode-org/skeleton for support or download. 9 | # See https://aboutcode.org for more information about nexB OSS projects. 10 | # 11 | import argparse 12 | import pathlib 13 | 14 | import utils_requirements 15 | 16 | """ 17 | Utilities to manage requirements files. 18 | NOTE: this should use ONLY the standard library and not import anything else 19 | because this is used for boostrapping with no requirements installed. 20 | """ 21 | 22 | 23 | def gen_dev_requirements(): 24 | description = """ 25 | Create or overwrite the `--dev-requirements-file` pip requirements FILE with 26 | all Python packages found installed in `--site-packages-dir`. Exclude 27 | package names also listed in the --main-requirements-file pip requirements 28 | FILE (that are assume to the production requirements and therefore to always 29 | be present in addition to the development requirements). 30 | """ 31 | parser = argparse.ArgumentParser(description=description) 32 | 33 | parser.add_argument( 34 | "-s", 35 | "--site-packages-dir", 36 | type=pathlib.Path, 37 | required=True, 38 | metavar="DIR", 39 | help='Path to the "site-packages" directory where wheels are installed such as lib/python3.6/site-packages', 40 | ) 41 | parser.add_argument( 42 | "-d", 43 | "--dev-requirements-file", 44 | type=pathlib.Path, 45 | metavar="FILE", 46 | default="requirements-dev.txt", 47 | help="Path to the dev requirements file to update or create.", 48 | ) 49 | parser.add_argument( 50 | "-r", 51 | "--main-requirements-file", 52 | type=pathlib.Path, 53 | default="requirements.txt", 54 | metavar="FILE", 55 | help="Path to the main requirements file. Its requirements will be excluded " 56 | "from the generated dev requirements.", 57 | ) 58 | args = parser.parse_args() 59 | 60 | utils_requirements.lock_dev_requirements( 61 | dev_requirements_file=args.dev_requirements_file, 62 | main_requirements_file=args.main_requirements_file, 63 | site_packages_dir=args.site_packages_dir, 64 | ) 65 | 66 | 67 | if __name__ == "__main__": 68 | gen_dev_requirements() 69 | -------------------------------------------------------------------------------- /etc/scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | aboutcode_toolkit 2 | attrs 3 | commoncode 4 | click 5 | requests 6 | saneyaml 7 | pip 8 | setuptools 9 | twine 10 | wheel 11 | build 12 | packvers 13 | -------------------------------------------------------------------------------- /etc/scripts/test_utils_pip_compatibility_tags.py: -------------------------------------------------------------------------------- 1 | """Generate and work with PEP 425 Compatibility Tags. 2 | 3 | copied from pip-20.3.1 pip/tests/unit/test_utils_compatibility_tags.py 4 | download_url: https://raw.githubusercontent.com/pypa/pip/20.3.1/tests/unit/test_utils_compatibility_tags.py 5 | 6 | Copyright (c) 2008-2020 The pip developers (see AUTHORS.txt file) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining 9 | a copy of this software and associated documentation files (the 10 | "Software"), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | """ 27 | 28 | from unittest.mock import patch 29 | import sysconfig 30 | 31 | import pytest 32 | 33 | import utils_pip_compatibility_tags 34 | 35 | 36 | @pytest.mark.parametrize( 37 | "version_info, expected", 38 | [ 39 | ((2,), "2"), 40 | ((2, 8), "28"), 41 | ((3,), "3"), 42 | ((3, 6), "36"), 43 | # Test a tuple of length 3. 44 | ((3, 6, 5), "36"), 45 | # Test a 2-digit minor version. 46 | ((3, 10), "310"), 47 | ], 48 | ) 49 | def test_version_info_to_nodot(version_info, expected): 50 | actual = utils_pip_compatibility_tags.version_info_to_nodot(version_info) 51 | assert actual == expected 52 | 53 | 54 | class Testcompatibility_tags(object): 55 | def mock_get_config_var(self, **kwd): 56 | """ 57 | Patch sysconfig.get_config_var for arbitrary keys. 58 | """ 59 | get_config_var = sysconfig.get_config_var 60 | 61 | def _mock_get_config_var(var): 62 | if var in kwd: 63 | return kwd[var] 64 | return get_config_var(var) 65 | 66 | return _mock_get_config_var 67 | 68 | def test_no_hyphen_tag(self): 69 | """ 70 | Test that no tag contains a hyphen. 71 | """ 72 | import pip._internal.utils.compatibility_tags 73 | 74 | mock_gcf = self.mock_get_config_var(SOABI="cpython-35m-darwin") 75 | 76 | with patch("sysconfig.get_config_var", mock_gcf): 77 | supported = pip._internal.utils.compatibility_tags.get_supported() 78 | 79 | for tag in supported: 80 | assert "-" not in tag.interpreter 81 | assert "-" not in tag.abi 82 | assert "-" not in tag.platform 83 | 84 | 85 | class TestManylinux2010Tags(object): 86 | @pytest.mark.parametrize( 87 | "manylinux2010,manylinux1", 88 | [ 89 | ("manylinux2010_x86_64", "manylinux1_x86_64"), 90 | ("manylinux2010_i686", "manylinux1_i686"), 91 | ], 92 | ) 93 | def test_manylinux2010_implies_manylinux1(self, manylinux2010, manylinux1): 94 | """ 95 | Specifying manylinux2010 implies manylinux1. 96 | """ 97 | groups = {} 98 | supported = utils_pip_compatibility_tags.get_supported(platforms=[manylinux2010]) 99 | for tag in supported: 100 | groups.setdefault((tag.interpreter, tag.abi), []).append(tag.platform) 101 | 102 | for arches in groups.values(): 103 | if arches == ["any"]: 104 | continue 105 | assert arches[:2] == [manylinux2010, manylinux1] 106 | 107 | 108 | class TestManylinux2014Tags(object): 109 | @pytest.mark.parametrize( 110 | "manylinuxA,manylinuxB", 111 | [ 112 | ("manylinux2014_x86_64", ["manylinux2010_x86_64", "manylinux1_x86_64"]), 113 | ("manylinux2014_i686", ["manylinux2010_i686", "manylinux1_i686"]), 114 | ], 115 | ) 116 | def test_manylinuxA_implies_manylinuxB(self, manylinuxA, manylinuxB): 117 | """ 118 | Specifying manylinux2014 implies manylinux2010/manylinux1. 119 | """ 120 | groups = {} 121 | supported = utils_pip_compatibility_tags.get_supported(platforms=[manylinuxA]) 122 | for tag in supported: 123 | groups.setdefault((tag.interpreter, tag.abi), []).append(tag.platform) 124 | 125 | expected_arches = [manylinuxA] 126 | expected_arches.extend(manylinuxB) 127 | for arches in groups.values(): 128 | if arches == ["any"]: 129 | continue 130 | assert arches[:3] == expected_arches 131 | -------------------------------------------------------------------------------- /etc/scripts/test_utils_pip_compatibility_tags.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_utils_pip_compatibility_tags.py 2 | 3 | type: github 4 | namespace: pypa 5 | name: pip 6 | version: 20.3.1 7 | subpath: tests/unit/test_utils_compatibility_tags.py 8 | 9 | package_url: pkg:github/pypa/pip@20.3.1#tests/unit/test_utils_compatibility_tags.py 10 | 11 | download_url: https://raw.githubusercontent.com/pypa/pip/20.3.1/tests/unit/test_utils_compatibility_tags.py 12 | copyright: Copyright (c) 2008-2020 The pip developers (see AUTHORS.txt file) 13 | license_expression: mit 14 | notes: subset copied from pip for tag handling 15 | -------------------------------------------------------------------------------- /etc/scripts/test_utils_pypi_supported_tags.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); 2 | # you may not use this file except in compliance with the License. 3 | # You may obtain a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | 13 | import pytest 14 | 15 | from utils_pypi_supported_tags import validate_platforms_for_pypi 16 | 17 | """ 18 | Wheel platform checking tests 19 | 20 | Copied and modified on 2020-12-24 from 21 | https://github.com/pypa/warehouse/blob/37a83dd342d9e3b3ab4f6bde47ca30e6883e2c4d/tests/unit/forklift/test_legacy.py 22 | """ 23 | 24 | 25 | def validate_wheel_filename_for_pypi(filename): 26 | """ 27 | Validate if the filename is a PyPI/warehouse-uploadable wheel file name 28 | with supported platform tags. Return a list of unsupported platform tags or 29 | an empty list if all tags are supported. 30 | """ 31 | from utils_thirdparty import Wheel 32 | 33 | wheel = Wheel.from_filename(filename) 34 | return validate_platforms_for_pypi(wheel.platforms) 35 | 36 | 37 | @pytest.mark.parametrize( 38 | "plat", 39 | [ 40 | "any", 41 | "win32", 42 | "win_amd64", 43 | "win_ia64", 44 | "manylinux1_i686", 45 | "manylinux1_x86_64", 46 | "manylinux2010_i686", 47 | "manylinux2010_x86_64", 48 | "manylinux2014_i686", 49 | "manylinux2014_x86_64", 50 | "manylinux2014_aarch64", 51 | "manylinux2014_armv7l", 52 | "manylinux2014_ppc64", 53 | "manylinux2014_ppc64le", 54 | "manylinux2014_s390x", 55 | "manylinux_2_5_i686", 56 | "manylinux_2_12_x86_64", 57 | "manylinux_2_17_aarch64", 58 | "manylinux_2_17_armv7l", 59 | "manylinux_2_17_ppc64", 60 | "manylinux_2_17_ppc64le", 61 | "manylinux_3_0_s390x", 62 | "macosx_10_6_intel", 63 | "macosx_10_13_x86_64", 64 | "macosx_11_0_x86_64", 65 | "macosx_10_15_arm64", 66 | "macosx_11_10_universal2", 67 | # A real tag used by e.g. some numpy wheels 68 | ( 69 | "macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64." 70 | "macosx_10_10_intel.macosx_10_10_x86_64" 71 | ), 72 | ], 73 | ) 74 | def test_is_valid_pypi_wheel_return_true_for_supported_wheel(plat): 75 | filename = f"foo-1.2.3-cp34-none-{plat}.whl" 76 | assert not validate_wheel_filename_for_pypi(filename) 77 | 78 | 79 | @pytest.mark.parametrize( 80 | "plat", 81 | [ 82 | "linux_x86_64", 83 | "linux_x86_64.win32", 84 | "macosx_9_2_x86_64", 85 | "macosx_12_2_arm64", 86 | "macosx_10_15_amd64", 87 | ], 88 | ) 89 | def test_is_valid_pypi_wheel_raise_exception_for_aunsupported_wheel(plat): 90 | filename = f"foo-1.2.3-cp34-none-{plat}.whl" 91 | invalid = validate_wheel_filename_for_pypi(filename) 92 | assert invalid 93 | -------------------------------------------------------------------------------- /etc/scripts/test_utils_pypi_supported_tags.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_utils_pypi_supported_tags.py 2 | 3 | type: github 4 | namespace: pypa 5 | name: warehouse 6 | version: 37a83dd342d9e3b3ab4f6bde47ca30e6883e2c4d 7 | subpath: tests/unit/forklift/test_legacy.py 8 | 9 | package_url: pkg:github/pypa/warehouse@37a83dd342d9e3b3ab4f6bde47ca30e6883e2c4d#tests/unit/forklift/test_legacy.py 10 | 11 | download_url: https://github.com/pypa/warehouse/blob/37a83dd342d9e3b3ab4f6bde47ca30e6883e2c4d/tests/unit/forklift/test_legacy.py 12 | copyright: Copyright (c) The warehouse developers 13 | homepage_url: https://warehouse.readthedocs.io 14 | license_expression: apache-2.0 15 | notes: Test for wheel platform checking copied and heavily modified on 16 | 2020-12-24 from warehouse. This contains the basic functions to check if a 17 | wheel file name is would be supported for uploading to PyPI. 18 | -------------------------------------------------------------------------------- /etc/scripts/utils_pip_compatibility_tags.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: utils_pip_compatibility_tags.py 2 | 3 | type: github 4 | namespace: pypa 5 | name: pip 6 | version: 20.3.1 7 | subpath: src/pip/_internal/utils/compatibility_tags.py 8 | 9 | package_url: pkg:github/pypa/pip@20.3.1#src/pip/_internal/utils/compatibility_tags.py 10 | 11 | download_url: https://github.com/pypa/pip/blob/20.3.1/src/pip/_internal/utils/compatibility_tags.py 12 | copyright: Copyright (c) 2008-2020 The pip developers (see AUTHORS.txt file) 13 | license_expression: mit 14 | notes: subset copied from pip for tag handling -------------------------------------------------------------------------------- /etc/scripts/utils_pypi_supported_tags.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); 2 | # you may not use this file except in compliance with the License. 3 | # You may obtain a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | 13 | import re 14 | 15 | """ 16 | Wheel platform checking 17 | 18 | Copied and modified on 2020-12-24 from 19 | https://github.com/pypa/warehouse/blob/37a83dd342d9e3b3ab4f6bde47ca30e6883e2c4d/warehouse/forklift/legacy.py 20 | 21 | This contains the basic functions to check if a wheel file name is would be 22 | supported for uploading to PyPI. 23 | """ 24 | 25 | # These platforms can be handled by a simple static list: 26 | _allowed_platforms = { 27 | "any", 28 | "win32", 29 | "win_amd64", 30 | "win_ia64", 31 | "manylinux1_x86_64", 32 | "manylinux1_i686", 33 | "manylinux2010_x86_64", 34 | "manylinux2010_i686", 35 | "manylinux2014_x86_64", 36 | "manylinux2014_i686", 37 | "manylinux2014_aarch64", 38 | "manylinux2014_armv7l", 39 | "manylinux2014_ppc64", 40 | "manylinux2014_ppc64le", 41 | "manylinux2014_s390x", 42 | "linux_armv6l", 43 | "linux_armv7l", 44 | } 45 | # macosx is a little more complicated: 46 | _macosx_platform_re = re.compile(r"macosx_(?P\d+)_(\d+)_(?P.*)") 47 | _macosx_arches = { 48 | "ppc", 49 | "ppc64", 50 | "i386", 51 | "x86_64", 52 | "arm64", 53 | "intel", 54 | "fat", 55 | "fat32", 56 | "fat64", 57 | "universal", 58 | "universal2", 59 | } 60 | _macosx_major_versions = { 61 | "10", 62 | "11", 63 | } 64 | 65 | # manylinux pep600 is a little more complicated: 66 | _manylinux_platform_re = re.compile(r"manylinux_(\d+)_(\d+)_(?P.*)") 67 | _manylinux_arches = { 68 | "x86_64", 69 | "i686", 70 | "aarch64", 71 | "armv7l", 72 | "ppc64", 73 | "ppc64le", 74 | "s390x", 75 | } 76 | 77 | 78 | def is_supported_platform_tag(platform_tag): 79 | """ 80 | Return True if the ``platform_tag`` is supported on PyPI. 81 | """ 82 | if platform_tag in _allowed_platforms: 83 | return True 84 | m = _macosx_platform_re.match(platform_tag) 85 | if m and m.group("major") in _macosx_major_versions and m.group("arch") in _macosx_arches: 86 | return True 87 | m = _manylinux_platform_re.match(platform_tag) 88 | if m and m.group("arch") in _manylinux_arches: 89 | return True 90 | return False 91 | 92 | 93 | def validate_platforms_for_pypi(platforms): 94 | """ 95 | Validate if the wheel platforms are supported platform tags on Pypi. Return 96 | a list of unsupported platform tags or an empty list if all tags are 97 | supported. 98 | """ 99 | 100 | # Check that if it's a binary wheel, it's on a supported platform 101 | invalid_tags = [] 102 | for plat in platforms: 103 | if not is_supported_platform_tag(plat): 104 | invalid_tags.append(plat) 105 | return invalid_tags 106 | -------------------------------------------------------------------------------- /etc/scripts/utils_pypi_supported_tags.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: utils_pypi_supported_tags.py 2 | 3 | type: github 4 | namespace: pypa 5 | name: warehouse 6 | version: 37a83dd342d9e3b3ab4f6bde47ca30e6883e2c4d 7 | subpath: warehouse/forklift/legacy.py 8 | 9 | package_url: pkg:github/pypa/warehouse@37a83dd342d9e3b3ab4f6bde47ca30e6883e2c4d#warehouse/forklift/legacy.py 10 | 11 | download_url: https://github.com/pypa/warehouse/blob/37a83dd342d9e3b3ab4f6bde47ca30e6883e2c4d/warehouse/forklift/legacy.py 12 | copyright: Copyright (c) The warehouse developers 13 | homepage_url: https://warehouse.readthedocs.io 14 | license_expression: apache-2.0 15 | notes: Wheel platform checking copied and heavily modified on 2020-12-24 from 16 | warehouse. This contains the basic functions to check if a wheel file name is 17 | would be supported for uploading to PyPI. 18 | -------------------------------------------------------------------------------- /etc/scripts/utils_thirdparty.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: utils_thirdparty.py 2 | package_url: pkg:github.com/pypa/pip/@20.3.1#src/pip/_internal/models/wheel.py 3 | type: github 4 | namespace: pypa 5 | name: pip 6 | version: 20.3.1 7 | subpath: src/pip/_internal/models/wheel.py 8 | 9 | download_url: https://github.com/pypa/pip/blob/20.3.1/src/pip/_internal/models/wheel.py 10 | copyright: Copyright (c) 2008-2020 The pip developers (see AUTHORS.txt file) 11 | license_expression: mit 12 | notes: copied from pip-20.3.1 pip/_internal/models/wheel.py 13 | The models code has been heavily inspired from the ISC-licensed packaging-dists 14 | https://github.com/uranusjr/packaging-dists by Tzu-ping Chung 15 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1658380158, 6 | "narHash": "sha256-DBunkegKWlxPZiOcw3/SNIFg93amkdGIy2g0y/jDpHg=", 7 | "owner": "nixos", 8 | "repo": "nixpkgs", 9 | "rev": "a65b5b3f5504b8b89c196aba733bdf2b0bd13c16", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "nixos", 14 | "ref": "nixos-unstable", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "root": { 20 | "inputs": { 21 | "nixpkgs": "nixpkgs" 22 | } 23 | } 24 | }, 25 | "root": "root", 26 | "version": 7 27 | } 28 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Parse and compare all the package versions and all the ranges. From debian, npm, pypi, ruby and more. Process all the version range specs and expressions."; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; 6 | }; 7 | 8 | outputs = { self, nixpkgs }: ({ 9 | overlays.default = import ./overlay.nix; 10 | }) // ( 11 | let 12 | supportedSystems = [ "aarch64-darwin" "aarch64-linux" "x86_64-darwin" "x86_64-linux" ]; 13 | forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system); 14 | nixpkgsFor = forAllSystems (system: self.overlays.default null nixpkgs.legacyPackages.${system}); 15 | in 16 | { 17 | packages = forAllSystems (system: rec { 18 | python3Packages = { 19 | inherit (nixpkgsFor.${system}.python3Packages) univers; 20 | }; 21 | default = python3Packages.univers; 22 | }); 23 | } 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /mit.LICENSE: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining 2 | a copy of this software and associated documentation files (the 3 | "Software"), to deal in the Software without restriction, including 4 | without limitation the rights to use, copy, modify, merge, publish, 5 | distribute, sublicense, and/or sell copies of the Software, and to 6 | permit persons to whom the Software is furnished to do so, subject to 7 | the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be 10 | included in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 13 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 14 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 15 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 16 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 17 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 18 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /overlay.nix: -------------------------------------------------------------------------------- 1 | final: prev: rec { 2 | python3 = prev.python3.override { 3 | packageOverrides = final: prev: 4 | { 5 | univers = python3Packages.callPackage 6 | ({ lib 7 | , buildPythonPackage 8 | , git 9 | , setuptools-scm 10 | , attrs 11 | , packaging 12 | , pyparsing 13 | , semantic-version 14 | , semver 15 | , black 16 | , commoncode 17 | , pytestCheckHook 18 | , saneyaml 19 | }: buildPythonPackage rec { 20 | name = "univers"; 21 | 22 | src = ./.; 23 | 24 | nativeBuildInputs = [ git setuptools-scm ]; 25 | propagatedBuildInputs = [ attrs packaging pyparsing semantic-version semver ]; 26 | checkInputs = [ black commoncode pytestCheckHook saneyaml ]; 27 | 28 | dontConfigure = true; # ./configure tries to setup virtualenv and downloads dependencies 29 | 30 | pythonImportsCheck = [ "univers" ]; 31 | 32 | meta = with lib; { 33 | description = "Library for parsing version ranges and expressions"; 34 | homepage = "https://github.com/aboutcode-org/univers"; 35 | license = with licenses; [ asl20 bsd3 mit ]; 36 | }; 37 | }) 38 | { }; 39 | }; 40 | }; 41 | python3Packages = prev.recurseIntoAttrs python3.pkgs; 42 | } 43 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools >= 50", "wheel", "setuptools_scm[toml] >= 6"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [tool.setuptools_scm] 6 | # this is used populated when creating a git archive 7 | # and when there is .git dir and/or there is no git installed 8 | fallback_version = "9999.50f83d1a-2025-06-11" 9 | 10 | [tool.pytest.ini_options] 11 | norecursedirs = [ 12 | ".git", 13 | "bin", 14 | "dist", 15 | "build", 16 | "_build", 17 | "dist", 18 | "etc", 19 | "local", 20 | "ci", 21 | "docs", 22 | "man", 23 | "share", 24 | "samples", 25 | ".cache", 26 | ".settings", 27 | "Include", 28 | "include", 29 | "Lib", 30 | "lib", 31 | "lib64", 32 | "Lib64", 33 | "Scripts", 34 | "thirdparty", 35 | "tmp", 36 | "venv", 37 | "tests/data", 38 | ".eggs", 39 | "src/*/data", 40 | "tests/*/data" 41 | ] 42 | 43 | python_files = "*.py" 44 | 45 | python_classes = "Test" 46 | python_functions = "test" 47 | 48 | addopts = [ 49 | "-rfExXw", 50 | "--strict-markers", 51 | "--doctest-modules" 52 | ] 53 | 54 | [tool.isort] 55 | profile = "black" 56 | line_length = 100 57 | force_single_line = true 58 | skip_gitignore = true 59 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | execnet==1.9.0 2 | importlib-metadata==4.8.1 3 | iniconfig==1.1.1 4 | pluggy==1.0.0 5 | py==1.11.0 6 | pytest==7.2.0 7 | pytest-forked==1.4.0 8 | pytest-xdist==3.2.0 9 | toml==0.10.2 10 | typing-extensions==3.10.0.2 11 | zipp==3.6.0 12 | black==22.3.0 13 | typed-ast==1.4.3 14 | pathspec==0.9.0 -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | attrs==21.2.0 2 | packaging==21.0 3 | pyparsing==2.4.7 4 | semantic-version==2.8.5 5 | semver==2.13.0 6 | isort==5.10.1 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = univers 3 | license = Apache-2.0 AND BSD-3-Clause AND MIT 4 | 5 | # description must be on ONE line https://github.com/pypa/setuptools/issues/1390 6 | description = A mostly universal library to parse and compare software package versions and version ranges. A companion to Package URLs. 7 | long_description = file:README.rst 8 | long_description_content_type = text/x-rst 9 | url = https://github.com/aboutcode-org/univers 10 | 11 | author = Shivam Sandbhor, nexB. Inc. and others 12 | author_email = info@aboutcode.org 13 | 14 | classifiers = 15 | Development Status :: 5 - Production/Stable 16 | Intended Audience :: Developers 17 | Programming Language :: Python :: 3 18 | Programming Language :: Python :: 3 :: Only 19 | Topic :: Software Development 20 | Topic :: Utilities 21 | keywords = 22 | semver 23 | utilities 24 | version 25 | release 26 | version range 27 | package URL 28 | purl 29 | arch 30 | pacman 31 | pypi 32 | rpm 33 | gentoo 34 | ebuild 35 | maven 36 | debian 37 | rubygems 38 | 39 | license_files = 40 | apache-2.0.LICENSE 41 | bsd-new.LICENSE 42 | mit.LICENSE 43 | NOTICE 44 | AUTHORS.rst 45 | CHANGELOG.rst 46 | README.rst 47 | CODE_OF_CONDUCT.rst 48 | 49 | [options] 50 | package_dir = 51 | =src 52 | packages = find: 53 | include_package_data = true 54 | zip_safe = false 55 | 56 | setup_requires = setuptools_scm[toml] >= 4 57 | 58 | python_requires = >=3.8 59 | 60 | install_requires = 61 | attrs 62 | packaging 63 | semantic-version 64 | semver 65 | 66 | 67 | [options.packages.find] 68 | where = src 69 | 70 | 71 | [options.extras_require] 72 | testing = 73 | pytest >= 6, != 7.0.0 74 | pytest-xdist >= 2 75 | aboutcode-toolkit >= 7.0.2 76 | pycodestyle >= 2.8.0 77 | twine 78 | black 79 | commoncode 80 | isort>=5.10.1 81 | 82 | docs = 83 | Sphinx>=5.0.2 84 | sphinx-rtd-theme>=1.0.0 85 | sphinx-reredirects >= 0.1.2 86 | doc8>=0.11.2 87 | sphinx-autobuild 88 | sphinx-rtd-dark-mode>=1.3.0 89 | sphinx-copybutton 90 | 91 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import setuptools 4 | 5 | if __name__ == "__main__": 6 | setuptools.setup() 7 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | (import (fetchTarball https://github.com/edolstra/flake-compat/archive/b4a34015c698c7793d592d66adbab377907a2be8.tar.gz) { 2 | src = builtins.fetchGit ./.; 3 | }).shellNix 4 | -------------------------------------------------------------------------------- /src/univers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aboutcode-org/univers/50f83d1a015153398315e46e55fa9e750c28a63f/src/univers/__init__.py -------------------------------------------------------------------------------- /src/univers/arch.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) Christoph Reiter 3 | # SPDX-License-Identifier: MIT 4 | # Version utility extracted from msys2 https://github.com/msys2/msys2-web/ 5 | # and further stripped down. 6 | # 7 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 8 | 9 | import re 10 | from itertools import zip_longest 11 | from typing import Dict 12 | from typing import List 13 | from typing import Optional 14 | from typing import Set 15 | from typing import Tuple 16 | 17 | from univers.utils import cmp 18 | 19 | 20 | def vercmp(v1: str, v2: str) -> int: 21 | def split(v: str) -> Tuple[str, str, Optional[str]]: 22 | if ":" in v: 23 | e, v = v.split(":", 1) 24 | else: 25 | e, v = ("0", v) 26 | 27 | r: Optional[str] = None 28 | if "-" in v: 29 | v, r = v.rsplit("-", 1) 30 | else: 31 | v, r = (v, None) 32 | 33 | return (e, v, r) 34 | 35 | digit, alpha, other = range(3) 36 | 37 | def get_type(c: str) -> int: 38 | assert c 39 | if c.isdigit(): 40 | return digit 41 | elif c.isalpha(): 42 | return alpha 43 | else: 44 | return other 45 | 46 | def parse(v: str) -> List[str]: 47 | parts: List[str] = [] 48 | current = "" 49 | for c in v: 50 | if not current: 51 | current += c 52 | else: 53 | if get_type(c) == get_type(current): 54 | current += c 55 | else: 56 | parts.append(current) 57 | current = c 58 | 59 | if current: 60 | parts.append(current) 61 | 62 | return parts 63 | 64 | def rpmvercmp(v1: str, v2: str) -> int: 65 | for p1, p2 in zip_longest(parse(v1), parse(v2), fillvalue=None): 66 | if p1 is None: 67 | if get_type(p2) == alpha: 68 | return 1 69 | return -1 70 | elif p2 is None: 71 | if get_type(p1) == alpha: 72 | return -1 73 | return 1 74 | 75 | t1 = get_type(p1) 76 | t2 = get_type(p2) 77 | if t1 != t2: 78 | if t1 == digit: 79 | return 1 80 | elif t2 == digit: 81 | return -1 82 | elif t1 == other: 83 | return 1 84 | elif t2 == other: 85 | return -1 86 | elif t1 == other: 87 | ret = cmp(len(p1), len(p2)) 88 | if ret != 0: 89 | return ret 90 | elif t1 == digit: 91 | ret = cmp(int(p1), int(p2)) 92 | if ret != 0: 93 | return ret 94 | elif t1 == alpha: 95 | ret = cmp(p1, p2) 96 | if ret != 0: 97 | return ret 98 | 99 | return 0 100 | 101 | e1, v1, r1 = split(v1) 102 | e2, v2, r2 = split(v2) 103 | 104 | ret = rpmvercmp(e1, e2) 105 | if ret == 0: 106 | ret = rpmvercmp(v1, v2) 107 | if ret == 0 and r1 is not None and r2 is not None: 108 | ret = rpmvercmp(r1, r2) 109 | 110 | return ret 111 | 112 | 113 | def extract_upstream_version(version: str) -> str: 114 | return version.rsplit("-")[0].split("+", 1)[0].split("~", 1)[-1].split(":", 1)[-1] 115 | 116 | 117 | def strip_vcs(package_name: str) -> str: 118 | if package_name.endswith(("-cvs", "-svn", "-hg", "-darcs", "-bzr", "-git")): 119 | return package_name.rsplit("-", 1)[0] 120 | return package_name 121 | 122 | 123 | def arch_version_to_msys(v: str) -> str: 124 | return v.replace(":", "~") 125 | 126 | 127 | def version_is_newer_than(v1: str, v2: str) -> bool: 128 | return vercmp(v1, v2) == 1 129 | 130 | 131 | def split_depends(deps: List[str]) -> Dict[str, Set[str]]: 132 | r: Dict[str, Set[str]] = {} 133 | for d in deps: 134 | parts = re.split("([<>=]+)", d, 1) 135 | first = parts[0].strip() 136 | second = "".join(parts[1:]).strip() 137 | r.setdefault(first, set()).add(second) 138 | return r 139 | 140 | 141 | def split_optdepends(deps: List[str]) -> Dict[str, Set[str]]: 142 | r: Dict[str, Set[str]] = {} 143 | for d in deps: 144 | if ":" in d: 145 | a, b = d.split(":", 1) 146 | a, b = a.strip(), b.strip() 147 | else: 148 | a, b = d.strip(), "" 149 | e = r.setdefault(a, set()) 150 | if b: 151 | e.add(b) 152 | return r 153 | -------------------------------------------------------------------------------- /src/univers/arch.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: arch.py 2 | package_url: pkg:github/msys2/msys2-web@3ed2dde45a8761523b749e42c201a737c7613e6e 3 | copyright: | 4 | Copyright 2016-2020 Christoph Reiter 5 | 6 | license_expression: MIT 7 | homepage_url: https://github.com/msys2/msys2-web/ 8 | 9 | notes: | 10 | The version comparison utility is extracted from msys2 and further stripped down. 11 | 12 | notice_file: arch.py.NOTICE -------------------------------------------------------------------------------- /src/univers/arch.py.NOTICE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2017 Christoph Reiter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/univers/bsd-new.LICENSE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without modification, 2 | are permitted provided that the following conditions are met: 3 | 4 | Redistributions of source code must retain the above copyright notice, this list 5 | of conditions and the following disclaimer. 6 | 7 | Redistributions in binary form must reproduce the above copyright notice, this 8 | list of conditions and the following disclaimer in the documentation and/or 9 | other materials provided with the distribution. 10 | 11 | Neither the name of the ORGANIZATION nor the names of its contributors may be 12 | used to endorse or promote products derived from this software without specific 13 | prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 19 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 21 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 24 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/univers/conan/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aboutcode-org/univers/50f83d1a015153398315e46e55fa9e750c28a63f/src/univers/conan/__init__.py -------------------------------------------------------------------------------- /src/univers/conan/errors.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: errors.py 2 | package_url: pkg:pypi/conan@2.0.0 3 | copyright: | 4 | Copyright (c) 2019 JFrog LTD 5 | download_url: https://github.com/conan-io/conan/blob/release/2.0/conans/errors.py 6 | license_expression: MIT 7 | homepage_url: https://github.com/conan-io/conan 8 | notice_file: errors.py.NOTICE 9 | -------------------------------------------------------------------------------- /src/univers/conan/errors.py.NOTICE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 JFrog LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/univers/conan/version.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: version.py 2 | package_url: pkg:pypi/conan@2.0.0 3 | copyright: | 4 | Copyright (c) 2019 JFrog LTD 5 | download_url: https://github.com/conan-io/conan/blob/release/2.0/conans/model/version.py 6 | license_expression: MIT 7 | homepage_url: https://github.com/conan-io/conan 8 | notice_file: version.py.NOTICE 9 | -------------------------------------------------------------------------------- /src/univers/conan/version.py.NOTICE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 JFrog LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/univers/conan/version_range.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019 JFrog LTD 3 | # SPDX-License-Identifier: MIT 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | from collections import namedtuple 8 | 9 | from univers.conan.errors import ConanException 10 | from univers.versions import ConanVersion 11 | 12 | _Condition = namedtuple("_Condition", ["operator", "version"]) 13 | 14 | 15 | class _ConditionSet: 16 | def __init__(self, expression, prerelease): 17 | expressions = expression.split() 18 | self.prerelease = prerelease 19 | self.conditions = [] 20 | for e in expressions: 21 | e = e.strip() 22 | if e[-1] == "-": # Include pre-releases 23 | e = e[:-1] 24 | self.prerelease = True 25 | self.conditions.extend(self._parse_expression(e)) 26 | 27 | @staticmethod 28 | def _parse_expression(expression): 29 | if expression == "" or expression == "*": 30 | return [_Condition(">=", ConanVersion("0.0.0"))] 31 | 32 | operator = expression[0] 33 | if operator not in (">", "<", "^", "~", "="): 34 | operator = "=" 35 | index = 0 36 | else: 37 | index = 1 38 | if operator in (">", "<"): 39 | if expression[1] == "=": 40 | operator += "=" 41 | index = 2 42 | version = expression[index:] 43 | if version == "": 44 | raise ConanException(f"Error parsing version range {expression}") 45 | if operator == "~": # tilde minor 46 | v = ConanVersion(version) 47 | index = 1 if len(v.main) > 1 else 0 48 | return [_Condition(">=", v), _Condition("<", v.upper_bound(index))] 49 | elif operator == "^": # caret major 50 | v = ConanVersion(version) 51 | 52 | def first_non_zero(main): 53 | for i, m in enumerate(main): 54 | if m != 0: 55 | return i 56 | return len(main) 57 | 58 | initial_index = first_non_zero(v.main) 59 | return [_Condition(">=", v), _Condition("<", v.upper_bound(initial_index))] 60 | else: 61 | return [_Condition(operator, ConanVersion(version))] 62 | 63 | def valid(self, version): 64 | if version.pre: 65 | if not self.prerelease: 66 | return False 67 | for condition in self.conditions: 68 | if condition.operator == ">": 69 | if not version > condition.version: 70 | return False 71 | elif condition.operator == "<": 72 | if not version < condition.version: 73 | return False 74 | elif condition.operator == ">=": 75 | if not version >= condition.version: 76 | return False 77 | elif condition.operator == "<=": 78 | if not version <= condition.version: 79 | return False 80 | elif condition.operator == "=": 81 | if not version == condition.version: 82 | return False 83 | return True 84 | 85 | 86 | class VersionRange: 87 | def __init__(self, expression): 88 | self._expression = expression 89 | tokens = expression.split(",") 90 | prereleases = None 91 | for t in tokens[1:]: 92 | if "include_prerelease" in t: 93 | prereleases = True 94 | break 95 | version_expr = tokens[0] 96 | self.condition_sets = [] 97 | for alternative in version_expr.split("||"): 98 | self.condition_sets.append(_ConditionSet(alternative, prereleases)) 99 | 100 | def __str__(self): 101 | return self._expression 102 | 103 | def __contains__(self, version): 104 | assert isinstance(version, ConanVersion), type(version) 105 | for condition_set in self.condition_sets: 106 | if condition_set.valid(version): 107 | return True 108 | return False 109 | -------------------------------------------------------------------------------- /src/univers/conan/version_range.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: version_range.py 2 | package_url: pkg:pypi/conan@2.0.0 3 | copyright: | 4 | Copyright (c) 2019 JFrog LTD 5 | download_url: https://github.com/conan-io/conan/blob/release/2.0/conans/model/version_range.py 6 | license_expression: MIT 7 | homepage_url: https://github.com/conan-io/conan 8 | notice_file: version_range.py.NOTICE 9 | -------------------------------------------------------------------------------- /src/univers/conan/version_range.py.NOTICE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 JFrog LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/univers/debian.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: debian.py 2 | package_url: pkg:pypi/deb-pkg-tools@8.4 3 | copyright: | 4 | Copyright (C) Peter Odding 5 | 6 | license_expression: mit 7 | homepage_url: https://github.com/xolox/python-deb-pkg-tools 8 | 9 | notes: | 10 | This has been substantially modified and enhanced from the original 11 | python-deb-pkg-tools code to extract the version comparison code. 12 | based on https://raw.githubusercontent.com/xolox/python-deb-pkg-tools/a3d6ef1d82c6342b6a57876fc2360875e033f8f0/deb_pkg_tools/version/native.py 13 | and on https://raw.githubusercontent.com/xolox/python-deb-pkg-tools/a3d6ef1d82c6342b6a57876fc2360875e033f8f0/deb_pkg_tools/version/__init__.py 14 | merged and simplified in a single module and further modified to work with 15 | our class structure. 16 | 17 | notice_file: debian.py.NOTICE -------------------------------------------------------------------------------- /src/univers/debian.py.NOTICE: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Copyright (c) 2018 Peter Odding 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining 6 | # a copy of this software and associated documentation files (the 7 | # "Software"), to deal in the Software without restriction, including 8 | # without limitation the rights to use, copy, modify, merge, publish, 9 | # distribute, sublicense, and/or sell copies of the Software, and to 10 | # permit persons to whom the Software is furnished to do so, subject to 11 | # the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be 14 | # included in all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | # Debian packaging tools: Version comparison. 25 | # Original-Author: Peter Odding 26 | # Original-URL: https://github.com/xolox/python-deb-pkg-tools 27 | -------------------------------------------------------------------------------- /src/univers/gem.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: gem.py 2 | license_expression: apache-2.0 AND mit 3 | download_url: https://raw.githubusercontent.com/coi-gov-pl/puppeter/04e2a2008bd89a0429b734fdde6da83813688865/puppeter/domain/model/gemrequirement.py 4 | copyright: | 5 | Copyright (c) nexB, Inc. and others. 6 | Copyright (c) Center for Information Technology, http://coi.gov.pl 7 | Copyright (c) Chad Fowler, Rich Kilmer, Jim Weirich and others. 8 | Copyright (c) Engine Yard and Andre Arko, Facebook, Inc. and its affiliates. 9 | 10 | package_url: pkg:pypi/puppeter@0.8.3#src/domain/model/gemrequirement.py 11 | homepage_url: https://github.com/coi-gov-pl/puppeter 12 | notice_file: gem.py.NOTICE 13 | 14 | notes: This file started as a subset of the coi.gov/pl code modified for 15 | use in univers. The original Apache-licensed puppeteer code was used as a base, 16 | extracting the Ruby version handling code. That coi code was in turn 17 | originally based on MIT-licensed Rubygems code ported to Python. 18 | This has been substantially modified and enhanced to pass correctly all the 19 | upstream Rubygems tests and work with univers. This mixed code has been further 20 | updated from the Rubygems ruby code from 21 | https://github.com/rubygems/rubygems specifically 22 | lib/rubygems/version.rb and lib/rubygems/requirement.rb 23 | 24 | -------------------------------------------------------------------------------- /src/univers/gem.py.NOTICE: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Center for Information Technology 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. -------------------------------------------------------------------------------- /src/univers/gentoo.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: gentoo.py 2 | package_url: pkg:pypi/pkgcore@0.11.8 3 | copyright: | 4 | Copyright (c) 2006-2019, pkgcore contributors 5 | 6 | license_expression: BSD-3-Clause 7 | homepage_url: https://github.com/pkgcore/pkgcore/blob/master/src/pkgcore/ebuild/cpv.py 8 | 9 | notes: The version comparison utility is extracted from pkgcore and further stripped down. 10 | 11 | notice_file: gentoo.py.NOTICE -------------------------------------------------------------------------------- /src/univers/gentoo.py.NOTICE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions are met: 3 | 4 | 1. Redistributions of source code must retain the above copyright notice, 5 | this list of conditions and the following disclaimer. 6 | 2. Redistributions in binary form must reproduce the above copyright 7 | notice, this list of conditions and the following disclaimer in the 8 | documentation and/or other materials provided with the distribution. 9 | 3. Neither the name of pkgcore nor the names of its 10 | contributors may be used to endorse or promote products derived from 11 | this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 17 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/univers/maven.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: maven.py 2 | package_url: pkg:pypi/pymaven-patch@0.2.9 3 | copyright: | 4 | Copyright (c) SAS Institute Inc. 5 | 6 | notes: This has been substantially modified and enhanced from the original 7 | pymaven code to extract the version comparison code. 8 | 9 | license_expression: apache-2.0 10 | homepage_url: https://github.com/nexB/pymaven 11 | notice_file: maven.py.NOTICE -------------------------------------------------------------------------------- /src/univers/maven.py.NOTICE: -------------------------------------------------------------------------------- 1 | # Copyright (c) SAS Institute Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. -------------------------------------------------------------------------------- /src/univers/nuget.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: nuget.py 2 | package_url: pkg:github/google/osv@0.0.14#lib/osv/nuget.py 3 | copyright: Copyright 2022 Google LLC and others 4 | download_url: https://raw.githubusercontent.com/google/osv/f5647ad2f746685b08debfba0293e442f2fb9945/lib/osv/nuget.py 5 | license_expression: apache-2.0 6 | homepage_url: https://github.com/google/osv/ 7 | notice_file: nuget.py.NOTICE -------------------------------------------------------------------------------- /src/univers/nuget.py.NOTICE: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. -------------------------------------------------------------------------------- /src/univers/rpm.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: rpm.py 2 | package_url: pkg:pypi/rpm_vercmp@0.1.2 3 | copyright: | 4 | Copyright (c) SAS Institute Inc. 5 | 6 | license_expression: apache-2.0 7 | homepage_url: https://github.com/nexB/python-rpm-vercmp 8 | 9 | notes: | 10 | This has been substantially modified and enhanced from the original code. 11 | 12 | notice_file: rpm.py.NOTICE -------------------------------------------------------------------------------- /src/univers/rpm.py.README: -------------------------------------------------------------------------------- 1 | Pure Python implementation of rpmvercmp. 2 | 3 | The RPM Package Manager (http://rpm.org) has a version comparison algorithm, 4 | implemented in its C library, which performs the comparison in a certain way. 5 | 6 | In certain circumstances, where the C library is not installable (for example, 7 | on non-rpm based systems), or does not support the desired version of the 8 | python interpreter, the pure-python implementation may be useful. 9 | 10 | Source Code 11 | =========== 12 | https://github.com/sassoftware/python-rpm-vercmp 13 | 14 | Installation 15 | ============ 16 | $ pip install rpm_vercmp 17 | 18 | Usage 19 | ===== 20 | 21 | import rpm_vercmp 22 | assert rpm_vercmp.vercmp("1.0", "1.0") == 0 23 | assert rpm_vercmp.vercmp("1.0", "1.1") == -1 24 | 25 | Testing 26 | ======= 27 | The testsuite uses rpm's test file in m4 format. 28 | The file cat be fetched from: 29 | https://raw.githubusercontent.com/rpm-software-management/rpm/master/tests/rpmvercmp.at 30 | -------------------------------------------------------------------------------- /src/univers/rpm.py.antlir.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: rpm.py 2 | package_url: pkg:github/facebookincubator/antlir@120b20de91c55244ceacf61f82c5154a28446590#antlir/rpm/rpm_metadata.py 3 | copyright: | 4 | Copyright (c) Facebook, Inc. and its affiliates. 5 | Copyright (c) SAS Institute Inc. 6 | 7 | license_expression: mit AND Apache-2.0 8 | homepage_url: https://github.com/facebookincubator/antlir/ 9 | 10 | notes: | 11 | This has been substantially modified and enhanced from the original code 12 | at https://github.com/facebookincubator/antlir/blob/120b20de91c55244ceacf61f82c5154a28446590/antlir/rpm/rpm_metadata.py 13 | itself taken from 14 | itself originally derived from the Apache-licensed 15 | 16 | notice_file: rpm.py.antlir.NOTICE -------------------------------------------------------------------------------- /src/univers/rpm.py.antlir.NOTICE: -------------------------------------------------------------------------------- 1 | 2 | SPDX-License-Identifier: MIT AND Apache-2.0 3 | 4 | Copyright (c) Facebook, Inc. and its affiliates. 5 | Copyright (c) SAS Institute Inc. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | -------------------------------------------------------------------------------- /src/univers/univers_semver.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | from univers.utils import remove_spaces 8 | from univers.version_constraint import VersionConstraint 9 | from univers.versions import SemverVersion 10 | 11 | """ 12 | node-semver and Rubygems semver-like related utilities. 13 | """ 14 | 15 | 16 | def get_caret_constraints(string): 17 | """ 18 | Return a tuple of two VersionConstraint of ``SemverVersion`` representing 19 | the lower and upper bound of version constraint ``string`` that contains a 20 | caret node-semver- like range. Raise a ValueError if this is not a caret 21 | range. 22 | 23 | For example: 24 | >>> lower_bound, upper_bound = get_caret_constraints("^1.0.2") 25 | >>> vlow = SemverVersion("1.0.2") 26 | >>> vup = SemverVersion("2.0.0") 27 | >>> assert lower_bound == VersionConstraint(comparator=">=", version=vlow) 28 | >>> assert upper_bound == VersionConstraint(comparator="<", version=vup) 29 | """ 30 | string = remove_spaces(string) 31 | if not string or not string.startswith("^"): 32 | raise ValueError(f"Invalid caret version range: {string!r}") 33 | 34 | version = string.lstrip("^") 35 | lower_bound = SemverVersion(version) 36 | upper_bound = SemverVersion(str(lower_bound.value.next_major())) 37 | 38 | return ( 39 | VersionConstraint(comparator=">=", version=lower_bound), 40 | VersionConstraint(comparator="<", version=upper_bound), 41 | ) 42 | 43 | 44 | def get_tilde_constraints(string, operator="~"): 45 | """ 46 | Return a tuple of two VersionConstraint of ``SemverVersion`` representing 47 | the lower and upper bound of a version range ``string`` that contains a 48 | tilde node-semver-like range. 49 | Raise a ValueError if this is not a tilde range. 50 | 51 | For example: 52 | >>> lower_bound, upper_bound = get_tilde_constraints("~1.0.2") 53 | >>> vlow = SemverVersion("1.0.2") 54 | >>> vup = SemverVersion("1.1.0") 55 | >>> assert lower_bound == VersionConstraint(comparator=">=", version=vlow) 56 | >>> assert upper_bound == VersionConstraint(comparator="<", version=vup) 57 | """ 58 | string = remove_spaces(string) 59 | if not string or not string.startswith(operator): 60 | raise ValueError(f"Invalid version range: {string!r} " f"does not start with {operator!r}") 61 | 62 | version = string.lstrip(operator) 63 | lower_bound = SemverVersion(version) 64 | upper_bound = SemverVersion(str(lower_bound.value.next_minor())) 65 | 66 | return ( 67 | VersionConstraint(comparator=">=", version=lower_bound), 68 | VersionConstraint(comparator="<", version=upper_bound), 69 | ) 70 | 71 | 72 | # FIXME: this is unlikely correct https://github.com/npm/node-semver/issues/112 73 | def get_pessimistic_constraints(string): 74 | """ 75 | Return a tuple of two VersionConstraint of ``SemverVersion`` representing 76 | the lower and upper bound of version range ``string`` that contains a 77 | pessimistic Ruby range. Raise a ValueError if this is not a pessimistic 78 | Rubygems range. 79 | 80 | For example: 81 | >>> lower_bound, upper_bound = get_pessimistic_constraints("~>2.0.8") 82 | >>> vlow = SemverVersion("2.0.8") 83 | >>> vup = SemverVersion("2.1.0") 84 | >>> assert lower_bound == VersionConstraint(comparator=">=", version=vlow) 85 | >>> assert upper_bound == VersionConstraint(comparator="<", version=vup) 86 | """ 87 | return get_tilde_constraints(string, operator="~>") 88 | -------------------------------------------------------------------------------- /src/univers/utils.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | 8 | def remove_spaces(string): 9 | return "".join(string.split()) 10 | 11 | 12 | def cmp(x, y): 13 | """ 14 | Replacement for built-in Python 2 function cmp that was removed in Python 3 15 | From https://docs.python.org/2/library/functions.html?highlight=cmp#cmp : 16 | 17 | Compare the two objects x and y and return an integer according to the 18 | outcome. The return value is negative if x < y, zero if x == y and 19 | strictly positive if x > y. 20 | """ 21 | if x == y: 22 | return 0 23 | elif x is None: 24 | return -1 25 | elif y is None: 26 | return 1 27 | else: 28 | # note that this is the minimal replacement function 29 | return (x > y) - (x < y) 30 | -------------------------------------------------------------------------------- /tests/bsd-new.LICENSE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without modification, 2 | are permitted provided that the following conditions are met: 3 | 4 | Redistributions of source code must retain the above copyright notice, this list 5 | of conditions and the following disclaimer. 6 | 7 | Redistributions in binary form must reproduce the above copyright notice, this 8 | list of conditions and the following disclaimer in the documentation and/or 9 | other materials provided with the distribution. 10 | 11 | Neither the name of the ORGANIZATION nor the names of its contributors may be 12 | used to endorse or promote products derived from this software without specific 13 | prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 19 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 21 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 24 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /tests/data/alpine_test.txt.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: alpine_test.txt 2 | description: alpine version comparison tests 3 | license_expression: gpl-2.0 4 | download_url: download_url: https://git.alpinelinux.org/apk-tools/plain/test/version.data?h=v2.12.9 5 | copyright: Copyright (c) Alpine Linux project and apk-tools contributors 6 | package_url: pkg:alpine/apk-tools@2.12.9#test/version.data 7 | notes: this test file does not have an explicit license but is assumed to be GPL-licensed like the rest of alpine 8 | homepage_url: https://git.alpinelinux.org/apk-tools/tree 9 | notice_file: alpine_test.txt.NOTICE -------------------------------------------------------------------------------- /tests/data/alpine_test.txt.NOTICE: -------------------------------------------------------------------------------- 1 | # Alpine Package Keeper 2 | By Natanael Copa and Timo Teräs 3 | Alpine Package Keeper (apk) is a package manager developed for Alpine Linux. -------------------------------------------------------------------------------- /tests/data/openssl/openssl_all_versions.txt: -------------------------------------------------------------------------------- 1 | 3.0.0 2 | 3.0.1 3 | 1.1.1 4 | 1.1.1a 5 | 1.1.1b 6 | 1.1.1c 7 | 1.1.1d 8 | 1.1.1e 9 | 1.1.1f 10 | 1.1.1g 11 | 1.1.1h 12 | 1.1.1i 13 | 1.1.1j 14 | 1.1.1k 15 | 1.1.1l 16 | 1.1.1m 17 | 1.0.2 18 | 1.0.2a 19 | 1.0.2b 20 | 1.0.2c 21 | 1.0.2d 22 | 1.0.2e 23 | 1.0.2f 24 | 1.0.2g 25 | 1.0.2h 26 | 1.0.2i 27 | 1.0.2j 28 | 1.0.2k 29 | 1.0.2l 30 | 1.0.2m 31 | 1.0.2n 32 | 1.0.2o 33 | 1.0.2p 34 | 1.0.2q 35 | 1.0.2r 36 | 1.0.2s 37 | 1.0.2t 38 | 1.0.2u 39 | 1.0.2v 40 | 1.0.2w 41 | 1.0.2x 42 | 1.0.2y 43 | 1.0.2za 44 | 1.0.2zb 45 | 1.0.2zc 46 | 3.0.2 47 | 1.1.1n 48 | 1.0.2zd 49 | 1.0.2zc-dev 50 | 1.1.0 51 | 1.1.0a 52 | 1.1.0b 53 | 1.1.0c 54 | 1.1.0d 55 | 1.1.0e 56 | 1.1.0f 57 | 1.1.0g 58 | 1.1.0h 59 | 1.1.0i 60 | 1.1.0j 61 | 1.1.0k 62 | 1.1.0l 63 | 1.0.1 64 | 1.0.1a 65 | 1.0.1b 66 | 1.0.1c 67 | 1.0.1d 68 | 1.0.1e 69 | 1.0.1f 70 | 1.0.1g 71 | 1.0.1h 72 | 1.0.1i 73 | 1.0.1j 74 | 1.0.1k 75 | 1.0.1l 76 | 1.0.1m 77 | 1.0.1n 78 | 1.0.1o 79 | 1.0.1p 80 | 1.0.1q 81 | 1.0.1r 82 | 1.0.1s 83 | 1.0.1t 84 | 1.0.1u 85 | 0.9.8 86 | 0.9.8a 87 | 0.9.8b 88 | 0.9.8c 89 | 0.9.8d 90 | 0.9.8e 91 | 0.9.8f 92 | 0.9.8g 93 | 0.9.8h 94 | 0.9.8i 95 | 0.9.8j 96 | 0.9.8k 97 | 0.9.8l 98 | 0.9.8m 99 | 0.9.8n 100 | 0.9.8o 101 | 0.9.8p 102 | 0.9.8q 103 | 0.9.8r 104 | 0.9.8s 105 | 0.9.8t 106 | 0.9.8u 107 | 0.9.8v 108 | 0.9.8w 109 | 0.9.8x 110 | 0.9.8y 111 | 0.9.8za 112 | 0.9.8zb 113 | 0.9.8zc 114 | 0.9.8zd 115 | 0.9.8ze 116 | 1.0.0 117 | 1.0.0a 118 | 1.0.0b 119 | 1.0.0c 120 | 1.0.0d 121 | 1.0.0e 122 | 1.0.0f 123 | 1.0.0g 124 | 1.0.0i 125 | 1.0.0j 126 | 1.0.0k 127 | 1.0.0l 128 | 1.0.0m 129 | 1.0.0n 130 | 1.0.0o 131 | 1.0.0p 132 | 1.0.0q 133 | 0.9.8zf 134 | 1.0.0r 135 | 0.9.8zg 136 | 1.0.0h 137 | 1.0.0s 138 | 1.0.0t 139 | 0.9.8zh 140 | 0.9.6 141 | 0.9.6a 142 | 0.9.6b 143 | 0.9.6c 144 | 0.9.6d 145 | 0.9.6e 146 | 0.9.7-beta3 147 | 0.9.7-beta5 148 | 0.9.7-beta1 149 | 0.9.7-alpha3 150 | 0.9.7-alpha2 151 | 0.9.7 152 | 0.9.6f 153 | 0.9.6g 154 | 0.9.6h 155 | 0.9.7a 156 | 0.9.6i 157 | 0.9.6j 158 | 0.9.7b 159 | 0.9.7c 160 | 0.9.6k 161 | 0.9.6l 162 | 0.9.7d 163 | 0.9.6m 164 | 0.9.7e 165 | 0.9.7f 166 | 0.9.6-cvs 167 | 0.9.7g 168 | 0.9.7h 169 | 0.9.7i 170 | 0.9.7j 171 | 0.9.7k 172 | 0.9.7l -------------------------------------------------------------------------------- /tests/data/rpmvercmp.at: -------------------------------------------------------------------------------- 1 | # rpmvercmp.at: rpm version comparison tests 2 | 3 | m4_define([RPMVERCMP],[ 4 | AT_SETUP([rpmvercmp($1, $2) = $3]) 5 | AT_KEYWORDS([vercmp]) 6 | AT_CHECK([ 7 | runroot rpm --eval '%{lua: print(rpm.vercmp("$1", "$2"))}'], [0], [$3 8 | ], []) 9 | AT_CLEANUP 10 | ]) 11 | 12 | AT_BANNER([RPM version comparison]) 13 | 14 | RPMVERCMP(1.0, 1.0, 0) 15 | RPMVERCMP(1.0, 2.0, -1) 16 | RPMVERCMP(2.0, 1.0, 1) 17 | 18 | RPMVERCMP(2.0.1, 2.0.1, 0) 19 | RPMVERCMP(2.0, 2.0.1, -1) 20 | RPMVERCMP(2.0.1, 2.0, 1) 21 | 22 | RPMVERCMP(2.0.1a, 2.0.1a, 0) 23 | RPMVERCMP(2.0.1a, 2.0.1, 1) 24 | RPMVERCMP(2.0.1, 2.0.1a, -1) 25 | 26 | RPMVERCMP(5.5p1, 5.5p1, 0) 27 | RPMVERCMP(5.5p1, 5.5p2, -1) 28 | RPMVERCMP(5.5p2, 5.5p1, 1) 29 | 30 | RPMVERCMP(5.5p10, 5.5p10, 0) 31 | RPMVERCMP(5.5p1, 5.5p10, -1) 32 | RPMVERCMP(5.5p10, 5.5p1, 1) 33 | 34 | RPMVERCMP(10xyz, 10.1xyz, -1) 35 | RPMVERCMP(10.1xyz, 10xyz, 1) 36 | 37 | RPMVERCMP(xyz10, xyz10, 0) 38 | RPMVERCMP(xyz10, xyz10.1, -1) 39 | RPMVERCMP(xyz10.1, xyz10, 1) 40 | 41 | RPMVERCMP(xyz.4, xyz.4, 0) 42 | RPMVERCMP(xyz.4, 8, -1) 43 | RPMVERCMP(8, xyz.4, 1) 44 | RPMVERCMP(xyz.4, 2, -1) 45 | RPMVERCMP(2, xyz.4, 1) 46 | 47 | RPMVERCMP(5.5p2, 5.6p1, -1) 48 | RPMVERCMP(5.6p1, 5.5p2, 1) 49 | 50 | RPMVERCMP(5.6p1, 6.5p1, -1) 51 | RPMVERCMP(6.5p1, 5.6p1, 1) 52 | 53 | RPMVERCMP(6.0.rc1, 6.0, 1) 54 | RPMVERCMP(6.0, 6.0.rc1, -1) 55 | 56 | RPMVERCMP(10b2, 10a1, 1) 57 | RPMVERCMP(10a2, 10b2, -1) 58 | 59 | RPMVERCMP(1.0aa, 1.0aa, 0) 60 | RPMVERCMP(1.0a, 1.0aa, -1) 61 | RPMVERCMP(1.0aa, 1.0a, 1) 62 | 63 | RPMVERCMP(10.0001, 10.0001, 0) 64 | RPMVERCMP(10.0001, 10.1, 0) 65 | RPMVERCMP(10.1, 10.0001, 0) 66 | RPMVERCMP(10.0001, 10.0039, -1) 67 | RPMVERCMP(10.0039, 10.0001, 1) 68 | 69 | RPMVERCMP(4.999.9, 5.0, -1) 70 | RPMVERCMP(5.0, 4.999.9, 1) 71 | 72 | RPMVERCMP(20101121, 20101121, 0) 73 | RPMVERCMP(20101121, 20101122, -1) 74 | RPMVERCMP(20101122, 20101121, 1) 75 | 76 | RPMVERCMP(2_0, 2_0, 0) 77 | RPMVERCMP(2.0, 2_0, 0) 78 | RPMVERCMP(2_0, 2.0, 0) 79 | 80 | dnl RhBug:178798 case 81 | RPMVERCMP(a, a, 0) 82 | RPMVERCMP(a+, a+, 0) 83 | RPMVERCMP(a+, a_, 0) 84 | RPMVERCMP(a_, a+, 0) 85 | RPMVERCMP(+a, +a, 0) 86 | RPMVERCMP(+a, _a, 0) 87 | RPMVERCMP(_a, +a, 0) 88 | RPMVERCMP(+_, +_, 0) 89 | RPMVERCMP(_+, +_, 0) 90 | RPMVERCMP(_+, _+, 0) 91 | RPMVERCMP(+, _, 0) 92 | RPMVERCMP(_, +, 0) 93 | 94 | dnl Basic testcases for tilde sorting 95 | RPMVERCMP(1.0~rc1, 1.0~rc1, 0) 96 | RPMVERCMP(1.0~rc1, 1.0, -1) 97 | RPMVERCMP(1.0, 1.0~rc1, 1) 98 | RPMVERCMP(1.0~rc1, 1.0~rc2, -1) 99 | RPMVERCMP(1.0~rc2, 1.0~rc1, 1) 100 | RPMVERCMP(1.0~rc1~git123, 1.0~rc1~git123, 0) 101 | RPMVERCMP(1.0~rc1~git123, 1.0~rc1, -1) 102 | RPMVERCMP(1.0~rc1, 1.0~rc1~git123, 1) 103 | 104 | dnl Basic testcases for caret sorting 105 | RPMVERCMP(1.0^, 1.0^, 0) 106 | RPMVERCMP(1.0^, 1.0, 1) 107 | RPMVERCMP(1.0, 1.0^, -1) 108 | RPMVERCMP(1.0^git1, 1.0^git1, 0) 109 | RPMVERCMP(1.0^git1, 1.0, 1) 110 | RPMVERCMP(1.0, 1.0^git1, -1) 111 | RPMVERCMP(1.0^git1, 1.0^git2, -1) 112 | RPMVERCMP(1.0^git2, 1.0^git1, 1) 113 | RPMVERCMP(1.0^git1, 1.01, -1) 114 | RPMVERCMP(1.01, 1.0^git1, 1) 115 | RPMVERCMP(1.0^20160101, 1.0^20160101, 0) 116 | RPMVERCMP(1.0^20160101, 1.0.1, -1) 117 | RPMVERCMP(1.0.1, 1.0^20160101, 1) 118 | RPMVERCMP(1.0^20160101^git1, 1.0^20160101^git1, 0) 119 | RPMVERCMP(1.0^20160102, 1.0^20160101^git1, 1) 120 | RPMVERCMP(1.0^20160101^git1, 1.0^20160102, -1) 121 | 122 | dnl Basic testcases for tilde and caret sorting 123 | RPMVERCMP(1.0~rc1^git1, 1.0~rc1^git1, 0) 124 | RPMVERCMP(1.0~rc1^git1, 1.0~rc1, 1) 125 | RPMVERCMP(1.0~rc1, 1.0~rc1^git1, -1) 126 | RPMVERCMP(1.0^git1~pre, 1.0^git1~pre, 0) 127 | RPMVERCMP(1.0^git1, 1.0^git1~pre, 1) 128 | RPMVERCMP(1.0^git1~pre, 1.0^git1, -1) 129 | 130 | dnl These are included here to document current, arguably buggy behaviors 131 | dnl for reference purposes and for easy checking against unintended 132 | dnl behavior changes. 133 | dnl 134 | dnl AT_BANNER([RPM version comparison oddities]) 135 | dnl RhBug:811992 case 136 | dnl RPMVERCMP(1b.fc17, 1b.fc17, 0) 137 | dnl RPMVERCMP(1b.fc17, 1.fc17, -1) 138 | dnl RPMVERCMP(1.fc17, 1b.fc17, 1) 139 | dnl RPMVERCMP(1g.fc17, 1g.fc17, 0) 140 | dnl RPMVERCMP(1g.fc17, 1.fc17, 1) 141 | dnl RPMVERCMP(1.fc17, 1g.fc17, -1) 142 | 143 | dnl Non-ascii characters are considered equal so these are all the same, eh... 144 | dnl RPMVERCMP(1.1.α, 1.1.α, 0) 145 | dnl RPMVERCMP(1.1.α, 1.1.β, 0) 146 | dnl RPMVERCMP(1.1.β, 1.1.α, 0) 147 | dnl RPMVERCMP(1.1.αα, 1.1.α, 0) 148 | dnl RPMVERCMP(1.1.α, 1.1.ββ, 0) 149 | dnl RPMVERCMP(1.1.ββ, 1.1.αα, 0) 150 | -------------------------------------------------------------------------------- /tests/data/rpmvercmp.at.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: rpmvercmp.at 2 | description: rpm version comparison tests 3 | license_expression: gpl-2.0 4 | download_url: https://github.com/rpm-software-management/rpm/blob/04de5e6c854edf4ef4a79b44eac3b20451c88df5/tests/rpmvercmp.at 5 | copyright: Copyright (c) Red Hat Software, Inc. 6 | package_url: pkg:github/rpm-software-management/rpm@04de5e6c854edf4ef4a79b44eac3b20451c88df5#/tests/rpmvercmp.at 7 | notes: this test file does not have an explicit license but is assumed to be GPL-licensed like the rest of RPM 8 | homepage_url: https://github.com/rpm-software-management/rpm 9 | notice_file: rpmvercmp.at.NOTICE -------------------------------------------------------------------------------- /tests/data/rpmvercmp.at.NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) Red Hat Software, Inc. 2 | 3 | RPM was originally written by: 4 | Erik Troan 5 | Marc Ewing 6 | 7 | This test file has been maintained by: 8 | Panu Matilainen @pmatilai 9 | 10 | with contributions by: 11 | Pavlina Varekova @pavlinamv 12 | Igor Gnatenko 13 | 14 | 15 | This program is free software; you can redistribute it and/or modify 16 | it under the terms of the GNU General Public License as published by 17 | the Free Software Foundation; either version 2 of the License, or 18 | (at your option) any later version. 19 | 20 | This program is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU General Public License for more details. 24 | 25 | You should have received a copy of the GNU General Public License 26 | along with this program; if not, write to the Free Software 27 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -------------------------------------------------------------------------------- /tests/data/test-suite-data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "valid simple semver version", 4 | "vers": "vers:semver/=1.3.4", 5 | "canonical_vers": "vers:semver/1.3.4", 6 | "scheme": "semver", 7 | "constraints": [ 8 | [{"comparator": "=", "version": "1.3.4"}] 9 | ], 10 | "is_invalid": false 11 | }, 12 | { 13 | "description": "valid complex debian version", 14 | "vers": "vers:debian/ 5.0A , > = 2.6 & < 3, > = 3.4.4+reloaded2-13+deb9u1 ", 15 | "canonical_vers": "vers:debian/>=2.6&<3,>=3.4.4+reloaded2-13+deb9u1,5.0a", 16 | "scheme": "debian", 17 | "constraints": [ 18 | [{"comparator": ">=", "version": "2.6"}, {"comparator": "<", "version": "3"}], 19 | [{"comparator": ">=", "version": "3.4.4+reloaded2-13+deb9u1"}], 20 | [{"comparator": "=", "version": "5.0a"}] 21 | ], 22 | "is_invalid": false 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /tests/nuget/test_nuget_version_comparer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) .NET Foundation. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # URL: https://github.com/NuGet/NuGet.Client 4 | # Ported to Python from the C# NuGet test suite and significantly modified 5 | 6 | import pytest 7 | 8 | from univers import nuget 9 | 10 | 11 | @pytest.mark.parametrize( 12 | "version1, version2", 13 | [ 14 | ("1.0.0", "1.0.0"), 15 | ("1.0.0-BETA", "1.0.0-beta"), 16 | ("1.0.0-BETA+AA", "1.0.0-beta+aa"), 17 | ("1.0.0-BETA.X.y.5.77.0+AA", "1.0.0-beta.x.y.5.77.0+aa"), 18 | ("1.0.0", "1.0.0+beta"), 19 | ], 20 | ) 21 | def test_VersionComparisonDefaultEqual(version1, version2): 22 | assert nuget.Version.from_string(version1) == nuget.Version.from_string(version2) 23 | 24 | 25 | @pytest.mark.parametrize( 26 | "version1, version2", 27 | [ 28 | ("1.0", "1.0.0.0"), 29 | ("1.0+test", "1.0.0.0"), 30 | ("1.0.0.1-1.2.A", "1.0.0.1-1.2.a+A"), 31 | ("1.0.01", "1.0.1.0"), 32 | ], 33 | ) 34 | def test_VersionComparisonDefaultEqualWithNuGetVersion(version1, version2): 35 | assert nuget.Version.from_string(version1) == nuget.Version.from_string(version2) 36 | 37 | 38 | @pytest.mark.parametrize( 39 | "version1, version2", 40 | [ 41 | ("1.0", "1.0.0.1"), 42 | ("1.0+test", "1.0.0.1"), 43 | ("1.0.0.1-1.2.A", "1.0.0.1-1.2.a.A+A"), 44 | ("1.0.01", "1.0.1.2"), 45 | ], 46 | ) 47 | def test_VersionComparisonDefaultNotEqualWithNuGetVersion(version1, version2): 48 | assert nuget.Version.from_string(version1) != nuget.Version.from_string(version2) 49 | 50 | 51 | @pytest.mark.parametrize( 52 | "version1, version2", 53 | [ 54 | ("0.0.0", "1.0.0"), 55 | ("1.1.0", "1.0.0"), 56 | ("1.0.1", "1.0.0"), 57 | ("1.0.0-BETA", "1.0.0-beta2"), 58 | ("1.0.0+AA", "1.0.0-beta+aa"), 59 | ("1.0.0-BETA.X.y.5.77.0+AA", "1.0.0-beta.x.y.5.79.0+aa"), 60 | ], 61 | ) 62 | def test_VersionComparisonDefaultNotEqual(version1, version2): 63 | assert nuget.Version.from_string(version1) != nuget.Version.from_string(version2) 64 | 65 | 66 | # FIXME: Semver considers these two the same, but this one NuGet test treated them as different 67 | @pytest.mark.parametrize( 68 | "version1, version2", 69 | [ 70 | ("1.0.0-BETA+AA", "1.0.0-beta"), 71 | ], 72 | ) 73 | def test_VersionComparisonDefaultNotEqual2(version1, version2): 74 | assert nuget.Version.from_string(version1) == nuget.Version.from_string(version2) 75 | -------------------------------------------------------------------------------- /tests/nuget/test_nuget_version_parsing.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) .NET Foundation. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # URL: https://github.com/NuGet/NuGet.Client 4 | # Ported to Python from the C# NuGet test suite and significantly modified 5 | 6 | import pytest 7 | 8 | from univers import nuget 9 | 10 | 11 | @pytest.mark.parametrize( 12 | "version", 13 | [ 14 | ("2"), 15 | ("2.0"), 16 | ("2.0.0"), 17 | ("2.0.0.0"), 18 | ], 19 | ) 20 | def test_VersionLength(version): 21 | semVer = nuget.Version.from_string(version) 22 | assert semVer.to_string() == "2.0.0" 23 | 24 | 25 | @pytest.mark.parametrize( 26 | ("version", "expected"), 27 | [ 28 | ("1.0.0-Beta", "1.0.0-beta"), 29 | ("1.0.0-Beta.2", "1.0.0-beta.2"), 30 | ("1.0.0+MetaOnly", "1.0.0+MetaOnly"), 31 | ("1.0.0", "1.0.0"), 32 | ("1.0.0-Beta+Meta", "1.0.0-beta+Meta"), 33 | ("1.0.0-RC.X+MetaAA", "1.0.0-rc.x+MetaAA"), 34 | ("1.0.0-RC.X.35.A.3455+Meta-A-B-C", "1.0.0-rc.x.35.a.3455+Meta-A-B-C"), 35 | ], 36 | ) 37 | def test_FullVersionParsing(version, expected): 38 | version = nuget.Version.from_string(version) 39 | assert str(version) == expected 40 | 41 | 42 | @pytest.mark.parametrize( 43 | ["expected", "version"], 44 | [ 45 | ("beta", "1.0.0-Beta"), 46 | ("beta", "1.0.0-Beta+Meta"), 47 | ("rc.x", "1.0.0-RC.X+Meta"), 48 | ("rc.x.35.a.3455", "1.0.0-RC.X.35.A.3455+Meta"), 49 | ], 50 | ) 51 | def test_SpecialVersionParsing(expected, version): 52 | version = nuget.Version.from_string(version) 53 | assert version.prerelease == expected 54 | 55 | 56 | @pytest.mark.parametrize( 57 | "expected, version", 58 | [ 59 | ("", "1.0.0-Beta"), 60 | ("Meta", "1.0.0-Beta+Meta"), 61 | ("MetaAA", "1.0.0-RC.X+MetaAA"), 62 | ("Meta-A-B-C", "1.0.0-RC.X.35.A.3455+Meta-A-B-C"), 63 | ], 64 | ) 65 | def test_MetadataParsing(expected, version): 66 | version = nuget.Version.from_string(version) 67 | assert version.build == expected 68 | 69 | 70 | @pytest.mark.parametrize( 71 | "expected, version", 72 | [ 73 | (False, "1.0.0-Beta"), 74 | (False, "1.0.0-Beta.2"), 75 | (True, "1.0.0+MetaOnly"), 76 | (False, "1.0.0"), 77 | (True, "1.0.0-Beta+Meta"), 78 | (True, "1.0.0-RC.X+MetaAA"), 79 | (True, "1.0.0-RC.X.35.A.3455+Meta-A-B-C"), 80 | ], 81 | ) 82 | def test_HasMetadataParsing(expected, version): 83 | version = nuget.Version.from_string(version) 84 | assert bool(version.build) == expected 85 | 86 | 87 | @pytest.mark.parametrize( 88 | "major, minor, patch, version", 89 | [ 90 | (0, 0, 0, "0.0.0"), 91 | (1, 0, 0, "1.0.0"), 92 | (3, 5, 1, "3.5.1"), 93 | (234, 234234, 1111, "234.234234.1111"), 94 | (3, 5, 1, "3.5.1+Meta"), 95 | (3, 5, 1, "3.5.1-x.y.z+AA"), 96 | ], 97 | ) 98 | def test_VersionParsing(major, minor, patch, version): 99 | version = nuget.Version.from_string(version) 100 | assert version.major == major 101 | assert version.minor == minor 102 | assert version.patch == patch 103 | -------------------------------------------------------------------------------- /tests/nuget_versioning_tests.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: nuget_versioning_tests 2 | package_url: pkg:github/NuGet/NuGet.Client@588d5d5fbf4e5d3fac29b655286a5f2f2a8a446f#test/NuGet.Core.Tests/NuGet.Versioning.Test 3 | copyright: Copyright (c) .NET Foundation and Contributors. 4 | 5 | license_expression: apache-2.0 6 | homepage_url: https://github.com/NuGet/NuGet.Client 7 | 8 | notes: | 9 | The C# version comparison test suite has been extracted from NugetClient 10 | and further stripped down. Then the interesting subsets have been converted 11 | to Python. 12 | 13 | notice_file: nuget_versioning_tests.NOTICE 14 | -------------------------------------------------------------------------------- /tests/nuget_versioning_tests.NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation and Contributors. 2 | 3 | All rights reserved. 4 | 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | these files except in compliance with the License. You may obtain a copy of the 8 | License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software distributed 13 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations under the License. 16 | -------------------------------------------------------------------------------- /tests/nuget_versioning_tests.README.md: -------------------------------------------------------------------------------- 1 | ![NuGet logo](https://raw.githubusercontent.com/NuGet/Home/dev/meta/resources/nuget.png) 2 | 3 | ----- 4 | 5 | # NuGet Client Tools 6 | 7 | This repo contains the following clients: 8 | 9 | - [NuGet CLI](https://docs.microsoft.com/nuget/tools/nuget-exe-cli-reference) 10 | - [NuGet Package Manager for Visual Studio](https://docs.microsoft.com/nuget/tools/package-manager-ui) 11 | - [PowerShell CmdLets](https://docs.microsoft.com/nuget/tools/powershell-reference) 12 | - [NuGet functionality for dotnet.exe](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet) 13 | 14 | ## Open Source Code of Conduct 15 | 16 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 17 | 18 | ## Getting Started guide 19 | 20 | For how to contribute to this repo follow the [Contributing doc](CONTRIBUTING.md). 21 | 22 | ## NuGet/Home repo 23 | 24 | The [NuGet/Home](https://github.com/nuget/Home) repo is the starting point for all things NuGet. It has the [issue tracker](https://github.com/nuget/home/issues) and [basic information](https://github.com/nuget/home) about all things NuGet. Make sure to consult it before beginning your journey through NuGet code. 25 | 26 | ## Feedback 27 | 28 | File NuGet.Client bugs in the [NuGet/Home](https://github.com/nuget/home/issues). 29 | 30 | ## License 31 | 32 | Unless explicitly stated otherwise all files in this repository are licensed under the License in the root repository 33 | -------------------------------------------------------------------------------- /tests/test_alpine.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | import operator 8 | from typing import NamedTuple 9 | 10 | import pytest 11 | 12 | from univers.versions import AlpineLinuxVersion 13 | from univers.versions import InvalidVersion 14 | 15 | 16 | class AlpineVersionComparison(NamedTuple): 17 | """ 18 | We have this class to drive the tests, where we compare 19 | `version1` and `version2` on the basis of the `comparator` 20 | """ 21 | 22 | version1: str 23 | comparator: str 24 | version2: str 25 | 26 | @classmethod 27 | def from_string(cls, s: str): 28 | segments = s.split() 29 | 30 | assert len(segments) == 3 31 | return cls(*segments) 32 | 33 | def compare(self): 34 | """ 35 | Compare version1 and version2 with comparator 36 | and return True if comparison is valid, False otherwise 37 | """ 38 | v1 = AlpineLinuxVersion(self.version1) 39 | v2 = AlpineLinuxVersion(self.version2) 40 | COMPARATORS = { 41 | "<": operator.lt, 42 | ">": operator.gt, 43 | "=": operator.eq, 44 | } 45 | comparator = COMPARATORS[self.comparator] 46 | return comparator(v1, v2) 47 | 48 | 49 | @pytest.mark.parametrize("test_case", open("./tests/data/alpine_test.txt").read().splitlines(False)) 50 | def test_alpine_vers_cmp(test_case): 51 | avc = AlpineVersionComparison.from_string(test_case) 52 | assert avc.compare() 53 | 54 | 55 | @pytest.mark.parametrize( 56 | "test_case", 57 | [ 58 | # these are the tests are not supported yet 59 | # when we start supporting these version, 60 | # they will be moved back to main test suite 61 | "2.10.1 > 02.08.01b", 62 | "02.08.01b < 4.77", 63 | "23_foo > 4_beta", 64 | "1.06-r6 < 006", 65 | "006 > 1.0.0", 66 | "2.10.1 > 02.08.01b", 67 | "02.08.01b < 4.77", 68 | "2.2.3-r2 < 013", 69 | "013 < 014-r1", 70 | "014-r1 > 1.3.1-r1", 71 | "3.0.0-r2 < 021109-r3", 72 | "021109-r3 < 20060512", 73 | "0.9.28.1 < 087-r1", 74 | "087-r1 < 103", 75 | # invalid. do string sort 76 | "1.0 < 1.0bc", 77 | ], 78 | ) 79 | def test_invalid_alpine_vers_cmp(test_case): 80 | avc = AlpineVersionComparison.from_string(test_case) 81 | with pytest.raises(InvalidVersion): 82 | AlpineLinuxVersion(avc.version1) 83 | AlpineLinuxVersion(avc.version2) 84 | -------------------------------------------------------------------------------- /tests/test_bundler_version_ranges_spec.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) Chad Fowler, Rich Kilmer, Jim Weirich and others. 3 | # Portions copyright (c) Engine Yard and Andre ArkoFacebook, Inc. and its affiliates. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Originally from https://github.com/rubygems/rubygems 8 | 9 | from univers.gem import GemRequirement 10 | 11 | 12 | def test_satisfied_by(): 13 | 14 | assert not GemRequirement("!= 1").satisfied_by("1") 15 | assert GemRequirement("!= 1").satisfied_by("2") 16 | 17 | assert not GemRequirement("!= 1", "= 2").satisfied_by("1") 18 | assert GemRequirement("!= 1", "= 2").satisfied_by("2") 19 | 20 | assert not GemRequirement("!= 1", "> 1").satisfied_by("1") 21 | assert GemRequirement("!= 1", "> 1").satisfied_by("2") 22 | 23 | assert not GemRequirement("!= 1", ">= 1").satisfied_by("1") 24 | assert GemRequirement("!= 1", ">= 1").satisfied_by("2") 25 | 26 | assert not GemRequirement("= 1", ">= 0.1", "<= 1.1").satisfied_by("0.2") 27 | assert GemRequirement("= 1", ">= 0.1", "<= 1.1").satisfied_by("1") 28 | assert not GemRequirement("= 1", ">= 0.1", "<= 1.1").satisfied_by("3") 29 | 30 | assert GemRequirement("= 1", ">= 1", "<= 1").satisfied_by("1") 31 | assert not GemRequirement("= 1", ">= 1", "<= 1").satisfied_by("2") 32 | assert not GemRequirement("= 1", ">= 1", "<= 1").satisfied_by("0.1") 33 | 34 | assert GemRequirement("= 1", "~> 1").satisfied_by("1") 35 | assert not GemRequirement("= 1", "~> 1").satisfied_by("1.1") 36 | 37 | assert GemRequirement(">= 0.z", "= 0").satisfied_by("0") 38 | assert not GemRequirement(">= 0.z", "= 0").satisfied_by("1") 39 | assert not GemRequirement(">= 0.z", "= 0").satisfied_by("0.1") 40 | assert not GemRequirement(">= 0.z", "= 0").satisfied_by("0.z") 41 | 42 | assert GemRequirement(">= 0").satisfied_by("1") 43 | assert GemRequirement(">= 0").satisfied_by("2") 44 | assert GemRequirement(">= 0").satisfied_by("0") 45 | 46 | assert not GemRequirement(">= 1.0.0", "< 2.0.0").satisfied_by("3") 47 | assert GemRequirement(">= 1.0.0", "< 2.0.0").satisfied_by("1.5.1") 48 | 49 | assert GemRequirement("~> 1").satisfied_by("1") 50 | assert GemRequirement("~> 1").satisfied_by("1.1") 51 | assert not GemRequirement("~> 1").satisfied_by("2") 52 | 53 | assert not GemRequirement("~> 2.0", "~> 2.1").satisfied_by("1") 54 | assert GemRequirement("~> 2.0", "~> 2.1").satisfied_by("2.1.2") 55 | 56 | assert not GemRequirement(">= 4.1.0", "< 5.0", "= 5.2.1").satisfied_by("1") 57 | assert not GemRequirement(">= 4.1.0", "< 5.0", "= 5.2.1").satisfied_by("5.2.1") 58 | assert not GemRequirement( 59 | "< 5.0", 60 | "< 5.3", 61 | "< 6.0", 62 | "< 6", 63 | "= 5.2.0", 64 | "> 2", 65 | ">= 3.0", 66 | ">= 3.1", 67 | ">= 3.2", 68 | ">= 4.0.0", 69 | ">= 4.1.0", 70 | ">= 4.2.0", 71 | ">= 4.2", 72 | ">= 4", 73 | ).satisfied_by("5.2.0") 74 | assert not GemRequirement("!= 1", "< 2", "> 2").satisfied_by("1") 75 | assert not GemRequirement("!= 1", "<= 1", ">= 1").satisfied_by("1") 76 | assert not GemRequirement("< 2", "> 2").satisfied_by("1") 77 | assert not GemRequirement("< 2", "> 2", "= 2").satisfied_by("1") 78 | assert not GemRequirement("= 1", "!= 1").satisfied_by("1") 79 | assert not GemRequirement("= 1", "= 2").satisfied_by("1") 80 | assert not GemRequirement("= 1", "~> 2").satisfied_by("1") 81 | assert not GemRequirement(">= 0", "<= 0.a").satisfied_by("1") 82 | assert not GemRequirement("~> 2.0", "~> 3").satisfied_by("1") 83 | -------------------------------------------------------------------------------- /tests/test_bundler_version_ranges_spec.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_bundler_version_ranges_spec.py 2 | package_url: pkg:github.com/rubygems/rubygems@5768c2bc5542ce05466d379981a433ba1ee1e10a 3 | copyright: | 4 | Portions copyright (c) André Arko 5 | Portions copyright (c) Engine Yard 6 | 7 | license_expression: mit 8 | homepage_url: https://github.com/rubygems/rubygems 9 | 10 | notes: This has been substantially modified and enhanced from the original code 11 | to port tests cases to Python 12 | 13 | notice_file: test_bundler_edgecases_spec.py.NOTICE -------------------------------------------------------------------------------- /tests/test_bundler_version_ranges_spec.py.NOTICE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Portions copyright (c) 2010-2019 André Arko 4 | Portions copyright (c) 2009 Engine Yard 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /tests/test_codestyle.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | import subprocess 8 | import sys 9 | import unittest 10 | 11 | import pytest 12 | 13 | 14 | @pytest.mark.skipif(sys.platform == "darwin", reason="Test does not run on macOS13 and older.") 15 | class BaseTests(unittest.TestCase): 16 | def test_codestyle(self): 17 | args = "black --check -l 100 setup.py src tests" 18 | try: 19 | subprocess.check_output(args.split(), shell=False) 20 | except subprocess.CalledProcessError as e: 21 | print("===========================================================") 22 | print(e.output) 23 | print("===========================================================") 24 | raise Exception( 25 | "Black style check failed; please format the code using:\n" 26 | " python -m black -l 100 setup.py src tests", 27 | e.output, 28 | ) from e 29 | 30 | args = "isort --check-only src tests setup.py" 31 | try: 32 | subprocess.check_output(args.split(), shell=False) 33 | except Exception as e: 34 | print("===========================================================") 35 | print(e.output) 36 | print("===========================================================") 37 | raise Exception( 38 | "Unsorted imports, please sort your imports using isort. " 39 | "Alternatively, run ``isort src tests setup.py``", 40 | e.output, 41 | ) from e 42 | -------------------------------------------------------------------------------- /tests/test_conan_version_bump.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019 JFrog LTD 3 | # SPDX-License-Identifier: MIT 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | import pytest 8 | 9 | from univers.versions import ConanVersion 10 | 11 | values = [ 12 | ["1.0.0", 0, "2.0.0"], 13 | ["1.1.0", 0, "2.0.0"], 14 | ["1.1.1-pre", 0, "2.0.0"], 15 | ["1.1.1", 1, "1.2.0"], 16 | ["1.1.1", 2, "1.1.2"], 17 | ] 18 | 19 | 20 | @pytest.mark.parametrize("version, index, result", values) 21 | def test_version_bump(version, index, result): 22 | r = ConanVersion(version) 23 | bumped = r.bump(index) 24 | assert bumped == result 25 | -------------------------------------------------------------------------------- /tests/test_conan_version_bump.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_conan_version_bump.py 2 | package_url: pkg:pypi/conan@2.0.0 3 | copyright: | 4 | Copyright (c) 2019 JFrog LTD 5 | download_url: https://github.com/conan-io/conan/tree/release/2.0/conans/test/unittests/model/version/test_conan_version_bump.py 6 | license_expression: MIT 7 | homepage_url: https://github.com/conan-io/conan 8 | notice_file: test_conan_version_bump.py.NOTICE 9 | -------------------------------------------------------------------------------- /tests/test_conan_version_bump.py.NOTICE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 JFrog LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_conan_version_comparison.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019 JFrog LTD 3 | # SPDX-License-Identifier: MIT 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | import pytest 8 | 9 | from univers.versions import ConanVersion 10 | 11 | v = [ 12 | ("1", "2"), 13 | ("1.0", "1.1"), 14 | ("1.0.2", "1.1.0"), 15 | ("1.3", "1.22"), 16 | ("1.1.3", "1.1.22"), 17 | ("1.1.1.3", "1.1.1.22"), 18 | ("1.1.1.1.3", "1.1.1.1.22"), 19 | # Different lengths 20 | ("1.0", "2"), 21 | ("1.2", "1.3.1"), 22 | ("1.0.2", "1.1"), 23 | # Now with letters 24 | ("1.1.a", "1.1.b"), 25 | ("1.1.1.abc", "1.1.1.abz"), 26 | ("a.b.c", "b.c"), 27 | ("1.1", "1.a"), 28 | ("1.1", "1.1a"), 29 | ("1.1", "1.1.a"), 30 | ("1.1.a", "1.2"), 31 | # Arterisk are before digits 32 | ("1.1*", "1.20"), 33 | ("1.1.*", "1.20"), 34 | ("1.2.2", "1.3.*"), 35 | ("1.2.2", "1.2.3*"), 36 | # build is easy 37 | ("1.1+b1", "1.1+b2"), 38 | ("1.1", "1.1+b2"), 39 | ("1.1+b1", "1.2"), 40 | ("1.1+b.3", "1.1+b.22"), 41 | # pre-release is challenging 42 | ("1.1-pre1", "1.1-pre2"), 43 | ("1.1-alpha.3", "1.1-alpha.22"), 44 | ("1.1-alpha.3+b1", "1.1-alpha.3+b2"), 45 | ("1.1-alpha.1", "1.1"), 46 | ("1.1", "1.2-alpha1"), 47 | ("1.1-alpha.1", "1.1.0"), # pre to the generic 1.1 is earlier than 1.1.0 48 | ("1.0.0-", "1.0.0-alpha1"), 49 | ] 50 | 51 | 52 | @pytest.mark.parametrize("v1, v2", v) 53 | def test_comparison(v1, v2): 54 | v1 = ConanVersion(v1) 55 | v2 = ConanVersion(v2) 56 | assert v1 < v2 57 | assert v2 > v1 58 | assert v1 != v2 59 | assert v1 <= v2 60 | assert v2 >= v1 61 | 62 | 63 | def test_comparison_with_integer(): 64 | v1 = ConanVersion("13.0") 65 | # Issue: https://github.com/conan-io/conan/issues/12907 66 | assert v1 > ConanVersion("5") 67 | assert v1 >= ConanVersion("5") 68 | assert v1 < ConanVersion("20") 69 | assert v1 <= ConanVersion("20") 70 | assert v1 == ConanVersion("13") 71 | assert v1 != ConanVersion("14") 72 | 73 | 74 | e = [ 75 | ("1", "1.0"), 76 | ("1", "1.0.0"), 77 | ("1.0", "1.0.0"), 78 | ("1.0", "1.0.0.0"), 79 | ("1-pre1", "1.0-pre1"), 80 | ("1-pre1", "1.0.0-pre1"), 81 | ("1.0-pre1", "1.0.0-pre1"), 82 | ("1.0-pre1.0", "1.0.0-pre1"), 83 | ("1-pre1+b1", "1.0-pre1+b1"), 84 | ("1-pre1+b1", "1.0.0-pre1+b1"), 85 | ("1.0-pre1+b1", "1.0.0-pre1+b1"), 86 | ("1+b1", "1.0+b1"), 87 | ("1+b1", "1.0+b1.0"), 88 | ("1+b1", "1.0.0+b1"), 89 | ("1.0+b1", "1.0.0+b1"), 90 | ] 91 | 92 | 93 | @pytest.mark.parametrize("v1, v2", e) 94 | def test_equality(v1, v2): 95 | v1 = ConanVersion(v1) 96 | v2 = ConanVersion(v2) 97 | assert v1 == v2 98 | assert not v1 != v2 99 | 100 | 101 | def test_elem_comparison(): 102 | v1 = ConanVersion("1.2.3b.4-pre.1.2b+build.1.1b") 103 | major = v1.major 104 | assert major < 2 105 | assert major < "2" 106 | assert major == 1 107 | assert major != 3 108 | assert major > 0 109 | assert str(major) == "1" 110 | patch = v1.patch 111 | assert patch < 4 112 | assert patch > 2 113 | assert patch < "3c" 114 | assert patch > "3a" 115 | assert patch == "3b" 116 | micro = v1.micro 117 | assert micro > 3 118 | assert micro < 5 119 | assert micro == 4 120 | -------------------------------------------------------------------------------- /tests/test_conan_version_comparison.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_conan_version_comparison.py 2 | package_url: pkg:pypi/conan@2.0.0 3 | copyright: | 4 | Copyright (c) 2019 JFrog LTD 5 | download_url: https://github.com/conan-io/conan/tree/release/2.0/conans/test/unittests/model/version/test_conan_version_comparison.py 6 | license_expression: MIT 7 | homepage_url: https://github.com/conan-io/conan 8 | notice_file: test_conan_version_comparison.py.NOTICE 9 | -------------------------------------------------------------------------------- /tests/test_conan_version_comparison.py.NOTICE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 JFrog LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_conan_version_range.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019 JFrog LTD 3 | # SPDX-License-Identifier: MIT 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | import pytest 8 | 9 | from univers.conan.errors import ConanException 10 | from univers.conan.version_range import VersionRange 11 | from univers.versions import ConanVersion 12 | 13 | values = [ 14 | [">1.0.0", [[[">", "1.0.0"]]], ["1.0.1"], ["0.1"]], 15 | ["<2.0", [[["<", "2.0"]]], ["1.0.1"], ["2.1"]], 16 | [">1 <2.0", [[[">", "1"], ["<", "2.0"]]], ["1.5.1"], ["0.1", "2.1"]], 17 | # tilde 18 | ["~2.5", [[[">=", "2.5"], ["<", "2.6-"]]], ["2.5.0", "2.5.3"], ["2.7", "2.6.1"]], 19 | ["~2.5.1", [[[">=", "2.5.1"], ["<", "2.6.0-"]]], ["2.5.1", "2.5.3"], ["2.5", "2.6.1"]], 20 | ["~1", [[[">=", "1"], ["<", "2-"]]], ["1.3", "1.8.1"], ["0.8", "2.2"]], 21 | # caret 22 | ["^1.2", [[[">=", "1.2"], ["<", "2.0-"]]], ["1.2.1", "1.51"], ["1", "2", "2.0.1"]], 23 | ["^1.2.3", [[[">=", "1.2.3"], ["<", "2.0.0-"]]], ["1.2.3", "1.2.4"], ["2", "2.1", "2.0.1"]], 24 | ["^0.1.2", [[[">=", "0.1.2"], ["<", "0.2.0-"]]], ["0.1.3", "0.1.44"], ["1", "0.3", "0.2.1"]], 25 | # Identity 26 | ["1.0.0", [[["=", "1.0.0"]]], ["1.0.0"], ["2", "1.0.1"]], 27 | ["=1.0.0", [[["=", "1.0.0"]]], ["1.0.0"], ["2", "1.0.1"]], 28 | # Any 29 | ["*", [[[">=", "0.0.0"]]], ["1.0", "a.b"], []], 30 | ["", [[[">=", "0.0.0"]]], ["1.0", "a.b"], []], 31 | # Unions 32 | ["1.0.0 || 2.1.3", [[["=", "1.0.0"]], [["=", "2.1.3"]]], ["1.0.0", "2.1.3"], ["2", "1.0.1"]], 33 | [ 34 | ">1 <2.0 || ^3.2 ", 35 | [[[">", "1"], ["<", "2.0"]], [[">=", "3.2"], ["<", "4.0-"]]], 36 | ["1.5", "3.3"], 37 | ["2.1", "0.1", "5"], 38 | ], 39 | # pre-releases 40 | ["", [[[">=", "0.0.0"]]], ["1.0"], ["1.0-pre.1"]], 41 | ["*, include_prerelease=True", [[[">=", "0.0.0"]]], ["1.0", "1.0-pre.1"], []], 42 | ["*-", [[[">=", "0.0.0"]]], ["1.0", "1.0-pre.1"], []], 43 | [">1- <2.0", [[[">", "1"], ["<", "2.0"]]], ["1.5.1-pre1"], ["2.1-pre1"]], 44 | [ 45 | ">1- <2.0 || ^3.2 ", 46 | [[[">", "1"], ["<", "2.0"]], [[">=", "3.2"], ["<", "4.0-"]]], 47 | ["1.5-a1", "3.3"], 48 | ["3.3-a1"], 49 | ], 50 | ["^1.1.2-", [[[">=", "1.1.2"], ["<", "2.0.0-"]]], ["1.2.3", "1.2.0-alpha1"], ["2.0.0-alpha1"]], 51 | ["~1.1.2-", [[[">=", "1.1.2"], ["<", "1.2.0-"]]], ["1.1.3", "1.1.3-alpha1"], ["1.2.0-alpha1"]], 52 | ] 53 | 54 | 55 | @pytest.mark.parametrize("version_range, conditions, versions_in, versions_out", values) 56 | def test_range(version_range, conditions, versions_in, versions_out): 57 | r = VersionRange(version_range) 58 | for condition_set, expected_condition_set in zip(r.condition_sets, conditions): 59 | for condition, expected_condition in zip(condition_set.conditions, expected_condition_set): 60 | assert condition.operator == expected_condition[0] 61 | assert condition.version == ConanVersion(expected_condition[1]) 62 | 63 | for v in versions_in: 64 | assert ConanVersion(v) in r 65 | 66 | for v in versions_out: 67 | assert ConanVersion(v) not in r 68 | 69 | 70 | def test_wrong_range_syntax(): 71 | # https://github.com/conan-io/conan/issues/12692 72 | with pytest.raises(ConanException): 73 | VersionRange(">= 1.0") 74 | -------------------------------------------------------------------------------- /tests/test_conan_version_range.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_conan_version_range.py 2 | package_url: pkg:pypi/conan@2.0.0 3 | copyright: | 4 | Copyright (c) 2019 JFrog LTD 5 | download_url: https://github.com/conan-io/conan/tree/release/2.0/conans/test/unittests/model/version/test_conan_version_range.py 6 | license_expression: MIT 7 | homepage_url: https://github.com/conan-io/conan 8 | notice_file: test_conan_version_range.py.NOTICE 9 | -------------------------------------------------------------------------------- /tests/test_conan_version_range.py.NOTICE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 JFrog LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_debian_version.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_debian_version.py 2 | license_expression: apache-2.0 3 | download_url: https://raw.githubusercontent.com/nexB/debian-inspector/b8f413de99c3f21bca759aba94cc815791b06619/tests/test_version.py 4 | copyright: Copyright (c) nexB Inc. and others. 5 | package_url: pkg:pypi/debian-inspector@0.9.10#tests/test_version.py 6 | notes: this subset of tests has been modified to tests version comparison and parsing 7 | homepage_url: https://github.com/aboutcode-org/debian-inspector 8 | notice_file: test_debian_version.py.NOTICE 9 | -------------------------------------------------------------------------------- /tests/test_debian_version.py.NOTICE: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Copyright (c) 2018 Peter Odding 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining 6 | # a copy of this software and associated documentation files (the 7 | # "Software"), to deal in the Software without restriction, including 8 | # without limitation the rights to use, copy, modify, merge, publish, 9 | # distribute, sublicense, and/or sell copies of the Software, and to 10 | # permit persons to whom the Software is furnished to do so, subject to 11 | # the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be 14 | # included in all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | # Debian packaging tools: Version comparison. 25 | # Original-Author: Peter Odding 26 | # Original-URL: https://github.com/xolox/python-deb-pkg-tools 27 | -------------------------------------------------------------------------------- /tests/test_debian_version_python_deb_pkg_tools.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) Peter Odding 3 | # URL: https://github.com/xolox/python-deb-pkg-tools 4 | # SPDX-License-Identifier: MIT 5 | # 6 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 7 | 8 | 9 | from unittest import TestCase 10 | 11 | from univers.debian import Version 12 | 13 | 14 | class DebPkgToolsTestCase(TestCase): 15 | def test_version_sorting(self): 16 | # Check version sorting implemented on top of `=' and `<<' comparisons. 17 | expected_order = ["0.1", "0.5", "1.0", "2.0", "3.0", "1:0.4", "2:0.3"] 18 | assert list(sorted(expected_order)) != expected_order 19 | result = [str(v) for v in sorted(map(Version.from_string, expected_order))] 20 | assert result == expected_order 21 | 22 | def test_version_comparison(self): 23 | assert Version.from_string("1.0") > Version.from_string("0.5") 24 | assert Version.from_string("1:0.5") > Version.from_string("2.0") 25 | assert not Version.from_string("0.5") > Version.from_string("2.0") 26 | 27 | assert Version.from_string("0.75") >= Version.from_string("0.5") 28 | assert Version.from_string("0.50") >= Version.from_string("0.5") 29 | assert Version.from_string("1:0.5") >= Version.from_string("5.0") 30 | assert not Version.from_string("0.2") >= Version.from_string("0.5") 31 | 32 | assert Version.from_string("0.5") < Version.from_string("1.0") 33 | assert Version.from_string("2.0") < Version.from_string("1:0.5") 34 | assert not Version.from_string("2.0") < Version.from_string("0.5") 35 | 36 | assert Version.from_string("0.5") <= Version.from_string("0.75") 37 | assert Version.from_string("0.5") <= Version.from_string("0.50") 38 | assert Version.from_string("5.0") <= Version.from_string("1:0.5") 39 | assert not Version.from_string("0.5") <= Version.from_string("0.2") 40 | 41 | assert Version.from_string("42") == Version.from_string("42") 42 | assert Version.from_string("0.5") == Version.from_string("0:0.5") 43 | assert not Version.from_string("0.5") == Version.from_string("1.0") 44 | 45 | assert Version.from_string("1") != Version.from_string("0") 46 | assert not Version.from_string("0.5") != Version.from_string("0:0.5") 47 | 48 | assert Version.from_string("1.3~rc2") < Version.from_string("1.3") 49 | -------------------------------------------------------------------------------- /tests/test_debian_version_python_deb_pkg_tools.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_version_python_deb_pkg_tools.py 2 | name: python-debian 3 | license_expression: mit 4 | download_url: https://raw.githubusercontent.com/xolox/python-deb-pkg-tools/a3d6ef1d82c6342b6a57876fc2360875e033f8f0/deb_pkg_tools/tests.py 5 | copyright: Copyright (c) Peter Odding 6 | package_url: pkg:pypi/deb-pkg-tools@8.4#deb_pkg_tools/tests.py 7 | notes: this subset of tests has been modified to tests version comparison and parsing 8 | homepage_url: https://github.com/xolox/python-deb-pkg-tools -------------------------------------------------------------------------------- /tests/test_gem.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Center for Information Technology, http://coi.gov.pl 2 | # SPDX-License-Identifier: Apache-2.0 3 | # this has been significantly modified from the original 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | # notes: This has been substantially modified and enhanced from the original 8 | # puppeteer code to extract the Ruby version handling code. 9 | 10 | from univers.gem import GemRequirement 11 | from univers.gem import GemVersion 12 | 13 | 14 | def test_gem_version_release(): 15 | assert GemVersion("1.2.4.beta").release() == GemVersion("1.2.4") 16 | 17 | 18 | def test_gem_version_bump(): 19 | assert GemVersion("1.2.4").bump() == GemVersion("1.3.0") 20 | 21 | 22 | def test_gem_version_compare(): 23 | assert GemVersion("1.3.0") == GemVersion("1.3") 24 | assert GemVersion("1.3.0") <= GemVersion("1.3") 25 | assert GemVersion("1.1.3") <= GemVersion("1.3") 26 | assert GemVersion("1.4.pre") >= GemVersion("1.3") 27 | assert GemVersion("1.4.pre") != GemVersion("1.4") 28 | 29 | 30 | def test_gem_requirement(): 31 | assert GemRequirement("3.4").satisfied_by("3.4.0") 32 | assert GemRequirement("~> 3.4").satisfied_by("3.4.8") 33 | assert GemRequirement(">= 3.4").satisfied_by("4.4.8") 34 | assert GemRequirement(">= 3.4", "<4").satisfied_by("3.45.8") 35 | 36 | 37 | def test_gem_requirement_fails1(): 38 | assert GemRequirement(">= 3.4", "<4").satisfied_by("4.1") is False 39 | 40 | 41 | def test_gem_requirement_fails2(): 42 | assert GemRequirement("~> 3").satisfied_by("4.1.0.pre") is False 43 | -------------------------------------------------------------------------------- /tests/test_gem.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_gem.py 2 | license_expression: apache-2.0 3 | download_url: https://raw.githubusercontent.com/coi-gov-pl/puppeter/develop/tests/domain/model/test_gemrequirement.py 4 | copyright: Copyright (c) Center for Information Technology http://coi.gov.pl 5 | package_url: pkg:pypi/puppeter@0.8.3#tests/domain/model/test_gemrequirement.py 6 | notes: this subset of tests has been modified to tests version comparison and parsing 7 | homepage_url: https://github.com/coi-gov-pl/puppeter 8 | notice_file: test_gem.py.NOTICE 9 | -------------------------------------------------------------------------------- /tests/test_gem.py.NOTICE: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Center for Information Technology 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. -------------------------------------------------------------------------------- /tests/test_gentoo.py: -------------------------------------------------------------------------------- 1 | # test_vercmp.py -- Portage Unit Testing Functionality 2 | # Copyright 2006 Gentoo Foundation 3 | # SPDX-License-Identifier: GPL-2.0-only 4 | # this has been significantly modified from the original 5 | # 6 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 7 | 8 | 9 | from unittest import TestCase 10 | 11 | from univers.gentoo import vercmp 12 | 13 | 14 | class VerCmpTestCase(TestCase): 15 | """A simple testCase for univers.gentoo.vercmp()""" 16 | 17 | def testVerCmpGreater(self): 18 | 19 | tests = [ 20 | ("6.0", "5.0"), 21 | ("5.0", "5"), 22 | ("1.0-r1", "1.0-r0"), 23 | ("1.0-r1", "1.0"), 24 | ("999999999999999999999999999999", "999999999999999999999999999998"), 25 | ("1.0.0", "1.0"), 26 | ("1.0.0", "1.0b"), 27 | ("1b", "1"), 28 | ("1b_p1", "1_p1"), 29 | ("1.1b", "1.1"), 30 | ("12.2.5", "12.2b"), 31 | ] 32 | for test in tests: 33 | self.assertFalse( 34 | vercmp(test[0], test[1]) <= 0, msg="%s < %s? Wrong!" % (test[0], test[1]) 35 | ) 36 | 37 | def testVerCmpLess(self): 38 | """ 39 | pre < alpha < beta < rc < p -> test each of these, they are inductive (or should be..) 40 | """ 41 | tests = [ 42 | ("4.0", "5.0"), 43 | ("5", "5.0"), 44 | ("1.0_pre2", "1.0_p2"), 45 | ("1.0_alpha2", "1.0_p2"), 46 | ("1.0_alpha1", "1.0_beta1"), 47 | ("1.0_beta3", "1.0_rc3"), 48 | ("1.001000000000000000001", "1.001000000000000000002"), 49 | ("1.00100000000", "1.0010000000000000001"), 50 | ("999999999999999999999999999998", "999999999999999999999999999999"), 51 | ("1.01", "1.1"), 52 | ("1.0-r0", "1.0-r1"), 53 | ("1.0", "1.0-r1"), 54 | ("1.0", "1.0.0"), 55 | ("1.0b", "1.0.0"), 56 | ("1_p1", "1b_p1"), 57 | ("1", "1b"), 58 | ("1.1", "1.1b"), 59 | ("12.2b", "12.2.5"), 60 | ] 61 | for test in tests: 62 | self.assertFalse( 63 | vercmp(test[0], test[1]) >= 0, msg="%s > %s? Wrong!" % (test[0], test[1]) 64 | ) 65 | 66 | def testVerCmpEqual(self): 67 | 68 | tests = [ 69 | ("4.0", "4.0"), 70 | ("1.0", "1.0"), 71 | ("1.0-r0", "1.0"), 72 | ("1.0", "1.0-r0"), 73 | ("1.0-r0", "1.0-r0"), 74 | ("1.0-r1", "1.0-r1"), 75 | ] 76 | for test in tests: 77 | self.assertFalse( 78 | vercmp(test[0], test[1]) != 0, msg="%s != %s? Wrong!" % (test[0], test[1]) 79 | ) 80 | 81 | def testVerNotEqual(self): 82 | 83 | tests = [ 84 | ("1", "2"), 85 | ("1.0_alpha", "1.0_pre"), 86 | ("1.0_beta", "1.0_alpha"), 87 | ("0", "0.0"), 88 | ("1.0-r0", "1.0-r1"), 89 | ("1.0-r1", "1.0-r0"), 90 | ("1.0", "1.0-r1"), 91 | ("1.0-r1", "1.0"), 92 | ("1.0", "1.0.0"), 93 | ("1_p1", "1b_p1"), 94 | ("1b", "1"), 95 | ("1.1b", "1.1"), 96 | ("12.2b", "12.2"), 97 | ] 98 | for test in tests: 99 | self.assertFalse( 100 | vercmp(test[0], test[1]) == 0, msg="%s == %s? Wrong!" % (test[0], test[1]) 101 | ) 102 | -------------------------------------------------------------------------------- /tests/test_gentoo.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_gentoo.py 2 | package_url: pkg:ebuild/sys-apps/portage@3.0.13#tests/versions/test_vercmp.py 3 | copyright: Copyright 1998-2016 Gentoo Foundation 4 | 5 | license_expression: GPL-2.0-only 6 | homepage_url: https://gitweb.gentoo.org/proj/portage.git/ 7 | 8 | notes: version comparison tests extracted from portage and further stripped down. 9 | 10 | notice_file: gentoo.py.NOTICE -------------------------------------------------------------------------------- /tests/test_gentoo.py.NOTICE: -------------------------------------------------------------------------------- 1 | +about_resource: test_gentoo.py 2 | +package_url: pkg:ebuild/sys-apps/portage@3.0.13#tests/versions/test_vercmp.py 3 | +copyright: | 4 | + Copyright 1998-2016 Gentoo Foundation 5 | + 6 | +license_expression: GPL-2.0-only 7 | +homepage_url: https://gitweb.gentoo.org/proj/portage.git/ 8 | + 9 | +notes: | 10 | + The version comparison utility is extracted from portage and further stripped down. 11 | + 12 | +notice_file: gentoo.py.NOTICE -------------------------------------------------------------------------------- /tests/test_gentoo_pkgcore.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_gentoo_pkgcore.py 2 | package_url: pkg:pypi/pkgcore@0.11.8#tests/ebuild/test_cpv.py 3 | copyright: Copyright (c) 2006-2019, pkgcore contributors 4 | license_expression: BSD-3-Clause 5 | homepage_url: https://github.com/pkgcore/pkgcore/blob/master/tests/ebuild/test_cpv.py 6 | notes: The version comparison utility code is extracted from pkgcore and further stripped down. 7 | notice_file: gentoo.py.NOTICE -------------------------------------------------------------------------------- /tests/test_gentoo_pkgcore.py.NOTICE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions are met: 3 | 4 | 1. Redistributions of source code must retain the above copyright notice, 5 | this list of conditions and the following disclaimer. 6 | 2. Redistributions in binary form must reproduce the above copyright 7 | notice, this list of conditions and the following disclaimer in the 8 | documentation and/or other materials provided with the distribution. 9 | 3. Neither the name of pkgcore nor the names of its 10 | contributors may be used to endorse or promote products derived from 11 | this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 17 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /tests/test_maven_version.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_maven_version.py 2 | license_expression: apache-2.0 3 | download_url: https://raw.githubusercontent.com/nexB/pymaven/f0fe2c908283916daf2573c484433ed55dc4b907/tests/test_versioning.py 4 | copyright: Copyright (c) SAS Institute Inc. 5 | package_url: pkg:pypi/pymaven-patch@0.2.9#tests/test_versioning.py 6 | notes: this subset of tests has been modified to tests version comparison and parsing 7 | homepage_url: https://github.com/nexB/pymaven 8 | notice_file: test_maven_version.py.NOTICE -------------------------------------------------------------------------------- /tests/test_maven_version.py.NOTICE: -------------------------------------------------------------------------------- 1 | # Copyright (c) SAS Institute Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. -------------------------------------------------------------------------------- /tests/test_maven_version_range.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | from univers.version_constraint import VersionConstraint 8 | from univers.version_range import MavenVersionRange 9 | from univers.versions import MavenVersion 10 | 11 | 12 | def test_maven_version_range_from_native_with_lower_inclusive(): 13 | version_range = MavenVersionRange.from_native("[1.0.0,2.0.0)") 14 | assert version_range == MavenVersionRange( 15 | constraints=( 16 | VersionConstraint(comparator=">=", version=MavenVersion(string="1.0.0")), 17 | VersionConstraint(comparator="<", version=MavenVersion(string="2.0.0")), 18 | ) 19 | ) 20 | 21 | 22 | def test_maven_version_range_from_native_with_nothing_inclusive(): 23 | version_range = MavenVersionRange.from_native(" ( 1.0.0 , 2.1.4 ) ") 24 | assert version_range == MavenVersionRange( 25 | constraints=( 26 | VersionConstraint(comparator=">", version=MavenVersion(string="1.0.0")), 27 | VersionConstraint(comparator="<", version=MavenVersion(string="2.1.4")), 28 | ) 29 | ) 30 | 31 | 32 | def test_maven_version_range_from_native_for_pinned_version(): 33 | version_range = MavenVersionRange.from_native("[1.0.0]") 34 | assert version_range == MavenVersionRange( 35 | constraints=(VersionConstraint(comparator="=", version=MavenVersion(string="1.0.0")),) 36 | ) 37 | 38 | 39 | def test_maven_version_range_from_native_for_illformed_version(): 40 | try: 41 | MavenVersionRange.from_native("(1.0.0]") 42 | assert False, "should have raised an exception" 43 | except ValueError: 44 | assert True 45 | 46 | 47 | def test_maven_version_range_from_native_str_representation(): 48 | version_range = MavenVersionRange.from_native("[1.0.0,5.1)") 49 | assert str(version_range) == "vers:maven/>=1.0.0|<5.1" 50 | 51 | 52 | def test_maven_version_range_from_native_for_multiple_version_ranges(): 53 | version_range = MavenVersionRange.from_native("[2.0,2.3.1] , [2.4.0,2.12.2) , [2.13.0,2.15.0)") 54 | assert version_range == MavenVersionRange( 55 | constraints=( 56 | VersionConstraint(comparator=">=", version=MavenVersion(string="2.0")), 57 | VersionConstraint(comparator="<=", version=MavenVersion(string="2.3.1")), 58 | VersionConstraint(comparator=">=", version=MavenVersion(string="2.4.0")), 59 | VersionConstraint(comparator="<", version=MavenVersion(string="2.12.2")), 60 | VersionConstraint(comparator=">=", version=MavenVersion(string="2.13.0")), 61 | VersionConstraint(comparator="<", version=MavenVersion(string="2.15.0")), 62 | ) 63 | ) 64 | 65 | 66 | def test_maven_version_range_from_native_for_multiple_pinned_versions_and_a_range(): 67 | version_range = MavenVersionRange.from_native("[2.0] , [2.4.0] , [2.13.0,2.15.0)") 68 | assert version_range == MavenVersionRange( 69 | constraints=( 70 | VersionConstraint(comparator="=", version=MavenVersion(string="2.0")), 71 | VersionConstraint(comparator="=", version=MavenVersion(string="2.4.0")), 72 | VersionConstraint(comparator=">=", version=MavenVersion(string="2.13.0")), 73 | VersionConstraint(comparator="<", version=MavenVersion(string="2.15.0")), 74 | ) 75 | ) 76 | -------------------------------------------------------------------------------- /tests/test_nuget.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # Copyright (c) .NET Foundation. All rights reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # pylint: disable=line-too-long 17 | # Many tests are ported from 18 | # https://github.com/NuGet/NuGet.Client/blob/dev/test/NuGet.Core.Tests/NuGet.Versioning.Test/VersionComparerTests.cs 19 | 20 | import unittest 21 | 22 | from univers.nuget import Version 23 | from univers.versions import NugetVersion 24 | 25 | 26 | class NuGetTest(unittest.TestCase): 27 | """NuGet version tests.""" 28 | 29 | def setUp(self): 30 | self.maxDiff = None # pylint: disable=invalid-name 31 | 32 | def check_order(self, comparison, first, second): 33 | """Check order.""" 34 | comparison(NugetVersion.build_value(first), NugetVersion.build_value(second)) 35 | 36 | def test_equals(self): 37 | """Test version equals.""" 38 | self.check_order(self.assertEqual, "1.0.0", "1.0.0") 39 | self.check_order(self.assertEqual, "1.0.0-BETA", "1.0.0-beta") 40 | self.check_order(self.assertEqual, "1.0.0-BETA+AA", "1.0.0-beta+aa") 41 | self.check_order(self.assertEqual, "1.0.0-BETA.X.y.5.77.0+AA", "1.0.0-beta.x.y.5.77.0+aa") 42 | self.check_order(self.assertEqual, "1.0.0", "1.0.0+beta") 43 | 44 | self.check_order(self.assertEqual, "1.0", "1.0.0.0") 45 | self.check_order(self.assertEqual, "1.0+test", "1.0.0.0") 46 | self.check_order(self.assertEqual, "1.0.0.1-1.2.A", "1.0.0.1-1.2.A") 47 | self.check_order(self.assertEqual, "1.0.01", "1.0.1.0") 48 | 49 | def test_not_equals(self): 50 | """Test version not equals.""" 51 | self.check_order(self.assertNotEqual, "1.0", "1.0.0.1") 52 | self.check_order(self.assertNotEqual, "1.0+test", "1.0.0.1") 53 | self.check_order(self.assertNotEqual, "1.0.0.1-1.2.A", "1.0.0.1-1.2.a.A+A") 54 | self.check_order(self.assertNotEqual, "1.0.01", "1.0.1.2") 55 | self.check_order(self.assertNotEqual, "0.0.0", "1.0.0") 56 | self.check_order(self.assertNotEqual, "1.1.0", "1.0.0") 57 | self.check_order(self.assertNotEqual, "1.0.1", "1.0.0") 58 | self.check_order(self.assertNotEqual, "1.0.0-BETA", "1.0.0-beta2") 59 | self.check_order(self.assertNotEqual, "1.0.0+AA", "1.0.0-beta+aa") 60 | self.check_order( 61 | self.assertNotEqual, "1.0.0-BETA.X.y.5.77.0+AA", "1.0.0-beta.x.y.5.79.0+aa" 62 | ) 63 | 64 | def test_less(self): 65 | """Test version less.""" 66 | self.check_order(self.assertLess, "0.0.0", "1.0.0") 67 | self.check_order(self.assertLess, "1.0.0", "1.1.0") 68 | self.check_order(self.assertLess, "1.0.0", "1.0.1") 69 | self.check_order(self.assertLess, "1.999.9999", "2.1.1") 70 | self.check_order(self.assertLess, "1.0.0-BETA", "1.0.0-beta2") 71 | self.check_order(self.assertLess, "1.0.0-beta+AA", "1.0.0+aa") 72 | self.check_order(self.assertLess, "1.0.0-BETA", "1.0.0-beta.1+AA") 73 | self.check_order(self.assertLess, "1.0.0-BETA.X.y.5.77.0+AA", "1.0.0-beta.x.y.5.79.0+aa") 74 | self.check_order(self.assertLess, "1.0.0-BETA.X.y.5.79.0+AA", "1.0.0-beta.x.y.5.790.0+abc") 75 | 76 | self.check_order(self.assertLess, "1.0.0", "1.0.0.1") 77 | self.check_order(self.assertLess, "1.0.0.1-alpha", "1.0.0.1-pre") 78 | self.check_order(self.assertLess, "1.0.0-pre", "1.0.0.1-alpha") 79 | self.check_order(self.assertLess, "1.0.0", "1.0.0.1-alpha") 80 | self.check_order(self.assertLess, "0.9.9.1", "1.0.0") 81 | 82 | def test_NugetVersion_hash(self): 83 | vers1 = NugetVersion("1.0.1+23") 84 | vers2 = NugetVersion("1.0.1+23") 85 | assert hash(vers1) == hash(vers2) 86 | 87 | def test_nuget_semver_hash(self): 88 | vers1 = Version.from_string("51.0.0+2") 89 | vers2 = Version.from_string("51.0.0+2") 90 | assert hash(vers1) == hash(vers2) 91 | -------------------------------------------------------------------------------- /tests/test_nuget.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_nuget.py 2 | package_url: pkg:github/google/osv@0.0.14#lib/osv/nuget_test.py 3 | download_url: https://raw.githubusercontent.com/google/osv/f5647ad2f746685b08debfba0293e442f2fb9945/lib/osv/nuget_test.py 4 | copyright: Copyright 2022 Google LLC 5 | 6 | license_expression: apache-2.0 7 | homepage_url: https://github.com/google/osv/ 8 | notice_file: test_nuget.py.NOTICE -------------------------------------------------------------------------------- /tests/test_nuget.py.NOTICE: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. -------------------------------------------------------------------------------- /tests/test_openssl_versort.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | from pathlib import Path 8 | 9 | from commoncode import testcase 10 | 11 | from tests import util_tests 12 | from univers.versions import OpensslVersion 13 | 14 | 15 | class TestOpenssl(testcase.FileBasedTesting): 16 | test_data_dir = str(Path(__file__).resolve().parent / "data" / "openssl") 17 | 18 | def test_openssl_version_sort(self): 19 | versions_file = self.get_test_loc("openssl_all_versions.txt") 20 | with open(versions_file) as f: 21 | all_openssl_versions = f.readlines() 22 | results = [OpensslVersion(x.strip()) for x in all_openssl_versions] 23 | results.sort() 24 | results = [version_to_dict(x) for x in results] 25 | expected_file = self.get_test_loc("openssl_versort_expected.json", must_exist=False) 26 | util_tests.check_results_against_json(results, expected_file) 27 | 28 | 29 | def version_to_dict(version): 30 | return { 31 | "string": version.string, 32 | "normalized_string": version.normalized_string, 33 | "value": str(version.value), 34 | } 35 | -------------------------------------------------------------------------------- /tests/test_pacman_vercmp.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2009-2020 by Pacman Development Team 2 | # Copyright (c) 2008 by Dan McGee 3 | # SPDX-License-Identifier: Apache-2.0 4 | # this has been significantly modified from the original 5 | # 6 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 7 | 8 | from univers.versions import ArchLinuxVersion 9 | 10 | 11 | def test_same_length(): 12 | assert ArchLinuxVersion("1.5.0") == ArchLinuxVersion("1.5.0") 13 | assert ArchLinuxVersion("1.5.1") > ArchLinuxVersion("1.5.0") 14 | 15 | 16 | def test_mixed_length(): 17 | assert ArchLinuxVersion("1.5.1") > ArchLinuxVersion("1.5") 18 | 19 | 20 | def test_with_pkgrel_same_length(): 21 | assert ArchLinuxVersion("1.5.0-1") == ArchLinuxVersion("1.5.0-1") 22 | assert ArchLinuxVersion("1.5.0-1") < ArchLinuxVersion("1.5.0-2") 23 | assert ArchLinuxVersion("1.5.0-1") < ArchLinuxVersion("1.5.1-1") 24 | assert ArchLinuxVersion("1.5.0-2") < ArchLinuxVersion("1.5.1-1") 25 | 26 | 27 | def test_alpha_dotted_versions(): 28 | assert ArchLinuxVersion("1.5.a") > ArchLinuxVersion("1.5") 29 | assert ArchLinuxVersion("1.5.b") > ArchLinuxVersion("1.5.a") 30 | assert ArchLinuxVersion("1.5.1") > ArchLinuxVersion("1.5.b") 31 | 32 | 33 | def test_with_epoch(): 34 | assert ArchLinuxVersion("0:1.0") == ArchLinuxVersion("0:1.0") 35 | assert ArchLinuxVersion("0:1.0") < ArchLinuxVersion("0:1.1") 36 | assert ArchLinuxVersion("1:1.0") > ArchLinuxVersion("0:1.0") 37 | assert ArchLinuxVersion("1:1.0") > ArchLinuxVersion("0:1.1") 38 | assert ArchLinuxVersion("1:1.0") < ArchLinuxVersion("2:1.1") 39 | 40 | 41 | def test_with_epoch_mixed_pkgrel(): 42 | assert ArchLinuxVersion("1:1.0") > ArchLinuxVersion("0:1.0-1") 43 | assert ArchLinuxVersion("1:1.0-1") > ArchLinuxVersion("0:1.1-1") 44 | 45 | 46 | def test_with_only_one_version_with_epoch(): 47 | assert ArchLinuxVersion("0:1.0") == ArchLinuxVersion("1.0") 48 | assert ArchLinuxVersion("0:1.0") < ArchLinuxVersion("1.1") 49 | assert ArchLinuxVersion("0:1.1") > ArchLinuxVersion("1.0") 50 | assert ArchLinuxVersion("1:1.0") > ArchLinuxVersion("1.0") 51 | assert ArchLinuxVersion("1:1.0") > ArchLinuxVersion("1.1") 52 | assert ArchLinuxVersion("1:1.1") > ArchLinuxVersion("1.1") 53 | 54 | 55 | def test_alpha_dot_and_dashes(): 56 | assert ArchLinuxVersion("1.5.b-1") == ArchLinuxVersion("1.5.b") 57 | assert ArchLinuxVersion("1.5-1") < ArchLinuxVersion("1.5.b") 58 | 59 | 60 | # def test_same_content_different_separators(): 61 | # assert ArchLinuxVersion("2.0") == ArchLinuxVersion("2_0") 62 | # assert ArchLinuxVersion("2.0_a") == ArchLinuxVersion("2_0.a") 63 | # assert ArchLinuxVersion("2.0a ") < ArchLinuxVersion("2.0.a") 64 | # assert ArchLinuxVersion("2___a") == ArchLinuxVersion("2_a") 65 | 66 | 67 | def test_with_pkgrel_mixed_length(): 68 | assert ArchLinuxVersion("1.5-1") < ArchLinuxVersion("1.5.1-1") 69 | assert ArchLinuxVersion("1.5-2") < ArchLinuxVersion("1.5.1-1") 70 | assert ArchLinuxVersion("1.5-2") < ArchLinuxVersion("1.5.1-2") 71 | 72 | 73 | def test_with_mixed_pkgrel_inclusion(): 74 | assert ArchLinuxVersion("1.5") == ArchLinuxVersion("1.5-1") 75 | assert ArchLinuxVersion("1.5-1") == ArchLinuxVersion("1.5") 76 | assert ArchLinuxVersion("1.1-1") == ArchLinuxVersion("1.1") 77 | assert ArchLinuxVersion("1.0-1") < ArchLinuxVersion("1.1") 78 | assert ArchLinuxVersion("1.1-1") > ArchLinuxVersion("1.0") 79 | 80 | 81 | def test_alphanumeric_versions(): 82 | assert ArchLinuxVersion("1.5b-1") < ArchLinuxVersion("1.5-1") 83 | assert ArchLinuxVersion("1.5b ") < ArchLinuxVersion("1.5 ") 84 | assert ArchLinuxVersion("1.5b-1") < ArchLinuxVersion("1.5 ") 85 | assert ArchLinuxVersion("1.5b ") < ArchLinuxVersion("1.5.1") 86 | 87 | 88 | def test_manpage_cases(): 89 | assert ArchLinuxVersion("1.0a") < ArchLinuxVersion("1.0alpha") 90 | assert ArchLinuxVersion("1.0alpha") < ArchLinuxVersion("1.0b") 91 | assert ArchLinuxVersion("1.0b") < ArchLinuxVersion("1.0beta") 92 | assert ArchLinuxVersion("1.0beta") < ArchLinuxVersion("1.0rc") 93 | assert ArchLinuxVersion("1.0rc") < ArchLinuxVersion("1.0") 94 | -------------------------------------------------------------------------------- /tests/test_pacman_vercmp.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_pacman_vercmp.py 2 | license_expression: apache-2.0 3 | download_url: https://git.archlinux.org/pacman.git/plain/test/util/vercmptest.sh 4 | copyright: | 5 | Copyright (c) 2009-2020 by Pacman Development Team 6 | Copyright (c) 2008 by Dan McGee 7 | 8 | package_url: pkg:pypi/pymaven-patch@0.2.9#tests/test_versioning.py 9 | notes: this subset of tests has been modified to tests version comparison and parsing 10 | homepage_url: https://git.archlinux.org/pacman.git 11 | notice_file: test_pacman_vercmp.py.NOTICE -------------------------------------------------------------------------------- /tests/test_pacman_vercmp.py.NOTICE: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2009-2020 by Pacman Development Team 2 | # Copyright (c) 2008 by Dan McGee 3 | # 4 | # This program is free software; you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation; either version 2 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . -------------------------------------------------------------------------------- /tests/test_pypi_version.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | from unittest import TestCase 8 | 9 | from packaging import version as packaging_version 10 | 11 | from univers.versions import InvalidVersion 12 | from univers.versions import PypiVersion 13 | 14 | # version comparison is already tested at: 15 | # https://github.com/pypa/packaging/blob/main/tests/test_version.py 16 | 17 | 18 | class TestPYPIVersion(TestCase): 19 | def test_constructor(self): 20 | pypi_version = PypiVersion("2.4.5") 21 | assert pypi_version.value == packaging_version.Version("2.4.5") 22 | self.assertRaises(InvalidVersion, PypiVersion, "2.//////") 23 | 24 | def test_compare(self): 25 | pypi_version = PypiVersion("2.4.5") 26 | assert pypi_version == PypiVersion("2.4.5") 27 | assert pypi_version != PypiVersion("2.4.6") 28 | assert pypi_version > PypiVersion("2.4.4") 29 | assert pypi_version >= PypiVersion("2.4.4") 30 | assert pypi_version < PypiVersion("2.4.6") 31 | assert pypi_version <= PypiVersion("2.4.6") 32 | assert PypiVersion("2.4") == PypiVersion("2.4.0") 33 | -------------------------------------------------------------------------------- /tests/test_python_semver.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | from unittest import TestCase 8 | 9 | import semver 10 | 11 | 12 | class TestPythonSemver(TestCase): 13 | def test_semver_hash(self): 14 | # python-semver doesn't consider build while hashing 15 | vers1 = semver.VersionInfo.parse("1.2.3") 16 | vers2 = semver.VersionInfo.parse("1.2.3+1") 17 | assert hash(vers1) == hash(vers2) 18 | -------------------------------------------------------------------------------- /tests/test_rpm.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | # SPDX-License-Identifier: MIT 3 | 4 | import unittest 5 | 6 | from univers.rpm import RpmVersion 7 | from univers.rpm import compare_rpm_versions 8 | 9 | 10 | class RpmMetadataTestCase(unittest.TestCase): 11 | def test_rpm_compare_versions(self): 12 | # Taste data was generated with: 13 | # rpmdev-vercmp 14 | # which also uses the same Python rpm lib. 15 | # 16 | # This number of test cases is excessive but does show how interesting 17 | # RPM version comparisons can be. 18 | test_evr_data = [ 19 | # Non-alphanumeric (except ~) are ignored for equality 20 | ((1, "2", "3"), (1, "2", "3"), 0), # 1:2-3 == 1:2-3 21 | ((1, ":2>", "3"), (1, "-2-", "3"), 0), # 1::2>-3 == 1:-2--3 22 | ((1, "2", "3?"), (1, "2", "?3"), 0), # 1:2-?3 == 1:2-3? 23 | # epoch takes precedence no matter what 24 | ((0, "2", "3"), (1, "2", "3"), -1), # 0:2-3 < 1:2-3 25 | ((1, "1", "3"), (0, "2", "3"), 1), # 1:1-3 > 0:2-3 26 | # version and release trigger the real comparison rules 27 | ((0, "1", "3"), (0, "2", "3"), -1), # 0:1-3 < 0:2-3 28 | ((0, "~2", "3"), (0, "1", "3"), -1), # 0:~2-3 < 0:1-3 29 | ((0, "~", "3"), (0, "1", "3"), -1), # 0:~-3 < 0:1-3 30 | ((0, "1", "3"), (0, "~", "3"), 1), # 0:1-3 > 0:~-3 31 | ((0, "^1", "3"), (0, "^", "3"), 1), # 0:^1-3 > 0:^-3 32 | ((0, "^", "3"), (0, "^1", "3"), -1), # 0:^-3 < 0:^1-3 33 | ((0, "0333", "b"), (0, "0033", "b"), 1), # 0:0333-b > 0:0033-b 34 | ((0, "0033", "b"), (0, "0333", "b"), -1), # 0:0033-b < 0:0333-b 35 | ((0, "3", "~~"), (0, "3", "~~~"), 1), # 0:3-~~ > 0:3-~~~ 36 | ((0, "3", "~~~"), (0, "3", "~~"), -1), # 0:3-~~~ < 0:3-~~ 37 | ((0, "3", "~~~"), (0, "3", "~~~"), 0), # 0:3-~~~ == 0:3-~~~ 38 | ((0, "a2aa", "b"), (0, "a2a", "b"), 1), # 0:a2aa-b > 0:a2a-b 39 | ((0, "33", "b"), (0, "aaa", "b"), 1), # 0:33-b > 0:aaa-b 40 | ] 41 | 42 | for evr1, evr2, expected in test_evr_data: 43 | a = RpmVersion(*evr1) 44 | b = RpmVersion(*evr2) 45 | self.assertEqual( 46 | compare_rpm_versions(a, b), 47 | expected, 48 | f"failed: {evr1}, {evr2}, {expected}", 49 | ) 50 | -------------------------------------------------------------------------------- /tests/test_rpm.py.antlir.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_rpm.py 2 | package_url: pkg:github/facebookincubator/antlir@120b20de91c55244ceacf61f82c5154a28446590#antlir/rpm/tests/test_rpm_metadata.py 3 | copyright: | 4 | Copyright (c) Facebook, Inc. and its affiliates. 5 | 6 | license_expression: mit 7 | homepage_url: https://github.com/facebookincubator/antlir/ 8 | 9 | notes: | 10 | This has been substantially modified and enhanced from the original code 11 | 12 | notice_file: test_rpm.py.antlir.NOTICE -------------------------------------------------------------------------------- /tests/test_rpm.py.mit.NOTICE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Facebook, Inc. and its affiliates. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_rpm_vercmp.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others 3 | # Copyright (c) SAS Institute Inc. 4 | # SPDX-License-Identifier: Apache-2.0 5 | # this has been significantly modified from the original 6 | # 7 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 8 | 9 | import io 10 | import os 11 | import re 12 | import unittest 13 | 14 | from univers import rpm as vercmp 15 | 16 | get_vercmp_test = re.compile( 17 | r"(.*)" r"RPMVERCMP\(" r"([^, ]*) *, *" r"([^, ]*) *, *" r"([^\)]*)" r"\).*" 18 | ).match 19 | 20 | 21 | def parse_rpmvercmp_tests(fobj, with_buggy_comparisons=True): 22 | """ 23 | Yield triples (version1, version2, comparison result) describing the RPM 24 | version comparison tests found in the rpmvercmp.at test file-like object at 25 | ``fobj`` Optionally include "buggy" upstream tests. 26 | """ 27 | for line in fobj: 28 | line = line.strip() 29 | if not line: 30 | continue 31 | if not with_buggy_comparisons and line.startswith("dnl"): 32 | continue 33 | match = get_vercmp_test(line) 34 | if not match: 35 | continue 36 | yield match.group(2), match.group(3), int(match.group(4)) 37 | 38 | 39 | class ParserTest(unittest.TestCase): 40 | def test_parse_without_buggy(self): 41 | fobj = io.StringIO( 42 | """ 43 | bla 44 | bla 45 | RPMVERCMP(1, 2, -1) 46 | dnl RPMVERCMP(1a, 1b, -1) 47 | """ 48 | ) 49 | parser = parse_rpmvercmp_tests(fobj, with_buggy_comparisons=False) 50 | expected = [("1", "2", -1)] 51 | assert list(parser) == expected 52 | 53 | def test_parse_with_buggy(self): 54 | fobj = io.StringIO( 55 | """ 56 | bla 57 | bla 58 | RPMVERCMP(1, 2, -1) 59 | dnl RPMVERCMP(1a, 1b, -1) 60 | """ 61 | ) 62 | parser = parse_rpmvercmp_tests(fobj, with_buggy_comparisons=True) 63 | expected = [("1", "2", -1), ("1a", "1b", -1)] 64 | assert list(parser) == expected 65 | 66 | 67 | class VersionCompareTest(unittest.TestCase): 68 | pass 69 | 70 | 71 | def create_test_function(ver1, ver2, expected, name): 72 | """ 73 | Return a test function closed on test arguments. 74 | """ 75 | 76 | def test_rpm_version(self): 77 | ver1_str = str(ver1).encode("utf-8") 78 | ver2_str = str(ver2).encode("utf-8") 79 | print(f"testing (ver1={ver1_str}, ver2={ver2_str}, expected=expected{expected}") 80 | result = vercmp.vercmp(ver1, ver2) 81 | if result != expected: 82 | assert result == (expected, ver1, ver2) 83 | 84 | test_rpm_version.__name__ = name 85 | return test_rpm_version 86 | 87 | 88 | def get_tests(): 89 | """ 90 | Yield test function from rpmvercmp.at data. 91 | """ 92 | test_file = os.path.join(os.path.dirname(__file__), "data", "rpmvercmp.at") 93 | 94 | with io.open(test_file, encoding="utf-8") as rpmtests: 95 | tests = list(parse_rpmvercmp_tests(rpmtests, with_buggy_comparisons=True)) 96 | for test_count, (ver1, ver2, expected) in enumerate(tests, 1): 97 | name = f"test_rpm_version_{test_count}" 98 | yield create_test_function(ver1, ver2, expected, name) 99 | 100 | # Make sure we still test something, in case the m4 file drops 101 | # content this will fail the test 102 | assert test_count > 20 103 | 104 | 105 | def build_tests(): 106 | """ 107 | Create tests from rpmvercmp.at data and attach them to a test class. 108 | """ 109 | for i, test_func in enumerate(get_tests()): 110 | name = f"test_rpm_version_{i}" 111 | setattr(VersionCompareTest, name, test_func) 112 | 113 | 114 | build_tests() 115 | -------------------------------------------------------------------------------- /tests/test_rpm_vercmp.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_rpm_vercmp.py 2 | license_expression: apache-2.0 3 | download_url: https://raw.githubusercontent.com/nexB/python-rpm-vercmp/15c5c29727c61d5d01e6a7d1a9b956f0d7af41bd/rpm_vercmp/tests/vercmp_test.py 4 | copyright: Copyright (c) SAS Institute Inc. 5 | package_url: pkg:pypi/rpm_vercmp@0.1.2#/rpm_vercmp/tests/vercmp_test.py 6 | notes: this subset of tests has been modified to tests version comparison and parsing 7 | homepage_url: https://github.com/nexB/python-rpm-vercmp 8 | notice_file: test_rpm_vercmp.py.NOTICE -------------------------------------------------------------------------------- /tests/test_rubygems_gem_requirement.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_rubygems_gem_requirement.py 2 | package_url: pkg:github.com/rubygems/rubygems@5768c2bc5542ce05466d379981a433ba1ee1e10a 3 | copyright: | 4 | Copyright (c) Chad Fowler, Rich Kilmer, Jim Weirich and others. 5 | Portions copyright (c) Engine Yard and Andre Arko 6 | 7 | license_expression: mit 8 | homepage_url: https://github.com/rubygems/rubygems 9 | 10 | notes: This has been substantially modified and enhanced from the original code 11 | to port tests cases to Python. The original license is a choice of MIT or Ruby 12 | license. We selected to use the MIT license here. 13 | 14 | notice_file: test_rubygems_gem_requirement.py.NOTICE -------------------------------------------------------------------------------- /tests/test_rubygems_gem_requirement.py.NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) Chad Fowler, Rich Kilmer, Jim Weirich and others. 2 | Portions copyright (c) Engine Yard and Andre Arko 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | 'Software'), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_rubygems_gem_version.py.ABOUT: -------------------------------------------------------------------------------- 1 | about_resource: test_rubygems_gem_version.py 2 | package_url: pkg:github.com/rubygems/rubygems@5768c2bc5542ce05466d379981a433ba1ee1e10a 3 | copyright: | 4 | Copyright (c) Chad Fowler, Rich Kilmer, Jim Weirich and others. 5 | Portions copyright (c) Engine Yard and Andre Arko 6 | 7 | license_expression: mit 8 | homepage_url: https://github.com/rubygems/rubygems 9 | 10 | notes: This has been substantially modified and enhanced from the original code 11 | to port tests cases to Python. The original license is a choice of MIT or Ruby 12 | license. We selected to use the MIT license here. 13 | 14 | notice_file: test_rubygems_gem_version.py.NOTICE -------------------------------------------------------------------------------- /tests/test_rubygems_gem_version.py.NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) Chad Fowler, Rich Kilmer, Jim Weirich and others. 2 | Portions copyright (c) Engine Yard and Andre Arko 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | 'Software'), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_skeleton_codestyle.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. All rights reserved. 3 | # ScanCode is a trademark of nexB Inc. 4 | # SPDX-License-Identifier: Apache-2.0 5 | # See http://www.apache.org/licenses/LICENSE-2.0 for the license text. 6 | # See https://github.com/aboutcode-org/skeleton for support or download. 7 | # See https://aboutcode.org for more information about nexB OSS projects. 8 | # 9 | 10 | import configparser 11 | import subprocess 12 | import unittest 13 | 14 | 15 | class BaseTests(unittest.TestCase): 16 | def test_skeleton_codestyle(self): 17 | """ 18 | This test shouldn't run in proliferated repositories. 19 | """ 20 | setup_cfg = configparser.ConfigParser() 21 | setup_cfg.read("setup.cfg") 22 | if setup_cfg["metadata"]["name"] != "skeleton": 23 | return 24 | 25 | args = "black --check -l 100 setup.py etc tests" 26 | try: 27 | subprocess.check_output(args.split()) 28 | except subprocess.CalledProcessError as e: 29 | print("===========================================================") 30 | print(e.output) 31 | print("===========================================================") 32 | raise Exception( 33 | "Black style check failed; please format the code using:\n" 34 | " python -m black -l 100 setup.py etc tests", 35 | e.output, 36 | ) from e 37 | -------------------------------------------------------------------------------- /tests/test_vers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (c) nexB Inc. and others. 4 | # SPDX-License-Identifier: Apache-2.0 5 | # 6 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 7 | 8 | import json 9 | import os 10 | import re 11 | import unittest 12 | from unittest.case import expectedFailure 13 | 14 | from univers.version_range import VersionRange 15 | 16 | 17 | def create_test_function( 18 | description, 19 | vers, 20 | canonical_vers, 21 | is_invalid, 22 | scheme, 23 | constraints, 24 | test_func_prefix="test_vers_", 25 | **kwargs 26 | ): 27 | """ 28 | Return a new (test function, test_name) where the test_function closed on 29 | test arguments. If is_error is True the tests are expected to raise an 30 | Exception. 31 | """ 32 | if is_invalid: 33 | 34 | def test_vers(self): 35 | try: 36 | VersionRange.from_string(vers) 37 | self.fail("Should raise a ValueError") 38 | except ValueError: 39 | pass 40 | 41 | try: 42 | VersionRange.from_string(canonical_vers) 43 | self.fail("Should raise a ValueError") 44 | except ValueError: 45 | pass 46 | 47 | else: 48 | 49 | def test_vers(self): 50 | # parsing the test canonical `vers` then re-building a `vers` from these 51 | # parsed components should return the test canonical `vers` 52 | cano = VersionRange.from_string(vers) 53 | assert canonical_vers == cano.to_string() 54 | 55 | # parsing the test `vers` should return the components parsed from the 56 | # test canonical `vers` 57 | parsed = VersionRange.from_string(canonical_vers) 58 | assert str(cano) == str(parsed) 59 | 60 | # parsing the test `vers` then re-building a `vers` from these parsed 61 | # components should return the test canonical `vers` 62 | assert canonical_vers == parsed.to_string() 63 | 64 | # building a `vers` from the test ranges should return the test 65 | # canonical `vers` 66 | built = VersionRange(scheme, constraints) 67 | assert canonical_vers == built.to_string() 68 | 69 | # create a good function name for use in test discovery 70 | if not description: 71 | description = vers 72 | if is_invalid: 73 | test_func_prefix += "is_invalid_" 74 | test_name = python_safe_name(test_func_prefix + description) 75 | test_vers.__name__ = test_name 76 | test_vers.funcname = test_name 77 | return test_vers, test_name 78 | 79 | 80 | def python_safe_name(s): 81 | """ 82 | Return a name derived from string `s` safe to use as a Python function name. 83 | 84 | For example: 85 | >>> s = "not `\\a /`good` -safe name ??" 86 | >>> assert python_safe_name(s) == 'not_good_safe_name' 87 | """ 88 | no_punctuation = re.compile(r"[\W_]", re.MULTILINE).sub 89 | s = s.lower() 90 | s = no_punctuation(" ", s) 91 | s = "_".join(s.split()) 92 | return s 93 | 94 | 95 | class VersTest(unittest.TestCase): 96 | pass 97 | 98 | 99 | def build_tests(clazz=VersTest, test_file="test-suite-data.json"): 100 | """ 101 | Dynamically build test methods for each vers test found in the `test_file` 102 | JSON file and attach a test method to the `clazz` class. 103 | """ 104 | test_data_dir = os.path.join(os.path.dirname(__file__), "data") 105 | test_file = os.path.join(test_data_dir, test_file) 106 | 107 | with open(test_file) as tf: 108 | tests_data = json.load(tf) 109 | for items in tests_data: 110 | test_func, test_name = create_test_function(**items) 111 | # TODO: remove once implemented 112 | test_func = expectedFailure(test_func) 113 | # attach that method to the class 114 | setattr(clazz, test_name, test_func) 115 | 116 | 117 | # build_tests() 118 | -------------------------------------------------------------------------------- /tests/test_version_comparison.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | import pytest 8 | 9 | from univers import versions 10 | 11 | 12 | @pytest.mark.parametrize( 13 | "version_class", 14 | [ 15 | versions.SemverVersion, 16 | versions.GolangVersion, 17 | versions.PypiVersion, 18 | versions.GenericVersion, 19 | versions.ComposerVersion, 20 | versions.NginxVersion, 21 | versions.ArchLinuxVersion, 22 | versions.DebianVersion, 23 | versions.RpmVersion, 24 | versions.MavenVersion, 25 | versions.NugetVersion, 26 | versions.GentooVersion, 27 | versions.OpensslVersion, 28 | versions.LegacyOpensslVersion, 29 | versions.AlpineLinuxVersion, 30 | ], 31 | ) 32 | def test_version_comparators_are_working(version_class): 33 | assert version_class("1.0.0") == version_class("1.0.0") 34 | assert version_class("1.0.0") != version_class("1.0.1") 35 | assert version_class("1.0.0") < version_class("1.0.1") 36 | assert version_class("1.0.1") > version_class("1.0.0") 37 | assert version_class("1.0.0") <= version_class("1.0.1") 38 | assert version_class("1.0.1") >= version_class("1.0.0") 39 | assert version_class("1.0.0") <= version_class("1.0.0") 40 | assert version_class("1.0.0") >= version_class("1.0.0") 41 | -------------------------------------------------------------------------------- /tests/test_version_constraint.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | import pytest 8 | 9 | from univers import versions 10 | from univers.version_constraint import VersionConstraint 11 | 12 | 13 | @pytest.mark.parametrize( 14 | "version, spec, expected", 15 | [ 16 | ("2.7", "<=3.4", True), 17 | ("2.7.1", "<=3.4", True), 18 | ("2.7.1rc1", "<=3.4", True), 19 | ("2.7.15", "<=3.4", True), 20 | ("2.7.15rc1", "<=3.4", True), 21 | ("2.7", ">=3.4", False), 22 | ("2.7.1", ">=3.4", False), 23 | ("2.7.1rc1", ">=3.4", False), 24 | ("2.7.15", ">=3.4", False), 25 | ("2.7.15rc1", ">=3.4", False), 26 | ("0.0.0", ">=1.0.0", False), 27 | ("1.2.3", ">=1.0.0", True), 28 | ("1.2.3b1", ">=1.0.0", True), 29 | ("1.0.1b1", ">=1.0.0", True), 30 | ("1.0.0b1", ">=1.0.0", False), 31 | ("1.0.0b1", ">=1.0.0b1", True), 32 | ], 33 | ) 34 | def test_pypi_comparison(version, spec, expected): 35 | version = versions.PypiVersion(version) 36 | constraint = VersionConstraint.from_string( 37 | string=spec, 38 | version_class=versions.PypiVersion, 39 | ) 40 | assert (version in constraint) is expected 41 | 42 | 43 | @pytest.mark.parametrize( 44 | "version, spec, expected", 45 | [ 46 | ("2.7.1", "<=3.4.3", True), 47 | ("1.1.0", ">1.0.0", True), 48 | ("2.0.0", "<=2.0.0", True), 49 | ("1.9999.9999", "<=2.0.0", True), 50 | ("0.2.9", "<=2.0.0", True), 51 | ("1.9999.9999", "<2.0.0", True), 52 | ("0.1.1-alpha", ">=0.1.1-beta", False), 53 | ("1.0.0+20130313144700", "=1.0.0+9999999999", False), 54 | ], 55 | ) 56 | def test_semver_comparison(version, spec, expected): 57 | version = versions.SemverVersion(version) 58 | constraint = VersionConstraint.from_string( 59 | string=spec, 60 | version_class=versions.SemverVersion, 61 | ) 62 | assert (version in constraint) is expected 63 | 64 | 65 | @pytest.mark.parametrize( 66 | "original, inverted", 67 | [ 68 | (">2.7.1", "<=2.7.1"), 69 | ("!=1.1.0", "=1.1.0"), 70 | ("=2.0.0", "!=2.0.0"), 71 | ("<=0.9999.9999", ">0.9999.9999"), 72 | (">=0.2.9", "<0.2.9"), 73 | ("<1.9999.9999", ">=1.9999.9999"), 74 | ("*", None), 75 | ], 76 | ) 77 | def test_invert_opertaion(original, inverted): 78 | constraint = VersionConstraint.from_string( 79 | string=original, 80 | version_class=versions.SemverVersion, 81 | ) 82 | if inverted: 83 | inverted_constraint = VersionConstraint.from_string( 84 | string=inverted, 85 | version_class=versions.SemverVersion, 86 | ) 87 | assert constraint.invert() == inverted_constraint 88 | else: 89 | assert constraint.invert() is None 90 | -------------------------------------------------------------------------------- /tests/util_tests.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) nexB Inc. and others. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. 6 | 7 | import json 8 | import os 9 | 10 | import saneyaml 11 | 12 | """ 13 | Shared testing utilities 14 | """ 15 | 16 | # Used for tests to regenerate fixtures with regen=True: run a test with this 17 | # env. var set to any value to regenarte expected result files. For example with: 18 | # "UNIVERS_REGEN_TEST_FIXTURES=yes pytest -vvs tests" 19 | UNIVERS_REGEN_TEST_FIXTURES = os.getenv("UNIVERS_REGEN_TEST_FIXTURES", False) 20 | 21 | 22 | def check_results_against_json( 23 | results, 24 | expected_file, 25 | regen=UNIVERS_REGEN_TEST_FIXTURES, 26 | ): 27 | """ 28 | Check the JSON-serializable mapping or sequence ``results`` against the 29 | expected data in the JSON ``expected_file`` 30 | 31 | If ``regen`` is True, the ``expected_file`` is overwritten with the 32 | ``results`` data. This is convenient for updating tests expectations. 33 | """ 34 | if regen: 35 | with open(expected_file, "w") as reg: 36 | json.dump(results, reg, indent=2, separators=(",", ": ")) 37 | expected = results 38 | else: 39 | with open(expected_file) as exp: 40 | expected = json.load(exp) 41 | 42 | # NOTE we redump the JSON as a YAML string for easier display of 43 | # the failures comparison/diff 44 | if results != expected: 45 | assert saneyaml.dump(results) == saneyaml.dump(expected) 46 | --------------------------------------------------------------------------------