Now, groups can retrieve a list of the contacts in that group. I probably should...
[adiumx.git] / Utilities / AppcastReplaceItem.py
blob06b2b22821f742c131a3011f1583bb70ade1c0f0
1 #!/usr/bin/env python
3 """
4 Usage:
5 AppcastReplaceItem <path-to-appcast> <old-version> <new-version> <path-to-dmg>
7 Example: AppcastReplaceItem appcast-release.xml 1.1.4 1.2 Release/build/Adium_1.2.dmg
8 """
10 # Configurable variables.
11 app_name = 'Adium'
12 changelog_fmt = 'http://www.adiumx.com/changelogs/%(version)s.html'
13 enclosure_fmt = ' <enclosure sparkle:md5Sum="%(md5)s" sparkle:version="%(version)s" url="%(url)s" length="%(file_size)s" type="application/octet-stream"/>\n'
14 # End of configurable variables.
16 import xml.etree.cElementTree as ElementTree
17 import sys
18 import os
19 import time
20 import subprocess
21 from stat import *
23 args = dict(zip(('appcast_path', 'old_version', 'version', 'dmg_pathname'), sys.argv[1:]))
24 try:
25 appcast_path = args['appcast_path']
26 old_version = args['old_version']
27 version = args['version']
28 dmg_pathname = args['dmg_pathname']
29 except KeyError:
30 sys.exit(__doc__.strip())
31 else:
32 args['app_name'] = app_name
34 # Get the length and modification time of the dmg file.
35 sb = os.stat(dmg_pathname)
36 file_size = args['file_size'] = sb[ST_SIZE]
37 dmg_mod_time = time.localtime(sb[ST_MTIME])
39 # Suffix for the day of the month.
40 th = ['st', 'nd', 'rd'] + ['th'] * (31 - 3)
42 # GMT offset in hours.
43 gmt_offset = '%+i' % (-int(time.timezone / 3600),)
45 # Format, which we must fill in with the above items first.
46 time_fmt = '%A, %B %dth, %Y %H:%M:%S GMT+0'.replace('th', th[dmg_mod_time.tm_mday]).replace('+0', gmt_offset)
47 dmg_mod_date = args['dmg_mod_date'] = time.strftime(time_fmt, dmg_mod_time)
49 openssl_md5 = subprocess.Popen(['openssl', 'md5', dmg_pathname], stdout=subprocess.PIPE)
50 # Skip the prefix
51 openssl_md5.stdout.read(len('MD5(') + len(dmg_pathname) + len(')= '))
52 md5 = args['md5'] = openssl_md5.stdout.read().strip()
53 exit_status = openssl_md5.wait()
54 if exit_status != 0: sys.exit('openssl md5 exited with status ' + str(exit_status))
55 # An MD5 hash is 16 bytes, which is 32 digits hexadecimal.
56 assert len(md5) == 32, 'MD5 sum is %u bytes' % (len(md5),)
58 dmg_filename = os.path.split(dmg_pathname)[1]
59 url = args['url'] = 'http://adiumx.cachefly.net/' + dmg_filename
61 # Because XML parsing with the standard library is a PITA, we're going to do it the hackish way.
62 xmlfile = file(appcast_path)
63 lines = []
64 is_in_item = False
65 is_correct_item = False
66 found_correct_item = False
67 for line in xmlfile:
68 if not is_in_item:
69 if '<item>' in line:
70 is_in_item = True
71 else:
72 if '</item>' in line:
73 is_in_item = False
74 is_correct_item = False
75 elif '<title>' in line:
76 if '>%(app_name)s %(old_version)s<' % args in line:
77 line = line.replace(old_version, version)
78 is_correct_item = found_correct_item = True
79 elif is_correct_item:
80 if'<pubDate>' in line:
81 line = ' <pubDate>%(dmg_mod_date)s</pubDate>\n' % args
82 elif '<sparkle:releaseNotesLink>' in line:
83 line = ' <sparkle:releaseNotesLink>%s</sparkle:releaseNotesLink>\n' % (changelog_fmt % args,)
84 elif '<enclosure' in line:
85 line = enclosure_fmt % args
86 lines.append(line)
88 if not found_correct_item:
89 sys.exit('No item found for version %(old_version)s' % args)
91 xmlfile = file(appcast_path, 'w')
92 xmlfile.writelines(lines)