-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #283 from dpeukert/master
feat: add opam source
- Loading branch information
Showing
3 changed files
with
112 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# MIT licensed | ||
# Copyright (c) 2024 Daniel Peukert <[email protected]>, et al. | ||
|
||
import asyncio | ||
from io import BytesIO | ||
import tarfile | ||
from typing import List | ||
|
||
from nvchecker.api import ( | ||
session, VersionResult, | ||
Entry, AsyncCache, | ||
KeyManager, RichResult | ||
) | ||
|
||
OPAM_REPO_INDEX_URL = "%s/index.tar.gz" | ||
OPAM_VERSION_PATH_PREFIX = "packages/%s/%s." | ||
OPAM_VERSION_PATH_SUFFIX = "/opam" | ||
|
||
OPAM_DEFAULT_REPO = 'https://opam.ocaml.org' | ||
OPAM_DEFAULT_REPO_VERSION_URL = "%s/packages/%s/%s.%s" | ||
|
||
def _decompress_and_list_files(data: bytes) -> List[str]: | ||
# Convert the bytes to a file object and get a list of files | ||
archive = tarfile.open(mode='r', fileobj=BytesIO(data)) | ||
return archive.getnames() | ||
|
||
async def get_files(url: str) -> List[str]: | ||
# Download the file and get its contents | ||
res = await session.get(url) | ||
data = res.body | ||
|
||
# Get the file list of the archive | ||
loop = asyncio.get_running_loop() | ||
return await loop.run_in_executor(None, _decompress_and_list_files, data) | ||
|
||
async def get_package_versions(files: List[str], pkg: str) -> List[str]: | ||
# Prepare the filename prefix based on the package name | ||
prefix = OPAM_VERSION_PATH_PREFIX % (pkg , pkg) | ||
|
||
# Only keep opam files that are relevant to the package we're working with | ||
filtered_files = [] | ||
|
||
for filename in files: | ||
if filename.startswith(prefix) and filename.endswith(OPAM_VERSION_PATH_SUFFIX): | ||
filtered_files.append(filename[len(prefix):-1*len(OPAM_VERSION_PATH_SUFFIX)]) | ||
|
||
return filtered_files | ||
|
||
async def get_version( | ||
name: str, conf: Entry, *, | ||
cache: AsyncCache, keymanager: KeyManager, | ||
**kwargs, | ||
): | ||
pkg = conf.get('pkg', name) | ||
repo = conf.get('repo', OPAM_DEFAULT_REPO).rstrip('/') | ||
|
||
# Get the list of files in the repo index (see https://opam.ocaml.org/doc/Manual.html#Repositories for repo structure) | ||
files = await cache.get(OPAM_REPO_INDEX_URL % repo, get_files) # type: ignore | ||
|
||
# Parse the version strings from the file names | ||
raw_versions = await get_package_versions(files, pkg) | ||
|
||
# Convert the version strings into RichResults () | ||
versions = [] | ||
for version in raw_versions: | ||
versions.append(RichResult( | ||
version = version, | ||
# There is no standardised URL scheme, so we only return an URL for the default registry | ||
url = OPAM_DEFAULT_REPO_VERSION_URL % (repo, pkg, pkg, version) if repo == OPAM_DEFAULT_REPO else None, | ||
)) | ||
return versions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# MIT licensed | ||
# Copyright (c) 2024 Daniel Peukert <[email protected]>, et al. | ||
|
||
import pytest | ||
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net] | ||
|
||
async def test_opam_official(get_version): | ||
assert await get_version("test", { | ||
"source": "opam", | ||
"pkg": "omigrate", | ||
}) == "0.3.2" | ||
|
||
async def test_opam_coq(get_version): | ||
assert await get_version("test", { | ||
"source": "opam", | ||
"repo": "https://coq.inria.fr/opam/released", | ||
"pkg": "coq-abp", | ||
}) == "8.10.0" | ||
|
||
async def test_opam_coq_trailing_slash(get_version): | ||
assert await get_version("test", { | ||
"source": "opam", | ||
"repo": "https://coq.inria.fr/opam/released/", | ||
"pkg": "coq-abp", | ||
}) == "8.10.0" |