From 8554e7af792869b0a4edf087ba34407724cf2b26 Mon Sep 17 00:00:00 2001 From: Xaoc7 Date: Wed, 23 Nov 2022 17:52:24 +0200 Subject: [PATCH 1/7] Add support for working with Aptly Mirrors API --- aptly_api/client.py | 3 + aptly_api/parts/mirrors.py | 177 +++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 aptly_api/parts/mirrors.py diff --git a/aptly_api/client.py b/aptly_api/client.py index a4930e0..7d41ef7 100644 --- a/aptly_api/client.py +++ b/aptly_api/client.py @@ -12,6 +12,7 @@ from aptly_api.parts.repos import ReposAPISection from aptly_api.parts.files import FilesAPISection from aptly_api.parts.snapshots import SnapshotAPISection +from aptly_api.parts.mirrors import MirrorsAPISection class Client: @@ -31,6 +32,8 @@ def __init__(self, aptly_server_url: str, ssl_verify: Union[str, bool, None] = N ssl_cert=ssl_cert, http_auth=http_auth, timeout=timeout) self.snapshots = SnapshotAPISection(base_url=self.__aptly_server_url, ssl_verify=ssl_verify, ssl_cert=ssl_cert, http_auth=http_auth, timeout=timeout) + self.mirrors = MirrorsAPISection( + base_url=self.__aptly_server_url, ssl_verify=ssl_verify, ssl_cert=ssl_cert, http_auth=http_auth, timeout=timeout) @property def aptly_server_url(self) -> str: diff --git a/aptly_api/parts/mirrors.py b/aptly_api/parts/mirrors.py new file mode 100644 index 0000000..30e6a0f --- /dev/null +++ b/aptly_api/parts/mirrors.py @@ -0,0 +1,177 @@ +# -* encoding: utf-8 *- + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +from typing import NamedTuple, Sequence, Dict, Union, cast, Optional, List +from urllib.parse import quote + +from aptly_api.base import BaseAPIClient, AptlyAPIException +from aptly_api.parts.packages import Package, PackageAPISection + + +Mirror = NamedTuple('Mirror', [ + ('uuid', str), + ('name', str), + ('archiveroot', str), + ('distribution', str), + ('components', Sequence[str]), + ('architectures', Sequence[str]), + ('meta', Sequence[Dict[str, str]]), + ('downloaddate', str), + ('filter', str), + ('status', str), + ('worker_pid', int), + ('filter_with_deps', bool), + ('skip_component_check', bool), + ('skip_architecture_check', bool), + ('download_sources', bool), + ('download_udebs', bool), + ('download_installer', bool) +]) + + +class MirrorsAPISection(BaseAPIClient): + @staticmethod + def mirror_from_response(api_response: Dict[str, str]) -> Mirror: + return Mirror( + uuid=cast(str, api_response["UUID"]), + name=cast(str, api_response["Name"]), + archiveroot=cast(str, api_response["ArchiveRoot"]), + distribution=cast(str, api_response["Distribution"]), + components=cast(List[str], api_response["Components"]), + architectures=cast(List[str], api_response["Architectures"]), + meta=cast(List[Dict[str, str]], api_response["Meta"]), + downloaddate=cast(str, api_response["LastDownloadDate"]), + filter=cast(str, api_response["Filter"]), + status=cast(str, api_response["Status"]), + worker_pid=cast(int, api_response["WorkerPID"]), + filter_with_deps=cast(bool, api_response["FilterWithDeps"]), + skip_component_check=cast( + bool, api_response["SkipComponentCheck"]), + skip_architecture_check=cast( + bool, api_response["SkipArchitectureCheck"]), + download_sources=cast(bool, api_response["DownloadSources"]), + download_udebs=cast(bool, api_response["DownloadUdebs"]), + download_installer=cast(bool, api_response["DownloadInstaller"]) + ) + + def list(self) -> Sequence[Mirror]: + resp = self.do_get("api/mirrors") + + mirrors = [] + for mirr in resp.json(): + mirrors.append( + self.mirror_from_response(mirr) + ) + return mirrors + + def update(self, name: str, ignore_signatures: bool = False) -> Sequence[Mirror]: + body = {} + if ignore_signatures: + body["IgnoreSignatures"] = ignore_signatures + resp = self.do_put("api/mirrors/%s" % (quote(name)), json=body) + return resp + + def edit(self, name: str, newname: Optional[str] = None, archiveroot: Optional[str] = None, + filter: Optional[str] = None, architectures: Optional[List[str]] = None, + components: Optional[List[str]] = None, keyrings: Optional[List[str]] = None, + filter_with_deps: bool = False, skip_existing_packages: bool = False, + download_sources: bool = False, download_udebs: bool = False, + skip_component_check: bool = False, ignore_checksums: bool = False, + ignore_signatures: bool = False, force_update: bool = False) -> Mirror: + + body = {} + if newname: + body["Name"] = newname + if archiveroot: + body["ArchiveURL"] = archiveroot + if filter: + body["Filter"] = filter + if architectures: + body["Architectures"] = architectures + if components: + body["Components"] = components + if keyrings: + body["Keyrings"] = keyrings + if filter_with_deps: + body["FilterWithDeps"] = filter_with_deps + if download_sources: + body["DownloadSources"] = download_sources + if download_udebs: + body["DownloadUdebs"] = download_udebs + if skip_component_check: + body["SkipComponentCheck"] = skip_component_check + if ignore_checksums: + body["IgnoreChecksums"] = ignore_checksums + if ignore_signatures: + body["IgnoreSignatures"] = ignore_signatures + if skip_existing_packages: + body["SkipExistingPackages"] = skip_existing_packages + if force_update: + body["ForceUpdate"] = force_update + + resp = self.do_put("api/mirrors/%s" % (quote(name)), json=body) + return resp + + def show(self, name: str) -> Mirror: + resp = self.do_get("api/mirrors/%s" % (quote(name))) + + return self.mirror_from_response(resp.json()) + + def list_packages(self, name: str, query: Optional[str] = None, with_deps: bool = False, + detailed: bool = False) -> Sequence[Package]: + params = {} + if query is not None: + params["q"] = query + if with_deps: + params["withDeps"] = "1" + if detailed: + params["format"] = "details" + + resp = self.do_get("api/mirrors/%s/packages" % + quote(name), params=params) + ret = [] + for rpkg in resp.json(): + ret.append(PackageAPISection.package_from_response(rpkg)) + return ret + + def delete(self, name: str) -> Sequence[Mirror]: + resp = self.do_delete("api/mirrors/%s" % quote(name)) + return resp + + def create(self, name: str, archiveroot: str, distribution: Optional[str] = None, + filter: Optional[str] = None, components: Optional[List[str]] = None, + architectures: Optional[List[str]] = None, keyrings: Optional[List[str]] = None, + download_sources: bool = False, download_udebs: bool = False, + download_installer: bool = False, filter_with_deps: bool = False, + skip_component_check: bool = False, ignore_signatures: bool = False) -> Mirror: + data = { + "Name": name, + "ArchiveURL": archiveroot + } + + if ignore_signatures: + data["IgnoreSignatures"] = ignore_signatures + if keyrings: + data["Keyrings"] = keyrings + if filter: + data["Filter"] = filter + if distribution: + data["Distribution"] = distribution + if components: + data["Components"] = components + if architectures: + data["Architectures"] = architectures + if download_sources: + data["DownloadSources"] = download_sources + if download_udebs: + data["DownloadUdebs"] = download_udebs + if download_installer: + data["DownloadInstaller"] = download_installer + if skip_component_check: + data["SkipComponentCheck"] = skip_component_check + + resp = self.do_post("api/mirrors", json=data) + + return self.mirror_from_response(resp.json()) From 941c9d0dda669e4770cfdf77fba6ebe272cd0e8f Mon Sep 17 00:00:00 2001 From: Xaoc7 Date: Wed, 23 Nov 2022 17:53:52 +0200 Subject: [PATCH 2/7] Add support for making snapshots from mirrors --- aptly_api/parts/snapshots.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/aptly_api/parts/snapshots.py b/aptly_api/parts/snapshots.py index 7831d4d..3cf9376 100644 --- a/aptly_api/parts/snapshots.py +++ b/aptly_api/parts/snapshots.py @@ -12,6 +12,7 @@ from aptly_api.base import BaseAPIClient, AptlyAPIException from aptly_api.parts.packages import Package, PackageAPISection +from aptly_api.parts.mirrors import Mirror Snapshot = NamedTuple('Snapshot', [ ('name', str), @@ -49,7 +50,16 @@ def create_from_repo(self, reponame: str, snapshotname: str, description: Option if description is not None: body["Description"] = description - resp = self.do_post("api/repos/%s/snapshots" % quote(reponame), json=body) + resp = self.do_post("api/repos/%s/snapshots" % + quote(reponame), json=body) + return self.snapshot_from_response(resp.json()) + + def create_from_mirror(self, mirrorname: str, snapshotname: str, description: Optional[str] = None) -> Snapshot: + body = { + "Name": snapshotname + } + resp = self.do_post("api/mirrors/%s/snapshots" % + quote(mirrorname), json=body) return self.snapshot_from_response(resp.json()) def create_from_packages(self, snapshotname: str, description: Optional[str] = None, @@ -99,7 +109,8 @@ def list_packages(self, snapshotname: str, query: Optional[str] = None, with_dep if detailed: params["format"] = "details" - resp = self.do_get("api/snapshots/%s/packages" % quote(snapshotname), params=params) + resp = self.do_get("api/snapshots/%s/packages" % + quote(snapshotname), params=params) ret = [] for rpkg in resp.json(): ret.append(PackageAPISection.package_from_response(rpkg)) @@ -115,5 +126,6 @@ def delete(self, snapshotname: str, force: bool = False) -> None: self.do_delete("api/snapshots/%s" % quote(snapshotname), params=params) def diff(self, snapshot1: str, snapshot2: str) -> Sequence[Dict[str, str]]: - resp = self.do_get("api/snapshots/%s/diff/%s" % (quote(snapshot1), quote(snapshot2),)) + resp = self.do_get("api/snapshots/%s/diff/%s" % + (quote(snapshot1), quote(snapshot2),)) return cast(List[Dict[str, str]], resp.json()) From 74488b9fcedb7974f70d08d7ebc3d4f602ab6938 Mon Sep 17 00:00:00 2001 From: Xaoc7 Date: Thu, 24 Nov 2022 14:34:07 +0200 Subject: [PATCH 3/7] Adding unit-tests to cover mirrors API functionality: --- aptly_api/parts/mirrors.py | 44 +++--- aptly_api/tests/__init__.py | 1 + aptly_api/tests/test_mirrors.py | 240 ++++++++++++++++++++++++++++++ aptly_api/tests/test_snapshots.py | 29 +++- 4 files changed, 292 insertions(+), 22 deletions(-) create mode 100644 aptly_api/tests/test_mirrors.py diff --git a/aptly_api/parts/mirrors.py b/aptly_api/parts/mirrors.py index 30e6a0f..5ce1b75 100644 --- a/aptly_api/parts/mirrors.py +++ b/aptly_api/parts/mirrors.py @@ -13,14 +13,14 @@ Mirror = NamedTuple('Mirror', [ ('uuid', str), ('name', str), - ('archiveroot', str), + ('archiveurl', str), ('distribution', str), ('components', Sequence[str]), ('architectures', Sequence[str]), ('meta', Sequence[Dict[str, str]]), ('downloaddate', str), ('filter', str), - ('status', str), + ('status', int), ('worker_pid', int), ('filter_with_deps', bool), ('skip_component_check', bool), @@ -35,17 +35,27 @@ class MirrorsAPISection(BaseAPIClient): @staticmethod def mirror_from_response(api_response: Dict[str, str]) -> Mirror: return Mirror( - uuid=cast(str, api_response["UUID"]), + uuid=cast(str, api_response["UUID"] + ) if "UUID" in api_response else None, name=cast(str, api_response["Name"]), - archiveroot=cast(str, api_response["ArchiveRoot"]), - distribution=cast(str, api_response["Distribution"]), - components=cast(List[str], api_response["Components"]), - architectures=cast(List[str], api_response["Architectures"]), - meta=cast(List[Dict[str, str]], api_response["Meta"]), - downloaddate=cast(str, api_response["LastDownloadDate"]), - filter=cast(str, api_response["Filter"]), - status=cast(str, api_response["Status"]), - worker_pid=cast(int, api_response["WorkerPID"]), + archiveurl=cast( + str, api_response["ArchiveRoot"]), + distribution=cast( + str, api_response["Distribution"]) if "Distribution" in api_response else None, + components=cast(List[str], api_response["Components"] + )if "Components" in api_response else None, + architectures=cast(List[str], api_response["Architectures"] + ) if "Architectures" in api_response else None, + meta=cast(List[Dict[str, str]], api_response["Meta"] + ) if "Meta" in api_response else None, + downloaddate=cast( + str, api_response["LastDownloadDate"]) if "LastDownloadDate" in api_response else None, + filter=cast(str, api_response["Filter"] + ) if "Filter" in api_response else None, + status=cast(int, api_response["Status"] + )if "Status" in api_response else None, + worker_pid=cast( + int, api_response["WorkerPID"])if "WorkerPID" in api_response else None, filter_with_deps=cast(bool, api_response["FilterWithDeps"]), skip_component_check=cast( bool, api_response["SkipComponentCheck"]), @@ -73,7 +83,7 @@ def update(self, name: str, ignore_signatures: bool = False) -> Sequence[Mirror] resp = self.do_put("api/mirrors/%s" % (quote(name)), json=body) return resp - def edit(self, name: str, newname: Optional[str] = None, archiveroot: Optional[str] = None, + def edit(self, name: str, newname: Optional[str] = None, archiveurl: Optional[str] = None, filter: Optional[str] = None, architectures: Optional[List[str]] = None, components: Optional[List[str]] = None, keyrings: Optional[List[str]] = None, filter_with_deps: bool = False, skip_existing_packages: bool = False, @@ -84,8 +94,8 @@ def edit(self, name: str, newname: Optional[str] = None, archiveroot: Optional[s body = {} if newname: body["Name"] = newname - if archiveroot: - body["ArchiveURL"] = archiveroot + if archiveurl: + body["ArchiveURL"] = archiveurl if filter: body["Filter"] = filter if architectures: @@ -140,7 +150,7 @@ def delete(self, name: str) -> Sequence[Mirror]: resp = self.do_delete("api/mirrors/%s" % quote(name)) return resp - def create(self, name: str, archiveroot: str, distribution: Optional[str] = None, + def create(self, name: str, archiveurl: str, distribution: Optional[str] = None, filter: Optional[str] = None, components: Optional[List[str]] = None, architectures: Optional[List[str]] = None, keyrings: Optional[List[str]] = None, download_sources: bool = False, download_udebs: bool = False, @@ -148,7 +158,7 @@ def create(self, name: str, archiveroot: str, distribution: Optional[str] = None skip_component_check: bool = False, ignore_signatures: bool = False) -> Mirror: data = { "Name": name, - "ArchiveURL": archiveroot + "ArchiveURL": archiveurl } if ignore_signatures: diff --git a/aptly_api/tests/__init__.py b/aptly_api/tests/__init__.py index 83c4e19..a66487b 100644 --- a/aptly_api/tests/__init__.py +++ b/aptly_api/tests/__init__.py @@ -12,3 +12,4 @@ from .test_publish import * # noqa from .test_repos import * # noqa from .test_snapshots import * # noqa +from .test_mirrors import * diff --git a/aptly_api/tests/test_mirrors.py b/aptly_api/tests/test_mirrors.py new file mode 100644 index 0000000..d20f5ae --- /dev/null +++ b/aptly_api/tests/test_mirrors.py @@ -0,0 +1,240 @@ +# -* encoding: utf-8 *- + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +from typing import Any +from unittest.case import TestCase + +import requests_mock + +from aptly_api.base import AptlyAPIException +from aptly_api.parts.packages import Package +from aptly_api.parts.mirrors import MirrorsAPISection, Mirror + + +@requests_mock.Mocker(kw='rmock') +class MirrorsAPISectionTests(TestCase): + def __init__(self, *args: Any) -> None: + super().__init__(*args) + self.mapi = MirrorsAPISection("http://test/") + + def test_create(self, *, rmock: requests_mock.Mocker) -> None: + rmock.post("http://test/api/mirrors", + text='{"UUID": "2cb5985a-a23f-4a1f-8eb6-d5409193b4eb", "Name": "aptly-mirror", "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", "Distribution": "bionic", "Components": ["main"], "Architectures": ["amd64"], "Meta": {"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", "Components": "main", "Date": "Tue, 06 Apr 2021 21:05:41 UTC","Description": " Apt Repository for the Node.JS 10.x Branch", "Label": "Node Source", "Origin": "Node Source"}, "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "test", "Status": 0, "WorkerPID": 0, "FilterWithDeps": true, "SkipComponentCheck": true, "SkipArchitectureCheck": true, "DownloadSources": true, "DownloadUdebs": true, "DownloadInstaller": true}' + ) + self.assertEqual( + self.mapi.create(name="aptly-mirror", archiveurl='https://deb.nodesource.com/node_10.x/', + distribution='bionic', components=["main"], + architectures=["amd64"], + filter="test", download_udebs=True, + download_sources=True, download_installer=True, + skip_component_check=True, filter_with_deps=True, + keyrings="/path/to/keyring", ignore_signatures=True), + Mirror( + uuid='2cb5985a-a23f-4a1f-8eb6-d5409193b4eb', + name="aptly-mirror", + archiveurl="https://deb.nodesource.com/node_10.x/", + distribution='bionic', + components=["main"], + architectures=["amd64"], + downloaddate='0001-01-01T00:00:00Z', + meta={"Architectures": "i386 amd64 armhf arm64", + "Codename": "bionic", + "Components": "main", + "Date": "Tue, 06 Apr 2021 21:05:41 UTC", + "Description": " Apt Repository for the Node.JS 10.x Branch", + "Label": "Node Source", "Origin": "Node Source"}, + filter="test", + status=0, + worker_pid=0, + filter_with_deps=True, + skip_component_check=True, + skip_architecture_check=True, + download_sources=True, + download_udebs=True, + download_installer=True + + ) + ) + + def test_list(self, *, rmock: requests_mock.Mocker) -> None: + rmock.get("http://test/api/mirrors", + text='[{"UUID": "2cb5985a-a23f-4a1f-8eb6-d5409193b4eb", "Name": "aptly-mirror", "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", "Distribution": "bionic", "Components": ["main"], "Architectures": ["amd64"], "Meta": {"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", "Components": "main", "Date": "Tue, 06 Apr 2021 21:05:41 UTC","Description": " Apt Repository for the Node.JS 10.x Branch", "Label": "Node Source", "Origin": "Node Source"}, "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "", "Status": 0, "WorkerPID": 0, "FilterWithDeps": false, "SkipComponentCheck": false, "SkipArchitectureCheck": false, "DownloadSources": false, "DownloadUdebs": false, "DownloadInstaller": false}]' + ) + self.assertSequenceEqual( + self.mapi.list(), + [ + Mirror( + uuid='2cb5985a-a23f-4a1f-8eb6-d5409193b4eb', + name="aptly-mirror", + archiveurl="https://deb.nodesource.com/node_10.x/", + distribution='bionic', + components=["main"], + architectures=["amd64"], + downloaddate='0001-01-01T00:00:00Z', + meta={"Architectures": "i386 amd64 armhf arm64", + "Codename": "bionic", + "Components": "main", + "Date": "Tue, 06 Apr 2021 21:05:41 UTC", + "Description": " Apt Repository for the Node.JS 10.x Branch", + "Label": "Node Source", "Origin": "Node Source"}, + filter="", + status=0, + worker_pid=0, + filter_with_deps=False, + skip_component_check=False, + skip_architecture_check=False, + download_sources=False, + download_udebs=False, + download_installer=False + + ) + ] + ) + + def test_show(self, *, rmock: requests_mock.Mocker) -> None: + rmock.get("http://test/api/mirrors/aptly-mirror", + text='{"UUID": "2cb5985a-a23f-4a1f-8eb6-d5409193b4eb", "Name": "aptly-mirror", "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", "Distribution": "bionic", "Components": ["main"], "Architectures": ["amd64"], "Meta": {"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", "Components": "main", "Date": "Tue, 06 Apr 2021 21:05:41 UTC","Description": " Apt Repository for the Node.JS 10.x Branch", "Label": "Node Source", "Origin": "Node Source"}, "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "", "Status": 0, "WorkerPID": 0, "FilterWithDeps": false, "SkipComponentCheck": false, "SkipArchitectureCheck": false, "DownloadSources": false, "DownloadUdebs": false, "DownloadInstaller": false}' + ) + self.assertEqual( + self.mapi.show(name="aptly-mirror"), + Mirror( + uuid='2cb5985a-a23f-4a1f-8eb6-d5409193b4eb', + name="aptly-mirror", + archiveurl="https://deb.nodesource.com/node_10.x/", + distribution='bionic', + components=["main"], + architectures=["amd64"], + downloaddate='0001-01-01T00:00:00Z', + meta={"Architectures": "i386 amd64 armhf arm64", + "Codename": "bionic", + "Components": "main", + "Date": "Tue, 06 Apr 2021 21:05:41 UTC", + "Description": " Apt Repository for the Node.JS 10.x Branch", + "Label": "Node Source", "Origin": "Node Source"}, + filter="", + status=0, + worker_pid=0, + filter_with_deps=False, + skip_component_check=False, + skip_architecture_check=False, + download_sources=False, + download_udebs=False, + download_installer=False + + ) + ) + + def test_list_packages(self, *, rmock: requests_mock.Mocker) -> None: + rmock.get("http://test/api/mirrors/aptly-mirror/packages", + text='["Pamd64 nodejs 10.24.1-1nodesource1 1f74a6abf6acc572"]') + self.assertSequenceEqual( + self.mapi.list_packages( + name="aptly-mirror", query=("nodejs"), with_deps=True), + [ + Package( + key="Pamd64 nodejs 10.24.1-1nodesource1 1f74a6abf6acc572", + short_key=None, + files_hash=None, + fields=None, + ) + ], + ) + + def test_list_packages_details(self, *, rmock: requests_mock.Mocker) -> None: + rmock.get( + "http://test/api/mirrors/aptly-mirror/packages?format=details", + text="""[{ + "Architecture":"amd64", + "Conflicts": "nodejs-dev, nodejs-legacy, npm", + "Depends":"1libc6 (>= 2.9), libgcc1 (>= 1:3.4), libstdc++6 (>= 4.4.0), python-minimal, ca-certificates", + "Description":"Node.js event-based server-side javascript engine\\n", + "Filename":"nodejs_10.24.1-1nodesource1_amd64.deb", + "FilesHash":"1f74a6abf6acc572", + "Homepage":"https://nodejs.org", + "Installed-Size":"78630", + "Key":"Pamd64 nodejs 10.24.1-1nodesource1 1f74a6abf6acc572", + "License":"unknown", + "MD5sum":"6d9f0e30396cb6c20945ff6de2f9f322", + "Maintainer":"Ivan Iguaran ", + "Package":"nodejs", + "Priority":"optional", + "Provides":"nodejs-dev, nodejs-legacy, npm", + "SHA1":"a3bc5a29614eab366bb3644abb1e602b5c8953d5", + "SHA256":"4b374d16b536cf1a3963ddc4575ed2b68b28b0b5ea6eefe93c942dfc0ed35177", + "SHA512":"bf203bb319de0c5f7ed3b6ba69de39b1ea8b5086b872561379bd462dd93f07969ca64fa01ade01ff08fa13a4e5e28625b59292ba44bc01ba876ec95875630460", + "Section":"web", + "ShortKey":"Pamd64 nodejs 10.24.1-1nodesource1", + "Size":"15949164", + "Version":"10.24.1-1nodesource1" + }]""" + ) + self.assertEqual( + self.mapi.list_packages( + "aptly-mirror", detailed=True, with_deps=True, query="nodejs"), + [ + Package( + key='Pamd64 nodejs 10.24.1-1nodesource1 1f74a6abf6acc572', + short_key='Pamd64 nodejs 10.24.1-1nodesource1', + files_hash='1f74a6abf6acc572', + fields={ + 'Architecture': 'amd64', + 'Conflicts': 'nodejs-dev, nodejs-legacy, npm', + 'Depends': '1libc6 (>= 2.9), libgcc1 (>= 1:3.4), libstdc++6 (>= 4.4.0), python-minimal, ca-certificates', + 'Description': 'Node.js event-based server-side javascript engine\n', + 'Filename': 'nodejs_10.24.1-1nodesource1_amd64.deb', + 'FilesHash': '1f74a6abf6acc572', + 'Homepage': 'https://nodejs.org', + 'Installed-Size': '78630', + 'Key': 'Pamd64 nodejs 10.24.1-1nodesource1 1f74a6abf6acc572', + 'License': 'unknown', + 'MD5sum': '6d9f0e30396cb6c20945ff6de2f9f322', + 'Maintainer': 'Ivan Iguaran ', + 'Package': 'nodejs', + 'Priority': 'optional', + 'Provides': 'nodejs-dev, nodejs-legacy, npm', + 'SHA1': 'a3bc5a29614eab366bb3644abb1e602b5c8953d5', + 'SHA256': '4b374d16b536cf1a3963ddc4575ed2b68b28b0b5ea6eefe93c942dfc0ed35177', + 'SHA512': 'bf203bb319de0c5f7ed3b6ba69de39b1ea8b5086b872561379bd462dd93f0796' + '9ca64fa01ade01ff08fa13a4e5e28625b59292ba44bc01ba876ec95875630460', + 'Section': 'web', + 'ShortKey': 'Pamd64 nodejs 10.24.1-1nodesource1', + 'Size': '15949164', + 'Version': '10.24.1-1nodesource1' + } + ) + ] + ) + + def test_delete(self, *, rmock: requests_mock.Mocker) -> None: + with self.assertRaises(requests_mock.NoMockAddress): + self.mapi.delete(name="aptly-mirror") + + def test_update(self, *, rmock: requests_mock.Mocker) -> None: + with self.assertRaises(requests_mock.NoMockAddress): + self.mapi.update(name="aptly-mirror", ignore_signatures=True) + + def test_edit(self, *, rmock: requests_mock.Mocker) -> None: + with self.assertRaises(requests_mock.NoMockAddress): + self.mapi.edit(name="aptly-mirror", newname="aptly-mirror-renamed", + archiveurl='https://deb.nodesource.com/node_10.x/', + architectures=["i386", "amd64"], filter="test", + components=["main"], keyrings="/path/to/keyring", + skip_existing_packages=True, ignore_checksums=True, + download_udebs=True, download_sources=True, + skip_component_check=True, filter_with_deps=True, + ignore_signatures=True, force_update=True), + + def test_delete_validation(self, *, rmock: requests_mock.Mocker) -> None: + rmock.delete("http://test/api/mirrors/aptly-mirror") + self.mapi.delete(name="aptly-mirror") + + def test_update_validation(self, *, rmock: requests_mock.Mocker) -> None: + rmock.put("http://test/api/mirrors/aptly-mirror") + self.mapi.update(name="aptly-mirror") + + def test_edit_validation(self, *, rmock: requests_mock.Mocker) -> None: + rmock.put("http://test/api/mirrors/aptly-mirror", + text='{"Name":"aptly-mirror-bla", "IgnoreSignatures": true}') + self.mapi.edit(name="aptly-mirror", newname="aptly-mirror-renamed") diff --git a/aptly_api/tests/test_snapshots.py b/aptly_api/tests/test_snapshots.py index 4ef06d4..507ad20 100644 --- a/aptly_api/tests/test_snapshots.py +++ b/aptly_api/tests/test_snapshots.py @@ -34,13 +34,15 @@ def test_list(self, *, rmock: requests_mock.Mocker) -> None: name='stretch-security-1', description='Snapshot from mirror [stretch-security]: http://security.debian.org/debian-security/ ' 'stretch/updates', - created_at=iso8601.parse_date('2017-06-03T21:36:22.2692213Z') + created_at=iso8601.parse_date( + '2017-06-03T21:36:22.2692213Z') ), Snapshot( name='stretch-updates-1', description='Snapshot from mirror [stretch-updates]: http://ftp-stud.hs-esslingen.de/debian/ ' 'stretch-updates', - created_at=iso8601.parse_date('2017-06-03T21:36:22.431767659Z') + created_at=iso8601.parse_date( + '2017-06-03T21:36:22.431767659Z') ) ] ) @@ -136,8 +138,10 @@ def test_list_packages_details(self, *, rmock: requests_mock.Mocker) -> None: self.assertIsNotNone(expected.fields) self.assertDictEqual( - parsed.fields if parsed.fields else {}, # make sure that mypy doesn't error on this being potentially None - expected.fields if expected.fields else {}, # this can't happen unless Package.__init__ is fubared + # make sure that mypy doesn't error on this being potentially None + parsed.fields if parsed.fields else {}, + # this can't happen unless Package.__init__ is fubared + expected.fields if expected.fields else {}, ) def test_show(self, *, rmock: requests_mock.Mocker) -> None: @@ -159,7 +163,8 @@ def test_update(self, *, rmock: requests_mock.Mocker) -> None: text='{"Name":"aptly-repo-2","CreatedAt":"2017-06-03T23:43:40.275605639Z",' '"Description":"test"}') self.assertEqual( - self.sapi.update("aptly-repo-1", newname="aptly-repo-2", newdescription="test"), + self.sapi.update( + "aptly-repo-1", newname="aptly-repo-2", newdescription="test"), Snapshot( name='aptly-repo-2', description='test', @@ -200,3 +205,17 @@ def test_create_from_packages(self, *, rmock: requests_mock.Mocker) -> None: created_at=iso8601.parse_date('2017-06-07T14:19:07.706408213Z') ) ) + + def test_create_from_mirror(self, *, rmock: requests_mock.Mocker) -> None: + rmock.post("http://test/api/mirrors/aptly-mirror/snapshots", + text='{"Name":"aptly-mirror-snap","CreatedAt":"2022-11-29T21:43:45.275605639Z",' + '"Description":"Snapshot from local mirror [aptly-mirror]"}') + self.assertEqual( + self.sapi.create_from_mirror(mirrorname="aptly-mirror", snapshotname="aptly-mirror-snap", + description='Snapshot from local repo [aptly-repo]'), + Snapshot( + name='aptly-mirror-snap', + description='Snapshot from local mirror [aptly-mirror]', + created_at=iso8601.parse_date('2022-11-29T21:43:45.275605639Z') + ) + ) From 3112113a51a13ab33c468c19cfc8f20000eb4a9f Mon Sep 17 00:00:00 2001 From: Xaoc7 Date: Fri, 2 Dec 2022 18:31:26 +0200 Subject: [PATCH 4/7] Fixed code style according flake8: * ensure that there are no lines longer than 120 characters * fix imported but not used Union * fix imported but not used AptlyAPIException * fix imported but not used Mirror * removed trailing whitespaces * removed black lines at the end of files --- aptly_api/client.py | 3 +- aptly_api/parts/mirrors.py | 13 ++++--- aptly_api/parts/snapshots.py | 1 - aptly_api/tests/__init__.py | 2 +- aptly_api/tests/test_mirrors.py | 66 +++++++++++++++++++++++++++------ 5 files changed, 66 insertions(+), 19 deletions(-) diff --git a/aptly_api/client.py b/aptly_api/client.py index 7d41ef7..bfce19b 100644 --- a/aptly_api/client.py +++ b/aptly_api/client.py @@ -33,7 +33,8 @@ def __init__(self, aptly_server_url: str, ssl_verify: Union[str, bool, None] = N self.snapshots = SnapshotAPISection(base_url=self.__aptly_server_url, ssl_verify=ssl_verify, ssl_cert=ssl_cert, http_auth=http_auth, timeout=timeout) self.mirrors = MirrorsAPISection( - base_url=self.__aptly_server_url, ssl_verify=ssl_verify, ssl_cert=ssl_cert, http_auth=http_auth, timeout=timeout) + base_url=self.__aptly_server_url, ssl_verify=ssl_verify, + ssl_cert=ssl_cert, http_auth=http_auth, timeout=timeout) @property def aptly_server_url(self) -> str: diff --git a/aptly_api/parts/mirrors.py b/aptly_api/parts/mirrors.py index 5ce1b75..3bedc35 100644 --- a/aptly_api/parts/mirrors.py +++ b/aptly_api/parts/mirrors.py @@ -3,10 +3,10 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from typing import NamedTuple, Sequence, Dict, Union, cast, Optional, List +from typing import NamedTuple, Sequence, Dict, cast, Optional, List from urllib.parse import quote -from aptly_api.base import BaseAPIClient, AptlyAPIException +from aptly_api.base import BaseAPIClient from aptly_api.parts.packages import Package, PackageAPISection @@ -41,7 +41,8 @@ def mirror_from_response(api_response: Dict[str, str]) -> Mirror: archiveurl=cast( str, api_response["ArchiveRoot"]), distribution=cast( - str, api_response["Distribution"]) if "Distribution" in api_response else None, + str, api_response["Distribution"]) + if "Distribution" in api_response else None, components=cast(List[str], api_response["Components"] )if "Components" in api_response else None, architectures=cast(List[str], api_response["Architectures"] @@ -49,13 +50,15 @@ def mirror_from_response(api_response: Dict[str, str]) -> Mirror: meta=cast(List[Dict[str, str]], api_response["Meta"] ) if "Meta" in api_response else None, downloaddate=cast( - str, api_response["LastDownloadDate"]) if "LastDownloadDate" in api_response else None, + str, api_response["LastDownloadDate"]) + if "LastDownloadDate" in api_response else None, filter=cast(str, api_response["Filter"] ) if "Filter" in api_response else None, status=cast(int, api_response["Status"] )if "Status" in api_response else None, worker_pid=cast( - int, api_response["WorkerPID"])if "WorkerPID" in api_response else None, + int, api_response["WorkerPID"]) + if "WorkerPID" in api_response else None, filter_with_deps=cast(bool, api_response["FilterWithDeps"]), skip_component_check=cast( bool, api_response["SkipComponentCheck"]), diff --git a/aptly_api/parts/snapshots.py b/aptly_api/parts/snapshots.py index 3cf9376..0bff9a7 100644 --- a/aptly_api/parts/snapshots.py +++ b/aptly_api/parts/snapshots.py @@ -12,7 +12,6 @@ from aptly_api.base import BaseAPIClient, AptlyAPIException from aptly_api.parts.packages import Package, PackageAPISection -from aptly_api.parts.mirrors import Mirror Snapshot = NamedTuple('Snapshot', [ ('name', str), diff --git a/aptly_api/tests/__init__.py b/aptly_api/tests/__init__.py index a66487b..e551fe6 100644 --- a/aptly_api/tests/__init__.py +++ b/aptly_api/tests/__init__.py @@ -12,4 +12,4 @@ from .test_publish import * # noqa from .test_repos import * # noqa from .test_snapshots import * # noqa -from .test_mirrors import * +from .test_mirrors import * # noqa diff --git a/aptly_api/tests/test_mirrors.py b/aptly_api/tests/test_mirrors.py index d20f5ae..240bcfe 100644 --- a/aptly_api/tests/test_mirrors.py +++ b/aptly_api/tests/test_mirrors.py @@ -8,7 +8,6 @@ import requests_mock -from aptly_api.base import AptlyAPIException from aptly_api.parts.packages import Package from aptly_api.parts.mirrors import MirrorsAPISection, Mirror @@ -21,7 +20,21 @@ def __init__(self, *args: Any) -> None: def test_create(self, *, rmock: requests_mock.Mocker) -> None: rmock.post("http://test/api/mirrors", - text='{"UUID": "2cb5985a-a23f-4a1f-8eb6-d5409193b4eb", "Name": "aptly-mirror", "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", "Distribution": "bionic", "Components": ["main"], "Architectures": ["amd64"], "Meta": {"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", "Components": "main", "Date": "Tue, 06 Apr 2021 21:05:41 UTC","Description": " Apt Repository for the Node.JS 10.x Branch", "Label": "Node Source", "Origin": "Node Source"}, "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "test", "Status": 0, "WorkerPID": 0, "FilterWithDeps": true, "SkipComponentCheck": true, "SkipArchitectureCheck": true, "DownloadSources": true, "DownloadUdebs": true, "DownloadInstaller": true}' + text="""{"UUID": "2cb5985a-a23f-4a1f-8eb6-d5409193b4eb", + "Name": "aptly-mirror", + "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", + "Distribution": "bionic", "Components": ["main"], + "Architectures": ["amd64"], + "Meta": {"Architectures": "i386 amd64 armhf arm64", + "Codename": "bionic", "Components": "main", + "Date": "Tue, 06 Apr 2021 21:05:41 UTC", + "Description": " Apt Repository for the Node.JS 10.x Branch", + "Label": "Node Source", "Origin": "Node Source"}, + "LastDownloadDate": "0001-01-01T00:00:00Z", + "Filter": "test", "Status": 0, "WorkerPID": 0, + "FilterWithDeps": true, "SkipComponentCheck": true, + "SkipArchitectureCheck": true, "DownloadSources": true, + "DownloadUdebs": true, "DownloadInstaller": true}""" ) self.assertEqual( self.mapi.create(name="aptly-mirror", archiveurl='https://deb.nodesource.com/node_10.x/', @@ -60,7 +73,21 @@ def test_create(self, *, rmock: requests_mock.Mocker) -> None: def test_list(self, *, rmock: requests_mock.Mocker) -> None: rmock.get("http://test/api/mirrors", - text='[{"UUID": "2cb5985a-a23f-4a1f-8eb6-d5409193b4eb", "Name": "aptly-mirror", "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", "Distribution": "bionic", "Components": ["main"], "Architectures": ["amd64"], "Meta": {"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", "Components": "main", "Date": "Tue, 06 Apr 2021 21:05:41 UTC","Description": " Apt Repository for the Node.JS 10.x Branch", "Label": "Node Source", "Origin": "Node Source"}, "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "", "Status": 0, "WorkerPID": 0, "FilterWithDeps": false, "SkipComponentCheck": false, "SkipArchitectureCheck": false, "DownloadSources": false, "DownloadUdebs": false, "DownloadInstaller": false}]' + text="""[{"UUID": "2cb5985a-a23f-4a1f-8eb6-d5409193b4eb", + "Name": "aptly-mirror", + "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", + "Distribution": "bionic", "Components": ["main"], + "Architectures": ["amd64"], + "Meta": {"Architectures": "i386 amd64 armhf arm64", + "Codename": "bionic", "Components": "main", + "Date": "Tue, 06 Apr 2021 21:05:41 UTC", + "Description": " Apt Repository for the Node.JS 10.x Branch", + "Label": "Node Source", "Origin": "Node Source"}, + "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "", + "Status": 0, "WorkerPID": 0, "FilterWithDeps": false, + "SkipComponentCheck": false, "SkipArchitectureCheck": false, + "DownloadSources": false, "DownloadUdebs": false, + "DownloadInstaller": false}]""" ) self.assertSequenceEqual( self.mapi.list(), @@ -95,7 +122,21 @@ def test_list(self, *, rmock: requests_mock.Mocker) -> None: def test_show(self, *, rmock: requests_mock.Mocker) -> None: rmock.get("http://test/api/mirrors/aptly-mirror", - text='{"UUID": "2cb5985a-a23f-4a1f-8eb6-d5409193b4eb", "Name": "aptly-mirror", "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", "Distribution": "bionic", "Components": ["main"], "Architectures": ["amd64"], "Meta": {"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", "Components": "main", "Date": "Tue, 06 Apr 2021 21:05:41 UTC","Description": " Apt Repository for the Node.JS 10.x Branch", "Label": "Node Source", "Origin": "Node Source"}, "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "", "Status": 0, "WorkerPID": 0, "FilterWithDeps": false, "SkipComponentCheck": false, "SkipArchitectureCheck": false, "DownloadSources": false, "DownloadUdebs": false, "DownloadInstaller": false}' + text="""{"UUID": "2cb5985a-a23f-4a1f-8eb6-d5409193b4eb", + "Name": "aptly-mirror", + "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", + "Distribution": "bionic", "Components": ["main"], + "Architectures": ["amd64"], + "Meta": {"Architectures": "i386 amd64 armhf arm64", + "Codename": "bionic", "Components": "main", + "Date": "Tue, 06 Apr 2021 21:05:41 UTC", + "Description": " Apt Repository for the Node.JS 10.x Branch", + "Label": "Node Source", "Origin": "Node Source"}, + "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "", + "Status": 0, "WorkerPID": 0, "FilterWithDeps": false, + "SkipComponentCheck": false, "SkipArchitectureCheck": false, + "DownloadSources": false, "DownloadUdebs": false, + "DownloadInstaller": false}""" ) self.assertEqual( self.mapi.show(name="aptly-mirror"), @@ -148,8 +189,9 @@ def test_list_packages_details(self, *, rmock: requests_mock.Mocker) -> None: text="""[{ "Architecture":"amd64", "Conflicts": "nodejs-dev, nodejs-legacy, npm", - "Depends":"1libc6 (>= 2.9), libgcc1 (>= 1:3.4), libstdc++6 (>= 4.4.0), python-minimal, ca-certificates", - "Description":"Node.js event-based server-side javascript engine\\n", + "Depends":"1libc6 (>= 2.9), libgcc1 (>= 1:3.4),""" + """ libstdc++6 (>= 4.4.0), python-minimal, ca-certificates", + "Description":" Node.js event-based server-side javascript engine\\n", "Filename":"nodejs_10.24.1-1nodesource1_amd64.deb", "FilesHash":"1f74a6abf6acc572", "Homepage":"https://nodejs.org", @@ -163,7 +205,8 @@ def test_list_packages_details(self, *, rmock: requests_mock.Mocker) -> None: "Provides":"nodejs-dev, nodejs-legacy, npm", "SHA1":"a3bc5a29614eab366bb3644abb1e602b5c8953d5", "SHA256":"4b374d16b536cf1a3963ddc4575ed2b68b28b0b5ea6eefe93c942dfc0ed35177", - "SHA512":"bf203bb319de0c5f7ed3b6ba69de39b1ea8b5086b872561379bd462dd93f07969ca64fa01ade01ff08fa13a4e5e28625b59292ba44bc01ba876ec95875630460", + "SHA512":"bf203bb319de0c5f7ed3b6ba69de39b1ea8b5086b872561379bd462dd93f0796""" + """9ca64fa01ade01ff08fa13a4e5e28625b59292ba44bc01ba876ec95875630460", "Section":"web", "ShortKey":"Pamd64 nodejs 10.24.1-1nodesource1", "Size":"15949164", @@ -179,10 +222,11 @@ def test_list_packages_details(self, *, rmock: requests_mock.Mocker) -> None: short_key='Pamd64 nodejs 10.24.1-1nodesource1', files_hash='1f74a6abf6acc572', fields={ - 'Architecture': 'amd64', + "Architecture": "amd64", 'Conflicts': 'nodejs-dev, nodejs-legacy, npm', - 'Depends': '1libc6 (>= 2.9), libgcc1 (>= 1:3.4), libstdc++6 (>= 4.4.0), python-minimal, ca-certificates', - 'Description': 'Node.js event-based server-side javascript engine\n', + 'Depends': '1libc6 (>= 2.9), libgcc1 (>= 1:3.4), ' + 'libstdc++6 (>= 4.4.0), python-minimal, ca-certificates', + 'Description': ' Node.js event-based server-side javascript engine\n', 'Filename': 'nodejs_10.24.1-1nodesource1_amd64.deb', 'FilesHash': '1f74a6abf6acc572', 'Homepage': 'https://nodejs.org', @@ -197,7 +241,7 @@ def test_list_packages_details(self, *, rmock: requests_mock.Mocker) -> None: 'SHA1': 'a3bc5a29614eab366bb3644abb1e602b5c8953d5', 'SHA256': '4b374d16b536cf1a3963ddc4575ed2b68b28b0b5ea6eefe93c942dfc0ed35177', 'SHA512': 'bf203bb319de0c5f7ed3b6ba69de39b1ea8b5086b872561379bd462dd93f0796' - '9ca64fa01ade01ff08fa13a4e5e28625b59292ba44bc01ba876ec95875630460', + '9ca64fa01ade01ff08fa13a4e5e28625b59292ba44bc01ba876ec95875630460', 'Section': 'web', 'ShortKey': 'Pamd64 nodejs 10.24.1-1nodesource1', 'Size': '15949164', From 41c580d7781933b75304de09ec25e7d41f2ffb5b Mon Sep 17 00:00:00 2001 From: Xaoc7 Date: Tue, 6 Dec 2022 08:11:47 +0200 Subject: [PATCH 5/7] Apply changes to mitigate mypy reported errors: * Incompatible type assignments * Incompatible types for arguments * Incompatible return values --- aptly_api/parts/mirrors.py | 42 +++++++------- aptly_api/tests/test_mirrors.py | 98 ++++++++++++++++----------------- 2 files changed, 70 insertions(+), 70 deletions(-) diff --git a/aptly_api/parts/mirrors.py b/aptly_api/parts/mirrors.py index 3bedc35..d833bbb 100644 --- a/aptly_api/parts/mirrors.py +++ b/aptly_api/parts/mirrors.py @@ -3,7 +3,7 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from typing import NamedTuple, Sequence, Dict, cast, Optional, List +from typing import NamedTuple, Sequence, Dict, cast, Optional, List, Union from urllib.parse import quote from aptly_api.base import BaseAPIClient @@ -11,17 +11,17 @@ Mirror = NamedTuple('Mirror', [ - ('uuid', str), + ('uuid', Optional[str]), ('name', str), ('archiveurl', str), - ('distribution', str), - ('components', Sequence[str]), - ('architectures', Sequence[str]), - ('meta', Sequence[Dict[str, str]]), - ('downloaddate', str), - ('filter', str), - ('status', int), - ('worker_pid', int), + ('distribution', Optional[str]), + ('components', Optional[Sequence[str]]), + ('architectures', Optional[Sequence[str]]), + ('meta', Optional[Sequence[Dict[str, str]]]), + ('downloaddate', Optional[str]), + ('filter', Optional[str]), + ('status', Optional[int]), + ('worker_pid', Optional[int]), ('filter_with_deps', bool), ('skip_component_check', bool), ('skip_architecture_check', bool), @@ -30,6 +30,9 @@ ('download_installer', bool) ]) +T_BodyDict = Dict[str, Union[str, bool, Sequence[Dict[str, str]], + Sequence[str], Dict[str, Union[bool, str]]]] + class MirrorsAPISection(BaseAPIClient): @staticmethod @@ -79,12 +82,11 @@ def list(self) -> Sequence[Mirror]: ) return mirrors - def update(self, name: str, ignore_signatures: bool = False) -> Sequence[Mirror]: + def update(self, name: str, ignore_signatures: bool = False) -> None: body = {} if ignore_signatures: body["IgnoreSignatures"] = ignore_signatures - resp = self.do_put("api/mirrors/%s" % (quote(name)), json=body) - return resp + self.do_put("api/mirrors/%s" % (quote(name)), json=body) def edit(self, name: str, newname: Optional[str] = None, archiveurl: Optional[str] = None, filter: Optional[str] = None, architectures: Optional[List[str]] = None, @@ -92,9 +94,9 @@ def edit(self, name: str, newname: Optional[str] = None, archiveurl: Optional[st filter_with_deps: bool = False, skip_existing_packages: bool = False, download_sources: bool = False, download_udebs: bool = False, skip_component_check: bool = False, ignore_checksums: bool = False, - ignore_signatures: bool = False, force_update: bool = False) -> Mirror: + ignore_signatures: bool = False, force_update: bool = False) -> None: - body = {} + body = {} # type: T_BodyDict if newname: body["Name"] = newname if archiveurl: @@ -124,8 +126,7 @@ def edit(self, name: str, newname: Optional[str] = None, archiveurl: Optional[st if force_update: body["ForceUpdate"] = force_update - resp = self.do_put("api/mirrors/%s" % (quote(name)), json=body) - return resp + self.do_put("api/mirrors/%s" % (quote(name)), json=body) def show(self, name: str) -> Mirror: resp = self.do_get("api/mirrors/%s" % (quote(name))) @@ -149,9 +150,8 @@ def list_packages(self, name: str, query: Optional[str] = None, with_deps: bool ret.append(PackageAPISection.package_from_response(rpkg)) return ret - def delete(self, name: str) -> Sequence[Mirror]: - resp = self.do_delete("api/mirrors/%s" % quote(name)) - return resp + def delete(self, name: str) -> None: + self.do_delete("api/mirrors/%s" % quote(name)) def create(self, name: str, archiveurl: str, distribution: Optional[str] = None, filter: Optional[str] = None, components: Optional[List[str]] = None, @@ -162,7 +162,7 @@ def create(self, name: str, archiveurl: str, distribution: Optional[str] = None, data = { "Name": name, "ArchiveURL": archiveurl - } + } # type: T_BodyDict if ignore_signatures: data["IgnoreSignatures"] = ignore_signatures diff --git a/aptly_api/tests/test_mirrors.py b/aptly_api/tests/test_mirrors.py index 240bcfe..07c1103 100644 --- a/aptly_api/tests/test_mirrors.py +++ b/aptly_api/tests/test_mirrors.py @@ -16,7 +16,7 @@ class MirrorsAPISectionTests(TestCase): def __init__(self, *args: Any) -> None: super().__init__(*args) - self.mapi = MirrorsAPISection("http://test/") + self.miapi = MirrorsAPISection("http://test/") def test_create(self, *, rmock: requests_mock.Mocker) -> None: rmock.post("http://test/api/mirrors", @@ -25,25 +25,25 @@ def test_create(self, *, rmock: requests_mock.Mocker) -> None: "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", "Distribution": "bionic", "Components": ["main"], "Architectures": ["amd64"], - "Meta": {"Architectures": "i386 amd64 armhf arm64", + "Meta": [{"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", "Components": "main", "Date": "Tue, 06 Apr 2021 21:05:41 UTC", "Description": " Apt Repository for the Node.JS 10.x Branch", - "Label": "Node Source", "Origin": "Node Source"}, + "Label": "Node Source", "Origin": "Node Source"}], "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "test", "Status": 0, "WorkerPID": 0, "FilterWithDeps": true, "SkipComponentCheck": true, "SkipArchitectureCheck": true, "DownloadSources": true, "DownloadUdebs": true, "DownloadInstaller": true}""" ) - self.assertEqual( - self.mapi.create(name="aptly-mirror", archiveurl='https://deb.nodesource.com/node_10.x/', - distribution='bionic', components=["main"], - architectures=["amd64"], - filter="test", download_udebs=True, - download_sources=True, download_installer=True, - skip_component_check=True, filter_with_deps=True, - keyrings="/path/to/keyring", ignore_signatures=True), + self.assertSequenceEqual( + self.miapi.create(name="aptly-mirror", archiveurl='https://deb.nodesource.com/node_10.x/', + distribution='bionic', components=["main"], + architectures=["amd64"], + filter="test", download_udebs=True, + download_sources=True, download_installer=True, + skip_component_check=True, filter_with_deps=True, + keyrings=["/path/to/keyring"], ignore_signatures=True), Mirror( uuid='2cb5985a-a23f-4a1f-8eb6-d5409193b4eb', name="aptly-mirror", @@ -52,12 +52,12 @@ def test_create(self, *, rmock: requests_mock.Mocker) -> None: components=["main"], architectures=["amd64"], downloaddate='0001-01-01T00:00:00Z', - meta={"Architectures": "i386 amd64 armhf arm64", + meta=[{"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", - "Components": "main", - "Date": "Tue, 06 Apr 2021 21:05:41 UTC", - "Description": " Apt Repository for the Node.JS 10.x Branch", - "Label": "Node Source", "Origin": "Node Source"}, + "Components": "main", + "Date": "Tue, 06 Apr 2021 21:05:41 UTC", + "Description": " Apt Repository for the Node.JS 10.x Branch", + "Label": "Node Source", "Origin": "Node Source"}], filter="test", status=0, worker_pid=0, @@ -78,11 +78,11 @@ def test_list(self, *, rmock: requests_mock.Mocker) -> None: "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", "Distribution": "bionic", "Components": ["main"], "Architectures": ["amd64"], - "Meta": {"Architectures": "i386 amd64 armhf arm64", + "Meta": [{"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", "Components": "main", "Date": "Tue, 06 Apr 2021 21:05:41 UTC", "Description": " Apt Repository for the Node.JS 10.x Branch", - "Label": "Node Source", "Origin": "Node Source"}, + "Label": "Node Source", "Origin": "Node Source"}], "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "", "Status": 0, "WorkerPID": 0, "FilterWithDeps": false, "SkipComponentCheck": false, "SkipArchitectureCheck": false, @@ -90,7 +90,7 @@ def test_list(self, *, rmock: requests_mock.Mocker) -> None: "DownloadInstaller": false}]""" ) self.assertSequenceEqual( - self.mapi.list(), + self.miapi.list(), [ Mirror( uuid='2cb5985a-a23f-4a1f-8eb6-d5409193b4eb', @@ -100,12 +100,12 @@ def test_list(self, *, rmock: requests_mock.Mocker) -> None: components=["main"], architectures=["amd64"], downloaddate='0001-01-01T00:00:00Z', - meta={"Architectures": "i386 amd64 armhf arm64", + meta=[{"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", - "Components": "main", - "Date": "Tue, 06 Apr 2021 21:05:41 UTC", - "Description": " Apt Repository for the Node.JS 10.x Branch", - "Label": "Node Source", "Origin": "Node Source"}, + "Components": "main", + "Date": "Tue, 06 Apr 2021 21:05:41 UTC", + "Description": " Apt Repository for the Node.JS 10.x Branch", + "Label": "Node Source", "Origin": "Node Source"}], filter="", status=0, worker_pid=0, @@ -127,19 +127,19 @@ def test_show(self, *, rmock: requests_mock.Mocker) -> None: "ArchiveRoot": "https://deb.nodesource.com/node_10.x/", "Distribution": "bionic", "Components": ["main"], "Architectures": ["amd64"], - "Meta": {"Architectures": "i386 amd64 armhf arm64", + "Meta": [{"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", "Components": "main", "Date": "Tue, 06 Apr 2021 21:05:41 UTC", "Description": " Apt Repository for the Node.JS 10.x Branch", - "Label": "Node Source", "Origin": "Node Source"}, + "Label": "Node Source", "Origin": "Node Source"}], "LastDownloadDate": "0001-01-01T00:00:00Z", "Filter": "", "Status": 0, "WorkerPID": 0, "FilterWithDeps": false, "SkipComponentCheck": false, "SkipArchitectureCheck": false, "DownloadSources": false, "DownloadUdebs": false, "DownloadInstaller": false}""" ) - self.assertEqual( - self.mapi.show(name="aptly-mirror"), + self.assertSequenceEqual( + self.miapi.show(name="aptly-mirror"), Mirror( uuid='2cb5985a-a23f-4a1f-8eb6-d5409193b4eb', name="aptly-mirror", @@ -148,12 +148,12 @@ def test_show(self, *, rmock: requests_mock.Mocker) -> None: components=["main"], architectures=["amd64"], downloaddate='0001-01-01T00:00:00Z', - meta={"Architectures": "i386 amd64 armhf arm64", + meta=[{"Architectures": "i386 amd64 armhf arm64", "Codename": "bionic", - "Components": "main", - "Date": "Tue, 06 Apr 2021 21:05:41 UTC", - "Description": " Apt Repository for the Node.JS 10.x Branch", - "Label": "Node Source", "Origin": "Node Source"}, + "Components": "main", + "Date": "Tue, 06 Apr 2021 21:05:41 UTC", + "Description": " Apt Repository for the Node.JS 10.x Branch", + "Label": "Node Source", "Origin": "Node Source"}], filter="", status=0, worker_pid=0, @@ -171,7 +171,7 @@ def test_list_packages(self, *, rmock: requests_mock.Mocker) -> None: rmock.get("http://test/api/mirrors/aptly-mirror/packages", text='["Pamd64 nodejs 10.24.1-1nodesource1 1f74a6abf6acc572"]') self.assertSequenceEqual( - self.mapi.list_packages( + self.miapi.list_packages( name="aptly-mirror", query=("nodejs"), with_deps=True), [ Package( @@ -213,8 +213,8 @@ def test_list_packages_details(self, *, rmock: requests_mock.Mocker) -> None: "Version":"10.24.1-1nodesource1" }]""" ) - self.assertEqual( - self.mapi.list_packages( + self.assertSequenceEqual( + self.miapi.list_packages( "aptly-mirror", detailed=True, with_deps=True, query="nodejs"), [ Package( @@ -253,32 +253,32 @@ def test_list_packages_details(self, *, rmock: requests_mock.Mocker) -> None: def test_delete(self, *, rmock: requests_mock.Mocker) -> None: with self.assertRaises(requests_mock.NoMockAddress): - self.mapi.delete(name="aptly-mirror") + self.miapi.delete(name="aptly-mirror") def test_update(self, *, rmock: requests_mock.Mocker) -> None: with self.assertRaises(requests_mock.NoMockAddress): - self.mapi.update(name="aptly-mirror", ignore_signatures=True) + self.miapi.update(name="aptly-mirror", ignore_signatures=True) def test_edit(self, *, rmock: requests_mock.Mocker) -> None: with self.assertRaises(requests_mock.NoMockAddress): - self.mapi.edit(name="aptly-mirror", newname="aptly-mirror-renamed", - archiveurl='https://deb.nodesource.com/node_10.x/', - architectures=["i386", "amd64"], filter="test", - components=["main"], keyrings="/path/to/keyring", - skip_existing_packages=True, ignore_checksums=True, - download_udebs=True, download_sources=True, - skip_component_check=True, filter_with_deps=True, - ignore_signatures=True, force_update=True), + self.miapi.edit(name="aptly-mirror", newname="aptly-mirror-renamed", + archiveurl='https://deb.nodesource.com/node_10.x/', + architectures=["i386", "amd64"], filter="test", + components=["main"], keyrings=["/path/to/keyring"], + skip_existing_packages=True, ignore_checksums=True, + download_udebs=True, download_sources=True, + skip_component_check=True, filter_with_deps=True, + ignore_signatures=True, force_update=True) def test_delete_validation(self, *, rmock: requests_mock.Mocker) -> None: rmock.delete("http://test/api/mirrors/aptly-mirror") - self.mapi.delete(name="aptly-mirror") + self.miapi.delete(name="aptly-mirror") def test_update_validation(self, *, rmock: requests_mock.Mocker) -> None: rmock.put("http://test/api/mirrors/aptly-mirror") - self.mapi.update(name="aptly-mirror") + self.miapi.update(name="aptly-mirror") def test_edit_validation(self, *, rmock: requests_mock.Mocker) -> None: rmock.put("http://test/api/mirrors/aptly-mirror", text='{"Name":"aptly-mirror-bla", "IgnoreSignatures": true}') - self.mapi.edit(name="aptly-mirror", newname="aptly-mirror-renamed") + self.miapi.edit(name="aptly-mirror", newname="aptly-mirror-renamed") From a14368e10a1228f9e4ad80f88511aaf2e5587293 Mon Sep 17 00:00:00 2001 From: Xaoc7 Date: Tue, 10 Jan 2023 10:44:39 +0200 Subject: [PATCH 6/7] Fixed code style Fixed code style1 --- aptly_api/parts/snapshots.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aptly_api/parts/snapshots.py b/aptly_api/parts/snapshots.py index 0bff9a7..0dba393 100644 --- a/aptly_api/parts/snapshots.py +++ b/aptly_api/parts/snapshots.py @@ -49,8 +49,7 @@ def create_from_repo(self, reponame: str, snapshotname: str, description: Option if description is not None: body["Description"] = description - resp = self.do_post("api/repos/%s/snapshots" % - quote(reponame), json=body) + resp = self.do_post("api/repos/%s/snapshots" % quote(reponame), json=body) return self.snapshot_from_response(resp.json()) def create_from_mirror(self, mirrorname: str, snapshotname: str, description: Optional[str] = None) -> Snapshot: From ef4f4172788f4e44176f73275aabbd999ca2e73e Mon Sep 17 00:00:00 2001 From: Jonas Maurus Date: Tue, 13 Aug 2024 14:11:44 +0200 Subject: [PATCH 7/7] fix code formatting --- aptly_api/parts/mirrors.py | 45 +++++++++++--------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/aptly_api/parts/mirrors.py b/aptly_api/parts/mirrors.py index d833bbb..e9f7714 100644 --- a/aptly_api/parts/mirrors.py +++ b/aptly_api/parts/mirrors.py @@ -38,35 +38,19 @@ class MirrorsAPISection(BaseAPIClient): @staticmethod def mirror_from_response(api_response: Dict[str, str]) -> Mirror: return Mirror( - uuid=cast(str, api_response["UUID"] - ) if "UUID" in api_response else None, - name=cast(str, api_response["Name"]), - archiveurl=cast( - str, api_response["ArchiveRoot"]), - distribution=cast( - str, api_response["Distribution"]) - if "Distribution" in api_response else None, - components=cast(List[str], api_response["Components"] - )if "Components" in api_response else None, - architectures=cast(List[str], api_response["Architectures"] - ) if "Architectures" in api_response else None, - meta=cast(List[Dict[str, str]], api_response["Meta"] - ) if "Meta" in api_response else None, - downloaddate=cast( - str, api_response["LastDownloadDate"]) - if "LastDownloadDate" in api_response else None, - filter=cast(str, api_response["Filter"] - ) if "Filter" in api_response else None, - status=cast(int, api_response["Status"] - )if "Status" in api_response else None, - worker_pid=cast( - int, api_response["WorkerPID"]) - if "WorkerPID" in api_response else None, + uuid=cast(str, api_response["UUID"]) if "UUID" in api_response else None, + name=cast(str, api_response["Name"]), archiveurl=cast(str, api_response["ArchiveRoot"]), + distribution=cast(str, api_response["Distribution"]) if "Distribution" in api_response else None, + components=cast(List[str], api_response["Components"])if "Components" in api_response else None, + architectures=cast(List[str], api_response["Architectures"]) if "Architectures" in api_response else None, + meta=cast(List[Dict[str, str]], api_response["Meta"]) if "Meta" in api_response else None, + downloaddate=cast(str, api_response["LastDownloadDate"]) if "LastDownloadDate" in api_response else None, + filter=cast(str, api_response["Filter"]) if "Filter" in api_response else None, + status=cast(int, api_response["Status"])if "Status" in api_response else None, + worker_pid=cast(int, api_response["WorkerPID"]) if "WorkerPID" in api_response else None, filter_with_deps=cast(bool, api_response["FilterWithDeps"]), - skip_component_check=cast( - bool, api_response["SkipComponentCheck"]), - skip_architecture_check=cast( - bool, api_response["SkipArchitectureCheck"]), + skip_component_check=cast(bool, api_response["SkipComponentCheck"]), + skip_architecture_check=cast(bool, api_response["SkipArchitectureCheck"]), download_sources=cast(bool, api_response["DownloadSources"]), download_udebs=cast(bool, api_response["DownloadUdebs"]), download_installer=cast(bool, api_response["DownloadInstaller"]) @@ -77,9 +61,7 @@ def list(self) -> Sequence[Mirror]: mirrors = [] for mirr in resp.json(): - mirrors.append( - self.mirror_from_response(mirr) - ) + mirrors.append(self.mirror_from_response(mirr)) return mirrors def update(self, name: str, ignore_signatures: bool = False) -> None: @@ -130,7 +112,6 @@ def edit(self, name: str, newname: Optional[str] = None, archiveurl: Optional[st def show(self, name: str) -> Mirror: resp = self.do_get("api/mirrors/%s" % (quote(name))) - return self.mirror_from_response(resp.json()) def list_packages(self, name: str, query: Optional[str] = None, with_deps: bool = False,