#!/usr/bin/env python3 # # This file is part of OpenMediaVault. # # @license http://www.gnu.org/licenses/gpl.html GPL Version 3 # @author Volker Theile # @copyright Copyright (c) 2009-2024 Volker Theile # # OpenMediaVault is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # any later version. # # OpenMediaVault is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with OpenMediaVault. If not, see . import json import platform import re # The following error might happen from time to time. # # Traceback (most recent call last): # File "/usr/sbin/omv-mkaptidx", line 27, in # import openmediavault # EOFError: EOF read where not expected # # To analyse the error execute: # python3 -vc 'import openmediavault' # # To fix this error simply execute the following command: # rm -f /usr/lib/python3/dist-packages/__pycache__/openmediavault.cpython-32.pyc import sys import apt import click import openmediavault.productinfo import openmediavault pi = openmediavault.productinfo.ProductInfo() class OpenMediaVaultPluginsFilter(apt.cache.Filter): """ Filter that returns all openmediavault plugins except the packages: - openmediavault - openmediavault-keyring """ def apply(self, pkg): m = re.match(r"^%s-(\S+)$" % pi.package_name, pkg.name) if not m: return False if m.group(1) == "keyring": return False if pkg.candidate is not None: # The 'Plugin-Architecture' is mostly used by plugins that are # using container images. The architectures that are supported # by those images are listed as comma separated values. Note, # the list contains the architecture labels used by Debian. arch = explode_csv(pkg.candidate.record.get( "Plugin-Architecture")) if arch: # Map the platform architecture to the Debian # architecture string used in 'debian/control'. machine_2_debian = { "i386": "i386", "x86_64": "amd64", "armv6l": "armel", "armv7l": "armhf", "aarch64": "arm64" } # Skip this package if the host architecture is # not in the list of the supported architectures. if machine_2_debian.get(platform.machine()) not in arch: return False return True def get_extended_description(raw_description): """ Return the extended description according to the Debian policy (Chapter 5.6.13). See http://www.debian.org/doc/debian-policy/ch-controlfields.html for more information. """ parts = raw_description.partition("\n") lines = parts[2].split("\n") for i, line in enumerate(lines): lines[i] = line.strip() if lines[i] == ".": lines[i] = "\n" return "\n".join(lines) def explode_csv(value): """ Split a comma separated string into parts. """ if not isinstance(value, str): return [] return [part.strip() for part in value.split(",") if part.strip()] def get_value(f, default=None): """ :param f: The function to be executed. :type f: callable :param default: The default value. Defaults to ``None``. :type default: str|int|None :return: Returns the specified value, otherwise the default on failure. """ try: return f() except SystemError: pass return default @click.command() @click.option('--verbose', is_flag=True, help='Shows verbose output.') def main(verbose: bool): cache = apt.cache.Cache() # Create the '/var/lib/openmediavault/apt/upgradeindex.json' file. print("Creating index of upgradeable packages ...") data = [] cache.upgrade(True) for pkg in cache.get_changes(): if pkg.candidate is None: continue data.append({ "name": pkg.name, "oldversion": pkg.installed.version if pkg.is_installed and pkg.installed is not None else "", "repository": "{}/{}".format(pkg.candidate.origins[0].label, pkg.candidate.origins[0].archive) if pkg.candidate.origins is not None else "", "package": pkg.candidate.record.get("Package"), "source": pkg.candidate.source_name, "sourceversion": pkg.candidate.source_version, "version": pkg.candidate.version, "installedsize": pkg.candidate.size, "maintainer": pkg.candidate.record.get("Maintainer", ""), "architecture": pkg.candidate.architecture, "depends": pkg.candidate.record.get("Depends", ""), "suggests": pkg.candidate.record.get("Suggests", ""), "conflicts": pkg.candidate.record.get("Conflicts", ""), "breaks": pkg.candidate.record.get("Breaks", ""), "abstract": pkg.candidate.summary, # Deprecated "summary": pkg.candidate.summary, "description": pkg.candidate.record.get("Description", ""), "extendeddescription": get_extended_description(pkg.candidate.raw_description), "homepage": pkg.candidate.homepage, "descriptionmd5": pkg.candidate.record.get("Description-md5", ""), "multiarch": pkg.candidate.record.get("Multi-Arch", ""), "predepends": pkg.candidate.record.get("Pre-Depends", ""), "section": pkg.candidate.section, "priority": pkg.candidate.priority, "filename": pkg.candidate.filename, "size": pkg.candidate.size, "md5sum": get_value(lambda: pkg.candidate.md5), "sha1": get_value(lambda: pkg.candidate.sha1), "sha256": get_value(lambda: pkg.candidate.sha256), "uri": pkg.candidate.uri, "uris": pkg.candidate.uris }) verbose and print(f"Added package '{pkg.name}'") with open( openmediavault.getenv( 'OMV_APT_UPGRADE_INDEX_FILE', '/var/lib/openmediavault/apt/upgradeindex.json' ), 'w' ) as outfile: json.dump(data, outfile, sort_keys=True, indent=4) verbose and print(f"Index file '{outfile.name}' successfully updated.") # Create the '/var/lib/openmediavault/apt/pluginsindex.json' file. print("Creating index of plugins ...") data = [] cache = apt.cache.Cache() filtered = apt.cache.FilteredCache(cache) filtered.set_filter(OpenMediaVaultPluginsFilter()) for pkg in filtered: if pkg.candidate is None: continue data.append({ "name": pkg.name, "repository": "{}/{}".format(pkg.candidate.origins[0].label, pkg.candidate.origins[0].archive) if pkg.candidate.origins is not None else "", "package": pkg.candidate.record.get("Package"), "version": pkg.candidate.version, "installedsize": pkg.candidate.size, "maintainer": pkg.candidate.record.get("Maintainer", ""), "architecture": pkg.candidate.architecture, "depends": pkg.candidate.record.get("Depends", ""), "suggests": pkg.candidate.record.get("Suggests", ""), "conflicts": pkg.candidate.record.get("Conflicts", ""), "breaks": pkg.candidate.record.get("Breaks", ""), "abstract": pkg.candidate.summary, # Deprecated "summary": pkg.candidate.summary, "description": pkg.candidate.record.get("Description", ""), "extendeddescription": get_extended_description(pkg.candidate.raw_description), "homepage": pkg.candidate.homepage, "descriptionmd5": pkg.candidate.record.get("Description-md5", ""), "multiarch": pkg.candidate.record.get("Multi-Arch", ""), "predepends": pkg.candidate.record.get("Pre-Depends", ""), "section": pkg.candidate.section, "pluginsection": pkg.candidate.record.get("Plugin-Section", ""), "pluginarchitecture": explode_csv(pkg.candidate.record.get("Plugin-Architecture")), "priority": pkg.candidate.priority, "filename": pkg.candidate.filename, "size": pkg.candidate.size, "md5sum": get_value(lambda: pkg.candidate.md5), "sha1": get_value(lambda: pkg.candidate.sha1), "sha256": get_value(lambda: pkg.candidate.sha256), "installed": pkg.is_installed }) verbose and print(f"Added package '{pkg.name}'") with open( openmediavault.getenv( 'OMV_APT_PLUGINS_INDEX_FILE', '/var/lib/openmediavault/apt/pluginsindex.json' ), 'w' ) as outfile: json.dump(data, outfile, sort_keys=True, indent=4) verbose and print(f"Index file '{outfile.name}' successfully updated.") sys.exit(0) if __name__ == '__main__': sys.exit(main())