def add_release(root, url, length, version, shortVersion, title, releaseNotes, minOS=None, maxOS=None, signature=None): root = E(root) firstItem = pq(root.element).find("item:first") method = "before" if not firstItem.size(): firstItem = [root.element] method = "append" c = getattr(E(firstItem[0]), method) c( E("item").append( E("title", title), E("sparkle:releaseNotesLink", releaseNotes), minOS and E("sparkle:minimumSystemVersion", minOS), maxOS and E("sparkle:maximumSystemVersion", maxOS), E("pubDate", time.strftime("%a, %d %b %Y %X %z", time.gmtime())), E( "enclosure", url=url, length=str(length), type="application/octet-stream", **( { "sparkle:version": version, "sparkle:dsaSignature": signature and "MCwCFAmB39sazl2xGIxSF8pHBbBh1zBLAhRmawuNanltHMlkCLv6R8OYiDRigQ==", "sparkle:shortVersionString": shortVersion, } ) ), ) )
def load_appcast(appcast_file): parser = lxml.etree.XMLParser(remove_blank_text=True) xml = lxml.etree.parse(appcast_file, parser) root = pq(xml.getroot()) if not root.find("channel").size(): return None return E(root[0])
def add_release(tool): options = {"class": "version", "data-version": tool.get("version"), "data-build": tool.get("build_version")} date = time.strftime("%B %d{S} %Y at %H:%M").replace("{S}", date_suffix(time.gmtime().tm_mday)) if minOS: options["data-min-os"] = minOS if maxOS: options["data-max-os"] = maxOS parent = E(pq(root.element).find(".sparkle-release-notes")[0]) release = E("div", E("h1", E("span", "Nightly Build %s" % (tool.get("build_version"))), E("time", date, datetime="%s" % (time.strftime("%Y-%m-%d")))), options) features = None if "features" in release_notes and len(release_notes["features"]): features = E("div", {"class": "features"}) for feature in release_notes["features"]: fe = E("div", {"class": "feature"}) fe.append(E("h3", feature["title"].decode('utf-8)'))) description_list = E("ul").append( *([E("li", d) for d in feature["description"]]) ) fe.append(description_list) features.append(fe) features and release.append(features) fixes = None if "fixes" in release_notes and len(release_notes["fixes"]): fixes = E("div", {"class": "fixes"}) fixes.append(E("h2", "Bugfixes")) fixes.append(E("ul").append( *([E("li", f) for f in release_notes["fixes"]]) )) fixes and release.append(fixes) parent.prepend(release)
def add_release(root, url, length, version, shortVersion, title, releaseNotes, minOS=None, maxOS=None, signature=None): root = E(root) firstItem = pq(root.element).find("item:first") method = "before" if not firstItem.size(): firstItem = [root.element] method = "append" c = getattr(E(firstItem[0]), method) c( E("item").append( E("title", title), E("sparkle:releaseNotesLink", releaseNotes), minOS and E("sparkle:minimumSystemVersion", minOS), maxOS and E("sparkle:maximumSystemVersion", maxOS), E("pubDate", time.strftime("%a, %d %b %Y %X %z", time.gmtime())), E("enclosure", url=url, length=str(length), type="application/octet-stream", **({ "sparkle:version": version, "sparkle:dsaSignature": signature and "MCwCFAmB39sazl2xGIxSF8pHBbBh1zBLAhRmawuNanltHMlkCLv6R8OYiDRigQ==", "sparkle:shortVersionString": shortVersion }))))
def convert_markdown_to_release_notes(md_code=None, filename=None): if filename: md_code = codecs.open(filename, mode="r", encoding="utf8").read() elif type(md_code) == types.StringType: md_code = md_code.decode("utf8") html = markdown.markdown(md_code) if not html: return (None, "Markdown document is empty.") root = pq("<html>%s</html>" % (html)) # Check if the required elements are available. if not root.find("h1").size(): return (None, "Title is missing! Please check your markdown for a line which looks like this:\n\n" "Title 1\n=======") if not root.find("h2").size(): return (None, "No Features or Bugfixes subtitle found! Please check your Markdown for a line that looks like this.\n\n" "Subtitle\n--------") if not root.find("ul").size(): return (None, "No Lists found! Please check your Markdown for at least one line that looks like this:\n\n" "* Item 1") # Format seems to be okay. # On to converting the markdown to release_notes dict. release_notes = {"info": {}} info = release_notes["info"] key = "" fixes = [] i = -1 titles = [] features = [] fixes = [] # First, find the items between two h2 titles (features and fixes.) for item in root.find("h1").nextAll(): item = pq(item) if item.is_("h2"): titles.append({"title": item.text().lower() == "features" and "features" or "fixes", "items": []}) i += 1 titles[i]["items"].append(item) for title in titles: if title["title"] == "features": j = -1 for item in title["items"]: if item.is_("h3"): features.append({ "title": item.html().strip(), "description": []}) j += 1 if item.is_("ul"): for item in item.children("li"): item = pq(item) features[j]["description"].append("\n".join([x.strip() for x in item.html().split("\n")])) elif title["title"] == "fixes": for item in title["items"]: if item.is_("ul"): for item in item.children("li"): item = pq(item) fixes.append("\n".join([x.strip() for x in item.html().split("\n")])) info["fixes"] = fixes info["features"] = features return (release_notes, None)
def main(): global APPCAST_ROOT (options, args) = parse_options() infile = None if len(args) == 1: infile = os.path.realpath(args[0]) # If a infile is given but no outfile is set, # write to infile. if not options.outfile and infile: options.outfile = infile config = options.from_config and tool_config() or options.__dict__ tool_name = config["name"].lower() if options.from_config: additional_options_from_config(config, options) else: config["title"] = "%s Releases" % (config.get("name")) config["description"] = None if not options.quiet: title("%s %s Sparkle appcast.xml" % (infile and "Update" or "Create", config.get("name"))) channel = None if infile: APPCAST_ROOT = None APPCAST_ROOT = load_appcast(infile) channel = pq(APPCAST_ROOT.element).find("channel")[0] if not APPCAST_ROOT: error("Couldn't load Sparkle appcast.xml file") if not infile: # Adding the channel info. add_channel_info( APPCAST_ROOT, title=config.get("title"), link=config.get("appcast_url"), description=config.get("description"), image=config.get("appicon_url"), ) channel = pq(APPCAST_ROOT.element).find("channel")[0] if options.from_config: filesize = config["filesize"] else: filesize = options.filesize # Adding the release item. if not options.quiet: status("Adding release info of %s v%s" % (config["name"], config.get("version"))) # If replace is set, remove all releases first. if options.replace: pq(channel).find("item").remove() add_release( channel, url=config.get("url"), length=filesize, version=config.get("build_version"), shortVersion=config.get("version"), title="%s v%s" % (config.get("name"), config.get("version").replace(")", " build %s)" % config.get("build_version"))), releaseNotes=config.get("release_notes_url"), minOS=config.get("minOS"), maxOS=config.get("maxOS"), ) xml = APPCAST_ROOT.xml(**XML_PRINT_CONFIG) if options.outfile: with open(options.outfile, "w") as fp: fp.write(xml) else: print xml if not options.quiet: success("Sparkle appcast.xml file was successfully %s" % (infile and "updated" or "created")) return True
def main(): global APPCAST_ROOT (options, args) = parse_options() infile = None if len(args) == 1: infile = os.path.realpath(args[0]) # If a infile is given but no outfile is set, # write to infile. if not options.outfile and infile: options.outfile = infile config = options.from_config and tool_config() or options.__dict__ tool_name = config["name"].lower() if options.from_config: additional_options_from_config(config, options) else: config["title"] = "%s Releases" % (config.get("name")) config["description"] = None if not options.quiet: title("%s %s Sparkle appcast.xml" % (infile and "Update" or "Create", config.get("name"))) channel = None if infile: APPCAST_ROOT = None APPCAST_ROOT = load_appcast(infile) channel = pq(APPCAST_ROOT.element).find("channel")[0] if not APPCAST_ROOT: error("Couldn't load Sparkle appcast.xml file") if not infile: # Adding the channel info. add_channel_info(APPCAST_ROOT, title=config.get("title"), link=config.get("appcast_url"), description=config.get("description"), image=config.get("appicon_url")) channel = pq(APPCAST_ROOT.element).find("channel")[0] if options.from_config: filesize = config["filesize"] else: filesize = options.filesize # Adding the release item. if not options.quiet: status("Adding release info of %s v%s" % (config["name"], config.get("version"))) # If replace is set, remove all releases first. if options.replace: pq(channel).find("item").remove() add_release(channel, url=config.get("url"), length=filesize, version=config.get("build_version"), shortVersion=config.get("version"), title="%s v%s" % (config.get("name"), config.get("version").replace( ")", " build %s)" % config.get("build_version"))), releaseNotes=config.get("release_notes_url"), minOS=config.get("minOS"), maxOS=config.get("maxOS")) xml = APPCAST_ROOT.xml(**XML_PRINT_CONFIG) if options.outfile: with open(options.outfile, "w") as fp: fp.write(xml) else: print xml if not options.quiet: success("Sparkle appcast.xml file was successfully %s" % (infile and "updated" or "created")) return True
def convert_markdown_to_release_notes(md_code=None, filename=None): if filename: md_code = codecs.open(filename, mode="r", encoding="utf8").read() elif type(md_code) == types.StringType: md_code = md_code.decode("utf8") html = markdown.markdown(md_code) if not html: return (None, "Markdown document is empty.") root = pq("<html>%s</html>" % (html)) # Check if the required elements are available. if not root.find("h1").size(): return ( None, "Title is missing! Please check your markdown for a line which looks like this:\n\n" "Title 1\n=======") if not root.find("h2").size(): return ( None, "No Features or Bugfixes subtitle found! Please check your Markdown for a line that looks like this.\n\n" "Subtitle\n--------") if not root.find("ul").size(): return ( None, "No Lists found! Please check your Markdown for at least one line that looks like this:\n\n" "* Item 1") # Format seems to be okay. # On to converting the markdown to release_notes dict. release_notes = {"info": {}} info = release_notes["info"] key = "" fixes = [] i = -1 titles = [] features = [] fixes = [] # First, find the items between two h2 titles (features and fixes.) for item in root.find("h1").nextAll(): item = pq(item) if item.is_("h2"): titles.append({ "title": item.text().lower() == "features" and "features" or "fixes", "items": [] }) i += 1 titles[i]["items"].append(item) for title in titles: if title["title"] == "features": j = -1 for item in title["items"]: if item.is_("h3"): features.append({ "title": item.html().strip(), "description": [] }) j += 1 if item.is_("ul"): for item in item.children("li"): item = pq(item) features[j]["description"].append("\n".join( [x.strip() for x in item.html().split("\n")])) elif title["title"] == "fixes": for item in title["items"]: if item.is_("ul"): for item in item.children("li"): item = pq(item) fixes.append("\n".join( [x.strip() for x in item.html().split("\n")])) info["fixes"] = fixes info["features"] = features return (release_notes, None)