#!/usr/bin/env python3
# Embed release-notes HTML as an inline on the appcast item whose
# sparkle:shortVersionString matches, and drop any sparkle:releaseNotesLink.
#
# Why inline rather than a : Sparkle renders an inline
# straight in the updater with no extra network fetch, so it
# doesn't depend on the notes host's content-type (GitHub serves release assets
# as application/octet-stream) and never 404s the way GitHub's /latest/download/
# link does once a newer release becomes "latest". The HTML is XML-escaped here,
# which Sparkle's parser decodes back to markup before rendering — functionally
# identical to a CDATA block. The signed is left untouched.
#
# Usage: embed-release-notes.py
import sys, xml.etree.ElementTree as ET
appcast, version, notes_path = sys.argv[1], sys.argv[2], sys.argv[3]
SPARKLE = "http://www.andymatuschak.org/xml-namespaces/sparkle"
ET.register_namespace("sparkle", SPARKLE)
with open(notes_path, encoding="utf-8") as f:
notes = f.read()
tree = ET.parse(appcast)
matched = False
for item in tree.getroot().iter("item"):
sv = item.find(f"{{{SPARKLE}}}shortVersionString")
if sv is None or sv.text != version:
continue
for tag in (f"{{{SPARKLE}}}releaseNotesLink", "description"):
for el in item.findall(tag):
item.remove(el)
ET.SubElement(item, "description").text = notes
matched = True
if not matched:
sys.exit(f"embed-release-notes: no appcast item with shortVersionString {version}")
tree.write(appcast, encoding="UTF-8", xml_declaration=True)