[elbe-devel] [PATCH 2/5] repodir: Preprocess XML and serve Debian repositories

Bastian Germann bage at linutronix.de
Mon Oct 10 16:13:17 CEST 2022


The repodir module provides a Python context manager which acts in two stages:
It reprocesses an XML file and serves the contents via the built-in Python
web server.

Signed-off-by: Bastian Germann <bage at linutronix.de>
---
 elbepack/repodir.py | 102 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 elbepack/repodir.py

diff --git a/elbepack/repodir.py b/elbepack/repodir.py
new file mode 100644
index 0000000000..9df2f6369b
--- /dev/null
+++ b/elbepack/repodir.py
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+# SPDX-FileCopyrightText: 2022 Linutronix GmbH
+
+import functools
+import os
+import sys
+
+from http.server import SimpleHTTPRequestHandler, HTTPServer
+from threading import Thread
+
+from lxml.etree import XMLParser, parse, Element, XMLSyntaxError
+
+
+class RepodirError(Exception):
+    pass
+
+def preprocess_repodir(xml, xmldir):
+    """Replaces each <repodir>, which points to a directory containing a Debian
+       repository, with a valid <url> element.
+       <repodir>'s text node holds a filepath plus the elements of a sources.list
+       entry after the URL (suite, components).
+
+       Returns a list with HTTPServer instances.
+    """
+    httpds = []
+    for repodir in xml.iterfind('.//mirror/url-list/repodir'):
+        repo = repodir.text.split(maxsplit=1)
+        if len(repo) != 2:
+            raise RepodirError("A <repodir> must consist of a file path, a suite name, and components")
+
+        hostdir = os.path.join(xmldir, repo[0])
+        httpd = HTTPServer(('localhost', 0), functools.partial(SimpleHTTPRequestHandler, directory=hostdir))
+
+        url_element = Element("url")
+        # Keep the variant attribute for later processing
+        if 'variant' in repodir.attrib:
+            url_element.attrib['variant'] = repodir.attrib['variant']
+
+        bin_el = Element("binary")
+        bin_el.text = f"http://LOCALMACHINE:{httpd.server_address[1]} {repo[1]}"
+        url_element.append(bin_el)
+        src_el = Element("source")
+        src_el.text = bin_el.text
+        url_element.append(src_el)
+
+        if 'signed-by' in repodir.attrib:
+            try:
+                keyfile = os.path.join(hostdir, repodir.attrib['signed-by'])
+                auth_el = Element("raw-key")
+                auth_el.text = "\n" + open(keyfile, encoding='ascii').read()
+            except:
+                raise RepodirError("%s is not a valid ascii-armored OpenPGP keyring" % keyfile)
+        else:
+            auth_el = Element("options")
+            option_el = Element("option")
+            option_el.text = "trusted=yes"
+            auth_el.append(option_el)
+        url_element.append(auth_el)
+
+        httpds.append(httpd)
+
+        repodir.getparent().append(url_element)
+        repodir.getparent().remove(repodir)
+
+    return httpds
+
+
+class Repodir:
+    """Constructs a Repodir."""
+    def __init__(self, input_xml_path, output_xml_path):
+        self.input = input_xml_path
+        self.output = output_xml_path
+        self.httpds = []
+
+    def __enter__(self):
+        parser = XMLParser(huge_tree=True)
+
+        try:
+            xml = parse(self.input, parser=parser)
+            xml.xinclude()
+
+            self.httpds = preprocess_repodir(xml, os.path.dirname(self.input))
+
+            xml.write(
+                self.output,
+                encoding="UTF-8",
+                pretty_print=True)
+
+            for httpd in self.httpds:
+                Thread(target=httpd.serve_forever).start()
+
+            return self
+
+        except XMLSyntaxError:
+            raise RepodirError("XML Parse error\n" + str(sys.exc_info()[1]))
+        except BaseException:
+           raise RepodirError(
+                "Unknown Exception during validation\n" + str(sys.exc_info()[1]))
+
+    def __exit__(self, _typ, _value, _traceback):
+        for httpd in self.httpds:
+            httpd.shutdown()
-- 
2.30.2



More information about the elbe-devel mailing list