From ae563d007fc7b1d2fd5e502a430016051fe46b98 Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Wed, 16 Sep 2020 17:20:17 +0800 Subject: [PATCH] Add an APT source This source follows the same flow apt itself uses to check for a package's version, so it can be used to check for any APT repository (not necessarily Debian or Ubuntu). --- docs/usage.rst | 26 +++++++++++++++++++++ nvchecker_source/apt.py | 52 +++++++++++++++++++++++++++++++++++++++++ tests/test_apt.py | 28 ++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 nvchecker_source/apt.py create mode 100644 tests/test_apt.py diff --git a/docs/usage.rst b/docs/usage.rst index 5b47529..44789e4 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -610,6 +610,32 @@ host This source returns tags and supports :ref:`list options`. +Check APT repository +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:: + + source = "apt" + +This enables you to track the update of an arbitary APT repository, without needing of apt and an updated local APT database. + +apt + Name of the APT package. + +mirror + URL of the repository (defaults to http://ftp.debian.org/debian/) + +suite + Name of the APT repository release (jessie, wheezy, etc, defaults to sid) + +repo + Name of the APT repository (main, contrib, etc, defaults to main) + +arch + Architecture of the repository (i386, amd64, etc, defaults to amd64) + +strip_release + Strip the release part. + Manually updating ~~~~~~~~~~~~~~~~~ :: diff --git a/nvchecker_source/apt.py b/nvchecker_source/apt.py new file mode 100644 index 0000000..51fc1b4 --- /dev/null +++ b/nvchecker_source/apt.py @@ -0,0 +1,52 @@ +# MIT licensed +# Copyright (c) 2020 Felix Yan , et al. + +from nvchecker.api import session, GetVersionError + +APT_RELEASE_URL = "%s/dists/%s/Release" +APT_PACKAGES_PATH = "%s/binary-%s/Packages%s" +APT_PACKAGES_URL = "%s/dists/%s/%s" +APT_PACKAGES_SUFFIX_PREFER = (".xz", ".gz", "") + +async def get_url(url): + res = await session.get(url) + data = res.body + + if url.endswith(".xz"): + import lzma + data = lzma.decompress(data) + elif url.endswith(".gz"): + import gzip + data = gzip.decompress(data) + + return data.decode('utf-8') + +async def get_version(name, conf, *, cache, **kwargs): + pkg = conf.get('apt') or name + mirror = conf.get('mirror', "http://ftp.debian.org/debian/") + suite = conf.get('suite', 'sid') + repo = conf.get('repo', 'main') + arch = conf.get('arch', 'amd64') + strip_release = conf.get('strip_release', False) + + apt_release = await cache.get(APT_RELEASE_URL % (mirror, suite), get_url) + for suffix in APT_PACKAGES_SUFFIX_PREFER: + packages_path = APT_PACKAGES_PATH % (repo, arch, suffix) + if " " + packages_path in apt_release: + break + else: + raise GetVersionError('Packages file not found in APT repository') + + apt_packages = await cache.get(APT_PACKAGES_URL % (mirror, suite, packages_path), get_url) + + pkg_found = False + for line in apt_packages.split("\n"): + if line == "Package: " + pkg: + pkg_found = True + if pkg_found and line.startswith("Version: "): + version = line[9:] + if strip_release: + version = version.split("-")[0] + return version + + raise GetVersionError('package not found in APT repository') diff --git a/tests/test_apt.py b/tests/test_apt.py new file mode 100644 index 0000000..d145237 --- /dev/null +++ b/tests/test_apt.py @@ -0,0 +1,28 @@ +# MIT licensed +# Copyright (c) 2020 lilydjwg , et al. +# Copyright (c) 2017 Felix Yan , et al. + +from flaky import flaky +import pytest +pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net] + +@flaky(max_runs=10) +async def test_apt(get_version): + assert await get_version("sigrok-firmware-fx2lafw", { + "source": "apt", + }) == "0.1.7-1" + +@flaky(max_runs=10) +async def test_apt_strip_release(get_version): + assert await get_version("sigrok-firmware-fx2lafw", { + "source": "apt", + "strip_release": 1, + }) == "0.1.7" + +@flaky(max_runs=10) +async def test_apt_deepin(get_version): + assert await get_version("sigrok-firmware-fx2lafw", { + "source": "apt", + "mirror": "https://community-packages.deepin.com/deepin", + "suite": "apricot", + }) == "0.1.6-1"