accept "partial" version arguments; resolve to latest matching version

This commit is contained in:
Fabio Valentini 2023-10-06 02:13:31 +02:00
parent 2f1505daf2
commit 52e2482019
No known key found for this signature in database
GPG key ID: 5AC5F572E5D410AF
4 changed files with 59 additions and 7 deletions

View file

@ -1,4 +1,4 @@
cargo2rpm>=0.1.8 cargo2rpm>=0.1.11
jinja2 jinja2
jsonschema jsonschema
pyparsing pyparsing

View file

@ -6,9 +6,9 @@ import tarfile
import tempfile import tempfile
from typing import Optional from typing import Optional
from cargo2rpm.metadata import Metadata from cargo2rpm.metadata import Metadata, Version, VersionReq
from rust2rpm.cratesio import download_crate from rust2rpm.cratesio import download_crate, query_available_versions
from rust2rpm import log from rust2rpm import log
from rust2rpm.patching import make_patches from rust2rpm.patching import make_patches
@ -196,6 +196,36 @@ def process_project_local(
return name, version, diffs, metadata, doc_files, license_files return name, version, diffs, metadata, doc_files, license_files
def resolve_version(crate: str, version: str) -> Optional[str]:
# try parsing version as actual version
try:
resolved_version = Version.parse(version)
return str(resolved_version)
except ValueError:
pass
# try parsing version as partial version
try:
parsed_version = VersionReq.parse(version)
log.info("Resolving partial version ...")
available_versions = query_available_versions(crate)
resolved_version = max(filter(lambda x: x in parsed_version, available_versions), default=None)
if resolved_version is None:
log.warn("Partial version does not match any available version.")
log.info("Falling back to latest version.")
return None
log.info(f"Partial version matched with available version: {resolved_version}")
return str(resolved_version)
except ValueError:
log.error(f"Invalid version: {version}")
log.info("Falling back to latest version.")
return None
def process_project( def process_project(
project: str, project: str,
version: Optional[str], version: Optional[str],
@ -220,8 +250,14 @@ def process_project(
else: else:
# project is just a crate name # project is just a crate name
name = project name = project
# download .crate from crates.io;
# set version to the latest stable version if it was not specified # download .crate from crates.io
if version:
# version or partial version was specified
resolved_version = resolve_version(project, version)
crate_file_path, version = download_crate(project, resolved_version)
else:
# no version was specified: download latest
crate_file_path, version = download_crate(project, version) crate_file_path, version = download_crate(project, version)
if store_crate: if store_crate:

View file

@ -6,6 +6,8 @@ from urllib.parse import urljoin
import requests import requests
import tqdm import tqdm
from cargo2rpm.semver import Version
from rust2rpm import log from rust2rpm import log
from rust2rpm.utils import remove_on_error from rust2rpm.utils import remove_on_error
@ -18,6 +20,20 @@ class NoVersionsError(Exception):
pass pass
def query_available_versions(crate: str, stable: bool = True) -> list[Version]:
url = urljoin(CRATES_IO_API_URL, f"crates/{crate}/versions")
req = requests.get(url, headers={"User-Agent": "rust2rpm"})
req.raise_for_status()
versions = req.json()["versions"]
parsed_versions = map(lambda x: Version.parse(x["num"]), filter(lambda x: not x["yanked"], versions))
if stable:
return list(filter(lambda x: x.pre is None, parsed_versions))
else:
return list(parsed_versions)
def query_newest_version(crate: str) -> str: def query_newest_version(crate: str) -> str:
url = urljoin(CRATES_IO_API_URL, f"crates/{crate}/versions") url = urljoin(CRATES_IO_API_URL, f"crates/{crate}/versions")
req = requests.get(url, headers={"User-Agent": "rust2rpm"}) req = requests.get(url, headers={"User-Agent": "rust2rpm"})

View file

@ -24,7 +24,7 @@ classifiers =
include_package_data = True include_package_data = True
packages = rust2rpm packages = rust2rpm
install_requires = install_requires =
cargo2rpm>=0.1.8 cargo2rpm>=0.1.11
jinja2 jinja2
jsonschema jsonschema
pyparsing pyparsing