From f94d1374566a63657ac0e3193c4249c436de0a55 Mon Sep 17 00:00:00 2001 From: James Watt Date: Thu, 4 Jan 2024 17:09:44 -0500 Subject: [PATCH 1/4] feature: add support for opkg (OpenWrt's package manager) --- pyinfra/facts/opkg.py | 208 ++++++++++++++++++ pyinfra/operations/opkg.py | 95 ++++++++ tests/facts/opkg.Conf/opkg_conf.json | 42 ++++ tests/facts/opkg.Feeds/opkg_feeds.json | 51 +++++ .../opkg_installable_architectures.json | 20 ++ tests/facts/opkg.Packages/opkg_packages.json | 39 ++++ .../opkg_upgradeable_packages.json | 34 +++ .../opkg.packages/add_existing_package.json | 12 + .../opkg.packages/add_multiple_packages.json | 12 + .../opkg.packages/add_one_package.json | 12 + .../add_with_unallowed_pinning.json | 11 + .../list_of_nulls_package_list.json | 9 + .../opkg.packages/null_package_list.json | 9 + .../remove_existing_package.json | 13 ++ ...e_existing_package_and_require_update.json | 14 ++ .../remove_not_existing_package.json | 13 ++ .../opkg.packages/update_then_add_one.json | 11 + .../operations/opkg.update/first_update.json | 9 + .../opkg_second_update_forced.json | 10 + .../operations/opkg.update/second_update.json | 9 + .../opkg.update/second_update_with_force.json | 10 + tests/words.txt | 4 + 22 files changed, 647 insertions(+) create mode 100644 pyinfra/facts/opkg.py create mode 100644 pyinfra/operations/opkg.py create mode 100644 tests/facts/opkg.Conf/opkg_conf.json create mode 100644 tests/facts/opkg.Feeds/opkg_feeds.json create mode 100644 tests/facts/opkg.InstallableArchitectures/opkg_installable_architectures.json create mode 100644 tests/facts/opkg.Packages/opkg_packages.json create mode 100644 tests/facts/opkg.UpgradeablePackages/opkg_upgradeable_packages.json create mode 100644 tests/operations/opkg.packages/add_existing_package.json create mode 100644 tests/operations/opkg.packages/add_multiple_packages.json create mode 100644 tests/operations/opkg.packages/add_one_package.json create mode 100644 tests/operations/opkg.packages/add_with_unallowed_pinning.json create mode 100644 tests/operations/opkg.packages/list_of_nulls_package_list.json create mode 100644 tests/operations/opkg.packages/null_package_list.json create mode 100644 tests/operations/opkg.packages/remove_existing_package.json create mode 100644 tests/operations/opkg.packages/remove_existing_package_and_require_update.json create mode 100644 tests/operations/opkg.packages/remove_not_existing_package.json create mode 100644 tests/operations/opkg.packages/update_then_add_one.json create mode 100644 tests/operations/opkg.update/first_update.json create mode 100644 tests/operations/opkg.update/opkg_second_update_forced.json create mode 100644 tests/operations/opkg.update/second_update.json create mode 100644 tests/operations/opkg.update/second_update_with_force.json diff --git a/pyinfra/facts/opkg.py b/pyinfra/facts/opkg.py new file mode 100644 index 000000000..52eac9eda --- /dev/null +++ b/pyinfra/facts/opkg.py @@ -0,0 +1,208 @@ +""" +Gather the information provided by ``opkg`` on OpenWrt systems: + + ``opkg`` configuration + + feeds configuration + + list of installed packages + + list of packages with available upgrades + + + see https://openwrt.org/docs/guide-user/additional-software/opkg +""" +from __future__ import annotations + +import re +from typing import NamedTuple + +from pyinfra import logger +from pyinfra.api import FactBase +from pyinfra.facts.util.packaging import parse_packages + +# TODO - change NamedTuple to dataclass but need to figure out how to get json serialization +# to work without changing core code + + +class PkgUpgradeInfo(NamedTuple): + installed: str + available: str + + +class ConfInfo(NamedTuple): + paths: dict[str, str] # list of paths, e.g. {'root':'/', 'ram':'/tmp} + list_dir: str # where package lists are stored, e.g. /var/opkg-lists + options: dict[str, str | bool] # mapping from option to value, e.g. {'check_signature': True} + arch_cfg: dict[str, int] # priorities for architectures + + +class FeedInfo(NamedTuple): + url: str # url for the feed + fmt: str # format of the feed, e.g. "src/gz" + kind: str # whether it comes from the 'distribution' or is 'custom' + + +class Conf(FactBase): + """ + Returns a NamedTuple with the current configuration: + + .. code:: python + + dest root / + dest ram /tmp + lists_dir ext /var/opkg-lists + option overlay_root /overlay + option check_signature + + """ + + regex = re.compile( + r""" + ^(?:\s*) + (?: + (?:arch\s+(?P\w+)\s+(?P\d+))| + (?:dest\s+(?P\w+)\s+(?P[\w/\-]+))| + (?:lists_dir\s+(?Pext)\s+(?P[\w/\-]+))| + (?:option\s+(?P