From 957f60ce933fcc60306d3749c1201ad8beaeb8a9 Mon Sep 17 00:00:00 2001 From: Gerrod Date: Tue, 13 Aug 2024 08:33:04 -0400 Subject: [PATCH] Fix package name normalization for package pypi json view Merge pull request #717 from gerrod3/normalize-name-pypi (cherry picked from commit fc43b4b253dbec5931d6a230296942e4ba52ec3e) --- CHANGES/716.bugfix | 1 + pulp_python/app/models.py | 6 +++- pulp_python/app/pypi/views.py | 3 +- .../functional/api/test_download_content.py | 30 +++++++++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 CHANGES/716.bugfix diff --git a/CHANGES/716.bugfix b/CHANGES/716.bugfix new file mode 100644 index 00000000..344bbf23 --- /dev/null +++ b/CHANGES/716.bugfix @@ -0,0 +1 @@ +Fixed package name normalization issue preventing syncing packages with "." or "_" in their names. diff --git a/pulp_python/app/models.py b/pulp_python/app/models.py index 0e8b29fc..7f69aa9b 100644 --- a/pulp_python/app/models.py +++ b/pulp_python/app/models.py @@ -16,6 +16,7 @@ from pathlib import PurePath from .utils import ( + canonicalize_name, get_project_metadata_from_artifact, parse_project_metadata, python_content_to_json, @@ -84,6 +85,8 @@ def content_handler(self, path): ).latest("pulp_created") except ObjectDoesNotExist: return None + if len(path.parts) == 2: + path = PurePath(f"simple/{canonicalize_name(path.parts[1])}") rel_path = f"{path}/index.html" try: ca = ( @@ -100,8 +103,9 @@ def content_handler(self, path): return ArtifactResponse(ca.artifact, headers=headers) if name: + normalized = canonicalize_name(name) package_content = PythonPackageContent.objects.filter( - pk__in=self.publication.repository_version.content, name__iexact=name + pk__in=self.publication.repository_version.content, name__normalize=normalized ) # TODO Change this value to the Repo's serial value when implemented headers = {PYPI_LAST_SERIAL: str(PYPI_SERIAL_CONSTANT)} diff --git a/pulp_python/app/pypi/views.py b/pulp_python/app/pypi/views.py index ab276558..d2e34f6b 100644 --- a/pulp_python/app/pypi/views.py +++ b/pulp_python/app/pypi/views.py @@ -278,7 +278,8 @@ def retrieve(self, request, path, meta): elif meta_path.match("*/json"): name = meta_path.parts[0] if name: - package_content = content.filter(name__iexact=name) + normalized = canonicalize_name(name) + package_content = content.filter(name__normalize=normalized) # TODO Change this value to the Repo's serial value when implemented headers = {PYPI_LAST_SERIAL: str(PYPI_SERIAL_CONSTANT)} json_body = python_content_to_json(path, package_content, version=version) diff --git a/pulp_python/tests/functional/api/test_download_content.py b/pulp_python/tests/functional/api/test_download_content.py index 2f20cca0..236f2107 100644 --- a/pulp_python/tests/functional/api/test_download_content.py +++ b/pulp_python/tests/functional/api/test_download_content.py @@ -1,5 +1,6 @@ # coding=utf-8 """Tests that verify download of content served by Pulp.""" +import pytest import hashlib from random import choice from urllib.parse import urljoin @@ -149,3 +150,32 @@ def test_full_pulp_to_pulp_sync(self): repo3 = self._create_repo_and_sync_with_remote(remote) self.assertEqual(get_content_summary(repo3.to_dict()), PYTHON_MD_FIXTURE_SUMMARY) + + +@pytest.mark.parallel +def test_pulp2pulp_sync_with_oddities( + python_repo_with_sync, + python_remote_factory, + python_publication_factory, + python_distribution_factory, + python_content_summary, +): + """Test that Pulp can handle syncing packages with wierd names.""" + remote = python_remote_factory(includes=["oslo.utils"], url="https://pypi.org") + repo = python_repo_with_sync(remote) + distro = python_distribution_factory(repository=repo.pulp_href) + summary = python_content_summary(repository_version=repo.latest_version_href) + # Test pulp 2 pulp full sync w/ live pypi apis + remote2 = python_remote_factory(includes=[], url=distro.base_url) + repo2 = python_repo_with_sync(remote2) + summary2 = python_content_summary(repository_version=repo2.latest_version_href) + assert summary2.present["python.python"]["count"] > 0 + assert summary.present["python.python"]["count"] == summary2.present["python.python"]["count"] + # Test w/ publication + pub = python_publication_factory(repository=repo) + distro2 = python_distribution_factory(publication=pub.pulp_href) + remote3 = python_remote_factory(includes=[], url=distro2.base_url) + repo3 = python_repo_with_sync(remote3) + summary3 = python_content_summary(repository_version=repo3.latest_version_href) + assert summary3.present["python.python"]["count"] > 0 + assert summary.present["python.python"]["count"] == summary3.present["python.python"]["count"]