Skip to content

Commit

Permalink
Use semantic_version for version requirements
Browse files Browse the repository at this point in the history
Pythons pkg_resources Requirement introduced stricter PEP-440 checking
that is incompatible with ansible versions.

fixes pulp#1349
  • Loading branch information
mdellweg committed Feb 5, 2023
1 parent 545a82a commit ae44f7e
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 27 deletions.
2 changes: 2 additions & 0 deletions CHANGES/1349.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Switched to using ``semantic_version`` for version comparison, and stopped depending on
``setuptools``.
39 changes: 14 additions & 25 deletions pulp_ansible/app/tasks/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
from galaxy_importer.collection import sync_collection
from galaxy_importer.exceptions import ImporterError
from git import GitCommandError, Repo
from pkg_resources import Requirement
from pulpcore.plugin.models import (
Artifact,
ContentArtifact,
Expand All @@ -50,7 +49,8 @@
Stage,
)
from rest_framework.serializers import ValidationError
from semantic_version import Version
from semantic_version import SimpleSpec, Version
from semantic_version.base import Always

from pulp_ansible.app.constants import PAGE_SIZE
from pulp_ansible.app.models import (
Expand All @@ -74,6 +74,14 @@
log = logging.getLogger(__name__)


# semantic_version.SimpleSpec interpretes "*" as ">=0.0.0"
class AnsibleSpec(SimpleSpec):
def __init__(self, expression):
super().__init__(expression)
if self.expression == "*":
self.clause = Always()


async def declarative_content_from_git_repo(remote, url, git_ref=None, metadata_only=False):
"""Returns a DeclarativeContent for the Collection in a Git repository."""
if git_ref:
Expand Down Expand Up @@ -197,25 +205,6 @@ def sync(remote_pk, repository_pk, mirror, optimize):
).all().update(version_removed=repo_version)


def parse_requirements_entry(requirements_entry):
"""Parses a `RequirementsFileEntry` and returns a `Requirement` object."""
if requirements_entry.version == "*":
requirement_version = Requirement.parse("collection")
else:
# We need specifiers to enforce Requirement object criteria
# https://setuptools.readthedocs.io/en/latest/pkg_resources.html#requirements-parsing
# https://setuptools.readthedocs.io/en/latest/pkg_resources.html#requirement-methods-and-attributes
# If requirements_entry.version is a valid version, adds == specifier to the requirement
try:
Version(requirements_entry.version)
req_to_parse = f"collection=={requirements_entry.version}"
except ValueError:
req_to_parse = f"collection{requirements_entry.version}"

requirement_version = Requirement.parse(req_to_parse)
return requirement_version


def import_collection(
temp_file_pk,
repository_pk=None,
Expand Down Expand Up @@ -689,7 +678,7 @@ async def _fetch_paginated_collection_metadata(self, name, namespace, requiremen
else:
collection_versions = collection_versions_list["data"]
for collection_version in collection_versions:
if collection_version["version"] in requirement:
if Version(collection_version["version"]) in requirement:
version_num = collection_version["version"]
collection_version_detail_url = f"{collection_url}/versions/{version_num}/"
if collection_metadata["deprecated"]:
Expand Down Expand Up @@ -736,7 +725,7 @@ async def _read_from_downloaded_metadata(self, name, namespace, requirement):

all_versions_of_collection = self._unpaginated_collection_version_metadata[namespace][name]
for col_version_metadata in all_versions_of_collection:
if col_version_metadata["version"] in requirement:
if Version(col_version_metadata["version"]) in requirement:
if "git_url" in col_version_metadata and col_version_metadata["git_url"]:
tasks.append(
loop.create_task(
Expand All @@ -763,7 +752,7 @@ async def _read_from_downloaded_metadata(self, name, namespace, requirement):
await asyncio.gather(*tasks)

async def _fetch_collection_metadata(self, requirements_entry):
requirement_version = parse_requirements_entry(requirements_entry)
requirement_version = AnsibleSpec(requirements_entry.version)

namespace, name = requirements_entry.name.split(".")

Expand Down Expand Up @@ -814,7 +803,7 @@ async def _download_unpaginated_metadata(self):
except ValidationError:
pass
else:
excludes = {r.name: parse_requirements_entry(r) for r in excludes_list}
excludes = {r.name: AnsibleSpec(r.version) for r in excludes_list}
self.exclude_info.update(excludes)

if not isinstance(col_results, FileNotFoundError):
Expand Down
1 change: 1 addition & 0 deletions pulp_ansible/tests/functional/api/collection/test_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ def test_semver_sync(
# If this fails check that it is still upstream!
# TODO create a better local fixture to sync from.
assert "0.0.1-rerelease+meta" in versions
assert "0.0.0-rerelease+meta" in versions


@pytest.mark.parallel
Expand Down
2 changes: 0 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ async_lru>=1.0,<1.1
galaxy_importer>=0.4.5,<0.5
GitPython>=3.1.24,<3.2
jsonschema>=4.9,<4.18
packaging>=21.3,<24
pulpcore>=3.21.dev,<3.25
PyYAML>=5.4.1,<7.0
semantic_version>=2.9,<2.11
setuptools>=39.2,<66.2.0

0 comments on commit ae44f7e

Please sign in to comment.