Files
KAIandClaude Opus 5 7dd3b9a0a2 Fassung 0.6.0 und ein Bauskript fuer das Plugin-Paket
tools/baue_paket.py schnuert aus dem Arbeitsstand das ZIP (genau ein Ordner vln_karten/,
ohne __pycache__) und schreibt die passende plugins.xml. Beides gehoert danach in den
Manager nach api/qgis/; von dort liefert der Server es unter /v2/qgis/ aus, und QGIS bietet
neue Fassungen von selbst an.

metadata.txt: Fassung 0.6.0, Beschreibung und Changelog auf den heutigen Stand (Widmungen
und Verkehrszeichen, Palette, Werkzeuge, Rollbalken). dist/ bleibt aus dem Git heraus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 11:40:23 +02:00

118 lines
4.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Aus dem Arbeitsstand ein QGIS-Plugin-Paket bauen (ZIP + plugins.xml).
QGIS installiert Erweiterungen aus einem ZIP, das genau einen Ordner enthält — hier
``vln_karten/``. Ein eigenes Plugin-Verzeichnis ist nichts weiter als eine ``plugins.xml``
neben diesen ZIPs; trägt man ihre Adresse in QGIS ein (Erweiterungen → Einstellungen →
Hinzufügen), bietet QGIS Aktualisierungen von selbst an.
Aufruf::
python3 tools/baue_paket.py [Zielordner]
Ohne Zielordner landet alles unter ``dist/``. Die beiden Dateien gehören danach in den
Manager (``api/qgis/``); von dort liefert der Server sie unter ``/v2/qgis/`` aus.
Nichts an QGIS gebunden — läuft mit jedem Python 3.
"""
import os
import sys
import zipfile
WURZEL = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PAKET = "vln_karten"
#: Was nicht ins Paket gehört (Laufzeitkram und Eigenes der Arbeitskopie).
AUS = (".pyc", ".pyo", ".DS_Store")
AUS_ORDNER = ("__pycache__", ".git")
#: Adresse, unter der der Manager die Pakete ausliefert.
BASIS = "https://api.flurneuordnung-sachsen.de/v2/qgis"
def metadaten():
"""``metadata.txt`` als dict (nur ``[general]``, mehrzeilige Werte zusammengefasst)."""
pfad = os.path.join(WURZEL, PAKET, "metadata.txt")
daten, schluessel = {}, None
with open(pfad, "r", encoding="utf-8") as fh:
for zeile in fh:
if zeile.startswith("[") or not zeile.strip():
continue
if "=" in zeile and not zeile.startswith((" ", "\t")):
schluessel, wert = zeile.split("=", 1)
schluessel = schluessel.strip()
daten[schluessel] = wert.strip()
elif schluessel:
daten[schluessel] += " " + zeile.strip()
return daten
def baue_zip(ziel, version):
"""Das Paket schreiben und seinen Pfad zurückgeben."""
name = "%s-%s.zip" % (PAKET, version)
pfad = os.path.join(ziel, name)
mit = 0
with zipfile.ZipFile(pfad, "w", zipfile.ZIP_DEFLATED) as z:
for ordner, unter, dateien in os.walk(os.path.join(WURZEL, PAKET)):
unter[:] = [u for u in unter if u not in AUS_ORDNER]
for datei in sorted(dateien):
if datei.endswith(AUS) or datei in AUS:
continue
voll = os.path.join(ordner, datei)
z.write(voll, os.path.relpath(voll, WURZEL))
mit += 1
return pfad, mit
def _xml(text):
return (str(text).replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
.replace('"', "&quot;"))
def baue_xml(ziel, daten, zipname):
"""``plugins.xml`` schreiben — das Verzeichnis, das QGIS abfragt."""
pfad = os.path.join(ziel, "plugins.xml")
inhalt = (
'<?xml version="1.0"?>\n<plugins>\n'
' <pyqgis_plugin name="%s" version="%s">\n'
' <description>%s</description>\n'
' <about>%s</about>\n'
' <version>%s</version>\n'
' <qgis_minimum_version>%s</qgis_minimum_version>\n'
' <qgis_maximum_version>%s</qgis_maximum_version>\n'
' <homepage>%s</homepage>\n'
' <file_name>%s</file_name>\n'
' <download_url>%s/%s</download_url>\n'
' <author_name>%s</author_name>\n'
' <tracker>%s</tracker>\n'
' <repository>%s</repository>\n'
' <tags>%s</tags>\n'
' <experimental>%s</experimental>\n'
' <deprecated>False</deprecated>\n'
' </pyqgis_plugin>\n</plugins>\n'
% (_xml(daten.get("name")), _xml(daten.get("version")),
_xml(daten.get("description")), _xml(daten.get("about")),
_xml(daten.get("version")), _xml(daten.get("qgisMinimumVersion", "3.22")),
_xml(daten.get("qgisMaximumVersion", "3.99")), _xml(daten.get("repository", "")),
_xml(zipname), BASIS, _xml(zipname), _xml(daten.get("author", "")),
_xml(daten.get("tracker", "")), _xml(daten.get("repository", "")),
_xml(daten.get("tags", "")), _xml(daten.get("experimental", "False"))))
with open(pfad, "w", encoding="utf-8") as fh:
fh.write(inhalt)
return pfad
def main():
ziel = sys.argv[1] if len(sys.argv) > 1 else os.path.join(WURZEL, "dist")
os.makedirs(ziel, exist_ok=True)
daten = metadaten()
zippfad, anzahl = baue_zip(ziel, daten["version"])
xmlpfad = baue_xml(ziel, daten, os.path.basename(zippfad))
print("Paket: %s (%d Dateien, %.0f KB)"
% (zippfad, anzahl, os.path.getsize(zippfad) / 1024))
print("Katalog: %s" % xmlpfad)
print("Beides nach VLNManager/api/qgis/ kopieren; der Server liefert es unter %s/" % BASIS)
if __name__ == "__main__":
main()