#!/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)