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
10 # Configurable variables.
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
23 args
= dict(zip(('appcast_path', 'old_version', 'version', 'dmg_pathname'), sys
.argv
[1:]))
25 appcast_path
= args
['appcast_path']
26 old_version
= args
['old_version']
27 version
= args
['version']
28 dmg_pathname
= args
['dmg_pathname']
30 sys
.exit(__doc__
.strip())
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
)
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
)
65 is_correct_item
= False
66 found_correct_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
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
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
)