Improve PyPI proxy and Package page UX
PyPI proxy improvements: - Set package format to "pypi" instead of "generic" - Extract version from filename and create PackageVersion record - Support .whl, .tar.gz, and .zip filename formats Package page UX overhaul: - Move upload to header button with modal - Simplify table: combine Tag/Version, remove Type and Artifact ID columns - Add row action menu (⋯) with: Copy ID, Ensure File, Create Tag, Dependencies - Remove cluttered "Download by Artifact ID" and "Create/Update Tag" sections - Add modals for upload and create tag actions - Cleaner, more scannable table layout
This commit is contained in:
@@ -17,7 +17,7 @@ from fastapi.responses import StreamingResponse, HTMLResponse
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from .database import get_db
|
||||
from .models import UpstreamSource, CachedUrl, Artifact, Project, Package, Tag
|
||||
from .models import UpstreamSource, CachedUrl, Artifact, Project, Package, Tag, PackageVersion
|
||||
from .storage import S3Storage, get_storage
|
||||
from .config import get_env_upstream_sources
|
||||
|
||||
@@ -30,6 +30,36 @@ PROXY_CONNECT_TIMEOUT = 30.0
|
||||
PROXY_READ_TIMEOUT = 60.0
|
||||
|
||||
|
||||
def _extract_pypi_version(filename: str) -> Optional[str]:
|
||||
"""Extract version from PyPI filename.
|
||||
|
||||
Handles formats like:
|
||||
- cowsay-6.1-py3-none-any.whl
|
||||
- cowsay-1.0.tar.gz
|
||||
- some_package-1.2.3.post1-cp39-cp39-linux_x86_64.whl
|
||||
"""
|
||||
# Remove extension
|
||||
if filename.endswith('.whl'):
|
||||
# Wheel: name-version-pytag-abitag-platform.whl
|
||||
parts = filename[:-4].split('-')
|
||||
if len(parts) >= 2:
|
||||
return parts[1]
|
||||
elif filename.endswith('.tar.gz'):
|
||||
# Source: name-version.tar.gz
|
||||
base = filename[:-7]
|
||||
# Find the last hyphen that precedes a version-like string
|
||||
match = re.match(r'^(.+)-(\d+.*)$', base)
|
||||
if match:
|
||||
return match.group(2)
|
||||
elif filename.endswith('.zip'):
|
||||
# Egg/zip: name-version.zip
|
||||
base = filename[:-4]
|
||||
match = re.match(r'^(.+)-(\d+.*)$', base)
|
||||
if match:
|
||||
return match.group(2)
|
||||
return None
|
||||
|
||||
|
||||
def _get_pypi_upstream_sources(db: Session) -> list[UpstreamSource]:
|
||||
"""Get all enabled upstream sources configured for PyPI."""
|
||||
# Get database sources
|
||||
@@ -507,6 +537,7 @@ async def pypi_download_file(
|
||||
project_id=system_project.id,
|
||||
name=normalized_name,
|
||||
description=f"PyPI package: {normalized_name}",
|
||||
format="pypi",
|
||||
)
|
||||
db.add(package)
|
||||
db.flush()
|
||||
@@ -525,6 +556,23 @@ async def pypi_download_file(
|
||||
)
|
||||
db.add(tag)
|
||||
|
||||
# Extract and create version
|
||||
version = _extract_pypi_version(filename)
|
||||
if version:
|
||||
existing_version = db.query(PackageVersion).filter(
|
||||
PackageVersion.package_id == package.id,
|
||||
PackageVersion.artifact_id == sha256,
|
||||
).first()
|
||||
if not existing_version:
|
||||
pkg_version = PackageVersion(
|
||||
package_id=package.id,
|
||||
artifact_id=sha256,
|
||||
version=version,
|
||||
version_source="filename",
|
||||
created_by="pypi-proxy",
|
||||
)
|
||||
db.add(pkg_version)
|
||||
|
||||
# Cache the URL mapping
|
||||
existing_cached = db.query(CachedUrl).filter(CachedUrl.url_hash == url_hash).first()
|
||||
if not existing_cached:
|
||||
|
||||
Reference in New Issue
Block a user