mirror of
https://github.com/brl/mutter.git
synced 2024-11-22 08:00:42 -05:00
basic release script; needs work, but probably good enough for the current
2008-02-03 Thomas Thurman <tthurman@gnome.org> * tools/release-wrangler.py: basic release script; needs work, but probably good enough for the current unstable release svn path=/trunk/; revision=3541
This commit is contained in:
parent
a660fd3805
commit
836a1f7b08
@ -1,3 +1,8 @@
|
|||||||
|
2008-02-03 Thomas Thurman <tthurman@gnome.org>
|
||||||
|
|
||||||
|
* tools/release-wrangler.py: basic release script; needs work,
|
||||||
|
but probably good enough for the current unstable release
|
||||||
|
|
||||||
2008-02-02 Thomas Thurman <tthurman@gnome.org>
|
2008-02-02 Thomas Thurman <tthurman@gnome.org>
|
||||||
|
|
||||||
* src/Makefile.am: core.h is in include, not core. (Last one, I
|
* src/Makefile.am: core.h is in include, not core. (Last one, I
|
||||||
|
@ -21,45 +21,64 @@
|
|||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
# 02111-1307, USA.
|
# 02111-1307, USA.
|
||||||
|
|
||||||
# This script doesn't do all the work yet, but it will soon.
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import commands
|
import commands
|
||||||
|
import time
|
||||||
|
|
||||||
# First step is always to get up to date.
|
def report_error(message):
|
||||||
os.system("svn up")
|
print message
|
||||||
|
sys.exit(255)
|
||||||
|
|
||||||
################################################################
|
def get_up_to_date():
|
||||||
|
"First step is always to get up to date."
|
||||||
|
os.system("svn up")
|
||||||
|
|
||||||
# Are we up to date now?
|
# yes, I know this is MY username. I will come back and fix it
|
||||||
|
# later, but for now there is a lot else to do. FIXME
|
||||||
|
your_username = 'Thomas Thurman <tthurman@gnome.org>'
|
||||||
|
|
||||||
changed = []
|
def changelog_and_checkin(filename, message):
|
||||||
for line in commands.getoutput('/usr/bin/svn status').split('\n'):
|
changelog = open('ChangeLog.tmp', 'w')
|
||||||
|
changelog.write('%s %s\n\n * %s: %s\n\n' % (
|
||||||
|
time.strftime('%Y-%m-%d',time.gmtime()),
|
||||||
|
your_username,
|
||||||
|
filename,
|
||||||
|
message))
|
||||||
|
|
||||||
|
for line in open('ChangeLog').readlines():
|
||||||
|
changelog.write(line)
|
||||||
|
|
||||||
|
changelog.close()
|
||||||
|
os.rename('ChangeLog.tmp', 'ChangeLog')
|
||||||
|
|
||||||
|
os.system('svn commit -m \\"%s\\"' % (message.replace('"','\\"')))
|
||||||
|
|
||||||
|
def check_we_are_up_to_date():
|
||||||
|
changed = []
|
||||||
|
for line in commands.getoutput('/usr/bin/svn status').split('\n'):
|
||||||
if line!='' and (line[0]=='C' or line[0]=='M'):
|
if line!='' and (line[0]=='C' or line[0]=='M'):
|
||||||
changed.append(line[1:].lstrip())
|
changed.append(line[1:].lstrip())
|
||||||
|
|
||||||
if changed:
|
if changed:
|
||||||
print 'These files are out of date; I can\'t continue until you fix them.'
|
report_error('These files are out of date; I can\'t continue until you fix them: ' + \
|
||||||
print ', '.join(changed)
|
', '.join(changed))
|
||||||
sys.exit(255)
|
|
||||||
|
|
||||||
################################################################
|
def version_numbers():
|
||||||
|
# FIXME: This is all very metacity-specific. Compare fusa, etc
|
||||||
|
"""Okay, read through configure.in and find who and where we are.
|
||||||
|
|
||||||
# FIXME: This is all very metacity-specific. Compare fusa, etc
|
We also try to figure out where the next micro version number
|
||||||
#
|
will be; some programs (e.g. Metacity) use a custom numbering
|
||||||
# Okay, read through configure.in and find who and where we are.
|
scheme, and if they have a list of numbers on the line before the
|
||||||
#
|
micro version then that will be used. Otherwise we will just
|
||||||
# We also try to figure out where the next micro version number
|
increment."""
|
||||||
# will be; some programs (e.g. Metacity) use a custom numbering
|
|
||||||
# scheme, and if they have a list of numbers on the line before the
|
version = {}
|
||||||
# micro version then that will be used. Otherwise we will just
|
previous_line = ''
|
||||||
# increment.
|
for line in file("configure.in").readlines():
|
||||||
version = {}
|
|
||||||
previous_line = ''
|
|
||||||
for line in file("configure.in").readlines():
|
|
||||||
product_name = re.search("^AC_INIT\(\[([^\]]*)\]", line)
|
product_name = re.search("^AC_INIT\(\[([^\]]*)\]", line)
|
||||||
if product_name:
|
if product_name:
|
||||||
version['name'] = product_name.group(1)
|
version['name'] = product_name.group(1)
|
||||||
@ -81,59 +100,56 @@ for line in file("configure.in").readlines():
|
|||||||
try:
|
try:
|
||||||
version['micro_next'] = versions[versions.index(version_value)+1]
|
version['micro_next'] = versions[versions.index(version_value)+1]
|
||||||
except:
|
except:
|
||||||
print "You gave a list of micro version numbers, but we've used them up!"
|
report_error("You gave a list of micro version numbers, but we've used them up!")
|
||||||
sys.exit(255)
|
|
||||||
else:
|
else:
|
||||||
print "You gave a list of micro version numbers, but the current one wasn't in it!"
|
report_error("You gave a list of micro version numbers, but the current one wasn't in it! Current is %s and your list is %s" % (
|
||||||
print "Current is ",version_value
|
`version_value`, `versions`))
|
||||||
print "Your list is ",versions
|
|
||||||
sys.exit(255)
|
|
||||||
|
|
||||||
previous_line = line
|
previous_line = line
|
||||||
|
|
||||||
if not 'micro_next' in version:
|
if not 'micro_next' in version:
|
||||||
version['micro_next'] = version['micro']+1
|
version['micro_next'] = version['micro']+1
|
||||||
|
|
||||||
################################################################
|
version['string'] = '%(major)s.%(minor)s.%(micro)s' % (version)
|
||||||
|
version['filename'] = '%(name)s-%(string)s.tar.gz' % (version)
|
||||||
|
return version
|
||||||
|
|
||||||
archive_filename = '%(name)s-%(major)s.%(minor)s.%(micro)s.tar.gz' % (version)
|
def check_file_does_not_exist(version):
|
||||||
if os.access(archive_filename, os.F_OK):
|
if os.access(version['filename'], os.F_OK):
|
||||||
print "Sorry, you already have a file called %s! Please delete it or move it first." % (archive_filename)
|
report_error("Sorry, you already have a file called %s! Please delete it or move it first." % (version['filename']))
|
||||||
sys.exit(255)
|
|
||||||
|
|
||||||
################################################################
|
|
||||||
|
|
||||||
changelog = file("ChangeLog").readlines()
|
|
||||||
|
|
||||||
# Find the most recent release.
|
|
||||||
|
|
||||||
def is_date(str):
|
def is_date(str):
|
||||||
return len(str)>3 and str[4]=='-'
|
return len(str)>3 and str[4]=='-'
|
||||||
|
|
||||||
release_date = None
|
def scan_changelog(version):
|
||||||
|
changelog = file("ChangeLog").readlines()
|
||||||
|
|
||||||
for line in changelog:
|
# Find the most recent release.
|
||||||
|
|
||||||
|
release_date = None
|
||||||
|
|
||||||
|
for line in changelog:
|
||||||
if is_date(line):
|
if is_date(line):
|
||||||
release_date = line[:10]
|
release_date = line[:10]
|
||||||
if "Post-release bump to %s.%s.%s." % (version['major'], version['minor'], version['micro']) in line:
|
if "Post-release bump to %s.%s.%s." % (version['major'], version['minor'], version['micro']) in line:
|
||||||
changelog = changelog[:changelog.index(line)+1]
|
changelog = changelog[:changelog.index(line)+1]
|
||||||
break
|
break
|
||||||
|
|
||||||
contributors = {}
|
contributors = {}
|
||||||
thanks = ''
|
thanks = ''
|
||||||
entries = []
|
entries = []
|
||||||
|
|
||||||
def assumed_surname(name):
|
def assumed_surname(name):
|
||||||
# might get more complicated later, but for now...
|
# might get more complicated later, but for now...
|
||||||
return name.split()[-1]
|
return name.split()[-1]
|
||||||
|
|
||||||
def assumed_forename(name):
|
def assumed_forename(name):
|
||||||
return name.split()[0]
|
return name.split()[0]
|
||||||
|
|
||||||
bug_re = re.compile('bug \#?(\d+)', re.IGNORECASE)
|
bug_re = re.compile('bug \#?(\d+)', re.IGNORECASE)
|
||||||
hash_re = re.compile('\#(\d+)')
|
hash_re = re.compile('\#(\d+)')
|
||||||
|
|
||||||
for line in changelog:
|
for line in changelog:
|
||||||
if is_date(line):
|
if is_date(line):
|
||||||
line = line[10:].lstrip()
|
line = line[10:].lstrip()
|
||||||
line = line[:line.find('<')].rstrip()
|
line = line[:line.find('<')].rstrip()
|
||||||
@ -145,12 +161,8 @@ for line in changelog:
|
|||||||
if match:
|
if match:
|
||||||
entries[-1] += ' (#%s)' % (match.group(1))
|
entries[-1] += ' (#%s)' % (match.group(1))
|
||||||
|
|
||||||
contributors_list = contributors.keys()
|
# FIXME: getting complex enough we should be returning a dictionary
|
||||||
contributors_list.sort()
|
return (contributors, changelog, entries, release_date)
|
||||||
thanksline = ', '.join([contributors[x] for x in contributors_list])
|
|
||||||
thanksline = thanksline.replace(contributors[contributors_list[-1]], 'and '+contributors[contributors_list[-1]])
|
|
||||||
|
|
||||||
version_string = '%(major)s.%(minor)s.%(micro)s' % (version)
|
|
||||||
|
|
||||||
def wordwrap(str, prefix=''):
|
def wordwrap(str, prefix=''):
|
||||||
"Really simple wordwrap"
|
"Really simple wordwrap"
|
||||||
@ -175,30 +187,50 @@ def wordwrap(str, prefix=''):
|
|||||||
|
|
||||||
return '\n'.join(result).replace('(',' (')
|
return '\n'.join(result).replace('(',' (')
|
||||||
|
|
||||||
thanks = '%s\n%s\n\n' % (version_string, '='*len(version_string))
|
def favourite_editor():
|
||||||
thanks += wordwrap('Thanks to %s for improvements in this version.' % (thanksline))
|
e = os.environ
|
||||||
thanks += '\n\n'
|
if e.has_key('VISUAL'): return e['VISUAL']
|
||||||
for line in entries:
|
if e.has_key('EDITOR'): return e['EDITOR']
|
||||||
|
if os.access('/usr/bin/nano', os.F_OK):
|
||||||
|
return '/usr/bin/nano'
|
||||||
|
report_error("I can't find an editor for you!")
|
||||||
|
|
||||||
|
def edit_news_entry(version):
|
||||||
|
|
||||||
|
# FIXME: still needs a lot of tidying up. Translator stuff especially needs to be
|
||||||
|
# factored out into a separate function.
|
||||||
|
|
||||||
|
(contributors, changelog, entries, release_date) = scan_changelog(version)
|
||||||
|
|
||||||
|
contributors_list = contributors.keys()
|
||||||
|
contributors_list.sort()
|
||||||
|
thanksline = ', '.join([contributors[x] for x in contributors_list])
|
||||||
|
thanksline = thanksline.replace(contributors[contributors_list[-1]], 'and '+contributors[contributors_list[-1]])
|
||||||
|
|
||||||
|
thanks = '%s\n%s\n\n' % (version['string'], '='*len(version['string']))
|
||||||
|
thanks += wordwrap('Thanks to %s for improvements in this version.' % (thanksline))
|
||||||
|
thanks += '\n\n'
|
||||||
|
for line in entries:
|
||||||
thanks += ' - xxx %s\n' % (line)
|
thanks += ' - xxx %s\n' % (line)
|
||||||
|
|
||||||
# and now pick up the translations.
|
# and now pick up the translations.
|
||||||
|
|
||||||
translations = {}
|
translations = {}
|
||||||
language_re = re.compile('\*\s*(.+)\.po')
|
language_re = re.compile('\*\s*(.+)\.po')
|
||||||
|
|
||||||
for line in file("po/ChangeLog").readlines():
|
for line in file("po/ChangeLog").readlines():
|
||||||
match = language_re.search(line)
|
match = language_re.search(line)
|
||||||
if match:
|
if match:
|
||||||
translations[match.group(1)] = 1
|
translations[match.group(1)] = 1
|
||||||
if is_date(line) and line[:10]<release_date:
|
if is_date(line) and line[:10]<release_date:
|
||||||
break
|
break
|
||||||
|
|
||||||
translator_list = translations.keys()
|
translator_list = translations.keys()
|
||||||
translator_list.sort()
|
translator_list.sort()
|
||||||
|
|
||||||
last_translator_re = re.compile('Last-Translator:([^<"]*)', re.IGNORECASE)
|
last_translator_re = re.compile('Last-Translator:([^<"]*)', re.IGNORECASE)
|
||||||
|
|
||||||
def translator_name(language):
|
def translator_name(language):
|
||||||
name = 'unknown'
|
name = 'unknown'
|
||||||
for line in file('po/%s.po' % (language)).readlines():
|
for line in file('po/%s.po' % (language)).readlines():
|
||||||
match = last_translator_re.search(line)
|
match = last_translator_re.search(line)
|
||||||
@ -207,71 +239,103 @@ def translator_name(language):
|
|||||||
break
|
break
|
||||||
return "%s (%s)" % (name, language)
|
return "%s (%s)" % (name, language)
|
||||||
|
|
||||||
thanks += '\nTranslations\n'
|
thanks += '\nTranslations\n'
|
||||||
thanks += wordwrap(', '.join([translator_name(x) for x in translator_list]), ' ')
|
thanks += wordwrap(', '.join([translator_name(x) for x in translator_list]), ' ')
|
||||||
thanks += '\n\n'
|
thanks += '\n\n'
|
||||||
|
|
||||||
changes = '## '+ ' '.join(changelog).replace('\n', '\n## ')
|
changes = '## '+ ' '.join(changelog).replace('\n', '\n## ')
|
||||||
|
|
||||||
filename = posixpath.expanduser("~/.release-wrangler-%(name)s-%(major)s-%(minor)s-%(micro)s.txt" % version)
|
filename = posixpath.expanduser("~/.release-wrangler-%(name)s-%(string)s.txt" % version)
|
||||||
tmp = open(filename, 'w')
|
tmp = open(filename, 'w')
|
||||||
tmp.write('## You are releasing %(name)s, version %(major)s.%(minor)s.%(micro)s.\n' % version)
|
tmp.write('## You are releasing %(name)s, version %(major)s.%(minor)s.%(micro)s.\n' % version)
|
||||||
tmp.write('## The text at the foot of the page is the part of the ChangeLog which\n')
|
tmp.write('## The text at the foot of the page is the part of the ChangeLog which\n')
|
||||||
tmp.write('## has changed since the last release. Please summarise it.\n')
|
tmp.write('## has changed since the last release. Please summarise it.\n')
|
||||||
tmp.write('## Anything preceded by a # is ignored.\n')
|
tmp.write('## Anything preceded by a # is ignored.\n')
|
||||||
tmp.write(thanks)
|
tmp.write(thanks)
|
||||||
tmp.write(changes)
|
tmp.write(changes)
|
||||||
tmp.close()
|
tmp.close()
|
||||||
|
|
||||||
os.spawnl(os.P_WAIT, '/bin/nano', 'nano', '+6', filename)
|
os.system(favourite_editor()+' +6 %s ' % (filename))
|
||||||
|
|
||||||
################################################################
|
# Write it out to NEWS
|
||||||
|
|
||||||
# Write it out to NEWS
|
news_tmp = open('NEWS.tmp', 'a')
|
||||||
|
for line in open(filename, 'r').readlines():
|
||||||
news_tmp = open('NEWS.tmp', 'a')
|
|
||||||
for line in open(filename, 'r').readlines():
|
|
||||||
if line=='' or line[0]!='#':
|
if line=='' or line[0]!='#':
|
||||||
news_tmp.write(line)
|
news_tmp.write(line)
|
||||||
|
|
||||||
for line in open('NEWS').readlines():
|
for line in open('NEWS').readlines():
|
||||||
news_tmp.write(line)
|
news_tmp.write(line)
|
||||||
|
|
||||||
news_tmp.close()
|
news_tmp.close()
|
||||||
|
|
||||||
os.rename('NEWS.tmp', 'NEWS')
|
os.rename('NEWS.tmp', 'NEWS')
|
||||||
|
changelog_and_checkin('NEWS', '%(major)s.%(minor)s.%(micro)s release.' % (version))
|
||||||
|
|
||||||
################################################################
|
def build_it_all(version):
|
||||||
|
"Now build the thing."
|
||||||
|
autogen_prefix= '/prefix' # FIXME: this is specific to tthurman's laptop!
|
||||||
|
|
||||||
# Now build the thing.
|
# FIXME: These should use os.system
|
||||||
|
|
||||||
autogen_prefix= '/prefix' # FIXME: this is specific to tthurman's laptop!
|
if os.spawnl(os.P_WAIT, './autogen.sh', './autogen.sh', '--prefix', autogen_prefix) != 0:
|
||||||
|
|
||||||
if os.spawnl(os.P_WAIT, './autogen.sh', './autogen.sh', '--prefix', autogen_prefix) != 0:
|
|
||||||
print 'autogen failed'
|
print 'autogen failed'
|
||||||
sys.exit(255)
|
sys.exit(255)
|
||||||
|
|
||||||
if os.spawnl(os.P_WAIT, '/usr/bin/make', '/usr/bin/make') != 0:
|
if os.spawnl(os.P_WAIT, '/usr/bin/make', '/usr/bin/make') != 0:
|
||||||
print 'make failed'
|
print 'make failed'
|
||||||
sys.exit(255)
|
sys.exit(255)
|
||||||
|
|
||||||
if os.spawnl(os.P_WAIT, '/usr/bin/make', '/usr/bin/make', 'install') != 0:
|
if os.spawnl(os.P_WAIT, '/usr/bin/make', '/usr/bin/make', 'install') != 0:
|
||||||
print 'install failed'
|
print 'install failed'
|
||||||
sys.exit(255)
|
sys.exit(255)
|
||||||
|
|
||||||
if os.spawnl(os.P_WAIT, '/usr/bin/make', '/usr/bin/make', 'distcheck') != 0:
|
if os.spawnl(os.P_WAIT, '/usr/bin/make', '/usr/bin/make', 'distcheck') != 0:
|
||||||
print 'distcheck failed'
|
print 'distcheck failed'
|
||||||
sys.exit(255)
|
sys.exit(255)
|
||||||
|
|
||||||
if not os.access(archive_filename, os.F_OK):
|
if not os.access(version['filename'], os.F_OK):
|
||||||
print "Sorry, we don't appear to have a file called %s!" % (archive_filename)
|
print "Sorry, we don't appear to have a file called %s!" % (archive_filename)
|
||||||
sys.exit(255)
|
sys.exit(255)
|
||||||
|
|
||||||
# No, we won't have a configuration option to set your name on svn.g.o; that's
|
def upload(version):
|
||||||
# what ~/.ssh/config is for.
|
# No, we won't have a configuration option to set your name on master.g.o; that's
|
||||||
|
# what ~/.ssh/config is for.
|
||||||
|
|
||||||
print "Uploading..."
|
print "Uploading..."
|
||||||
upload_result = commands.getstatusoutput('scp %s master.gnome.org:' % (archive_filename))
|
upload_result = commands.getstatusoutput('scp %s master.gnome.org:' % (version['filename']))
|
||||||
|
|
||||||
|
if upload_result[0]!=0:
|
||||||
|
report_error("There appears to have been an uploading problem: %d\n%s\n" % (upload_result[0], upload_result[1]))
|
||||||
|
|
||||||
|
def increment_version(version):
|
||||||
|
configure_in = file('configure.in.tmp', 'w')
|
||||||
|
for line in file('configure.in'):
|
||||||
|
if re.search("^m4_define\(\[.*_micro_version\], \[(\d+)\]", line):
|
||||||
|
line = line.replace('[%(micro)s]' % version, '[%(micro_next)s]' % version)
|
||||||
|
configure_in.write(line)
|
||||||
|
|
||||||
|
configure_in.close()
|
||||||
|
os.rename('configure.in.tmp', 'configure.in')
|
||||||
|
|
||||||
|
changelog_and_checkin('configure.in', 'Post-release bump to %(major)s.%(minor)s.%(micro_next)s.' % version)
|
||||||
|
|
||||||
|
def tag_the_release(version):
|
||||||
|
version['ucname'] = name.upper()
|
||||||
|
os.system("svn cp -m release . svn+ssh://svn.gnome.org/svn/%(name)s/tags/%(ucname)s_%(major)s_%(minor)_%(micro)" % (version))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
get_up_to_date()
|
||||||
|
check_we_are_up_to_date()
|
||||||
|
version = version_numbers()
|
||||||
|
check_file_does_not_exist(version)
|
||||||
|
edit_news_entry(version)
|
||||||
|
build_it_all(version)
|
||||||
|
tag_the_release(version)
|
||||||
|
increment_version(version)
|
||||||
|
upload(version)
|
||||||
|
print "-- Done --"
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
if upload_result[0]!=0:
|
|
||||||
print "There appears to have been an uploading problem: %d\n%s\n" % (upload_result[0], upload_result[1])
|
|
||||||
|
Loading…
Reference in New Issue
Block a user