-
Notifications
You must be signed in to change notification settings - Fork 3
/
generate_appcast.py
executable file
·169 lines (128 loc) · 4 KB
/
generate_appcast.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/usr/bin/env python
"""
Helpers to generate Sparkle AppCast XML
AppCast is a RSS2.0-based spec for publishing application versions
- https://sparkle-project.org/documentation/publishing/
- https://github.com/vslavik/winsparkle/wiki/Appcast-Feeds
"""
from xml.etree import ElementTree
from dateutil.parser import parse as parse_datetime
import markdown
class Channel:
tag_name = "channel"
def __init__(self, title, link, language=""):
self.title = title
self.link = link
self.language = language
self.items = []
def to_xml(self):
ret = ElementTree.Element("rss")
ret.attrib["version"] = "2.0"
ret.attrib["xmlns:sparkle"] = "http://www.andymatuschak.org/xml-namespaces/sparkle"
ret.attrib["xmlns:dc"] = "http://purl.org/dc/elements/1.1/"
channel = ElementTree.Element(self.tag_name)
ret.append(channel)
title = ElementTree.Element("title")
title.text = self.title
channel.append(title)
link = ElementTree.Element("link")
link.text = self.link
channel.append(link)
if self.language:
language = ElementTree.Element("language")
language.text = self.language
channel.append(language)
for item in self.items:
channel.append(item.to_xml())
return ret
def to_xml_string(self):
return ElementTree.tostring(self.to_xml()).decode("utf-8")
class Item:
tag_name = "item"
def __init__(self, title, description, pub_date):
self.title = title
self.description = description
self.pub_date = pub_date
self.minimum_system_version = ""
def to_xml(self):
ret = ElementTree.Element(self.tag_name)
title = ElementTree.Element("title")
title.text = self.title
ret.append(title)
pub_date = ElementTree.Element("pubDate")
pub_date.text = self.pub_date.isoformat()
ret.append(pub_date)
return ret
class AppCastItem(Item):
def __init__(self, *args):
super().__init__(*args)
self.minimum_system_version = ""
self.version = ""
self.short_version_string = ""
self.url = ""
self.length = 0
self.type = "application/octet-stream"
def to_xml(self):
ret = super().to_xml()
if self.minimum_system_version:
minver = ElementTree.Element("sparkle:minimumSystemVersion")
minver.text = self.minimum_system_version
ret.append(minver)
if self.description:
description = ElementTree.Element("description")
description.text = self.description
ret.append(description)
enclosure = ElementTree.Element("enclosure")
enclosure.attrib["url"] = self.url
enclosure.attrib["type"] = self.type
enclosure.attrib["length"] = str(self.length)
enclosure.attrib["sparkle:version"] = self.version
enclosure.attrib["sparkle:shortVersionString"] = self.short_version_string
ret.append(enclosure)
return ret
def item_from_github(release):
# Only support releases with ==1 asset
if not release["assets"]:
return
version = release["tag_name"]
# version must be formatted as x.y.z.build
if version.count(".") < 2:
return
title = release["name"]
description = markdown.markdown(release["body"])
date = parse_datetime(release["published_at"])
item = AppCastItem(title, description, date)
item.short_version_string = version
item.version = version.rpartition(".")[-1]
asset = release["assets"][0]
item.url = asset["browser_download_url"]
item.type = asset["content_type"]
item.length = asset["size"]
return item
def from_github(org, repo):
"""
Convert a list of releases in a Github repository
to an AppCast channel
"""
import requests
# https://api.github.com/repos/HearthSim/HDT-Releases/releases
url = "https://github.com/%s/%s" % (org, repo)
releases_url = "https://api.github.com/repos/%s/%s/releases" % (org, repo)
r = requests.get(releases_url)
d = r.json()
channel = Channel(repo, url)
for release in d:
item = item_from_github(release)
if item:
channel.items.append(item)
return channel
def main():
import sys
if len(sys.argv) < 3:
print("Usage: %s <GH-ORG> <GH-REPO>" % (sys.argv[0]), file=sys.stderr)
exit(1)
org = sys.argv[1]
repo = sys.argv[2]
print(from_github(org, repo).to_xml_string())
if __name__ == "__main__":
main()