releng r929 - in trunk: . tools/maintainer



Author: mr
Date: Wed Jan 16 09:43:18 2008
New Revision: 929
URL: http://svn.gnome.org/viewvc/releng?rev=929&view=rev

Log:
Added maintainer script

Added:
   trunk/tools/maintainer/
   trunk/tools/maintainer/AUTHOR
   trunk/tools/maintainer/ChangeLog
   trunk/tools/maintainer/Makefile
   trunk/tools/maintainer/README
   trunk/tools/maintainer/announcer.py   (contents, props changed)
   trunk/tools/maintainer/maintainer.py   (contents, props changed)
Modified:
   trunk/ChangeLog

Added: trunk/tools/maintainer/AUTHOR
==============================================================================
--- (empty file)
+++ trunk/tools/maintainer/AUTHOR	Wed Jan 16 09:43:18 2008
@@ -0,0 +1 @@
+Martyn Russell <martyn imendio com>

Added: trunk/tools/maintainer/Makefile
==============================================================================
--- (empty file)
+++ trunk/tools/maintainer/Makefile	Wed Jan 16 09:43:18 2008
@@ -0,0 +1,12 @@
+all:
+	@echo "Use make install or make uninstall"
+
+scripts = maintainer.py announcer.py
+
+install: $(scripts) 
+	/usr/bin/install -t $(HOME)/bin maintainer.py
+	/usr/bin/install -t $(HOME)/bin announcer.py
+	
+uninstall: $(scripts)
+	/bin/rm -f $(HOME)/bin/maintainer.py
+	/bin/rm -f $(HOME)/bin/announcer.py

Added: trunk/tools/maintainer/README
==============================================================================
--- (empty file)
+++ trunk/tools/maintainer/README	Wed Jan 16 09:43:18 2008
@@ -0,0 +1,13 @@
+These scripts are here to help maintainers release and announce
+package releases.
+
+maintainer.py:
+==============
+Used by maintainers to do some of the laborious tasks when releasing
+an application, like retrieving a list of fixes from Bugzilla,
+creating a release note, etc.
+
+announcer.py:
+=============
+Used to produce an email template based on the debian/changelog so
+that you can literally just press 'send' in your email application.

Added: trunk/tools/maintainer/announcer.py
==============================================================================
--- (empty file)
+++ trunk/tools/maintainer/announcer.py	Wed Jan 16 09:43:18 2008
@@ -0,0 +1,200 @@
+#!/usr/bin/env python
+#
+# Python script useful to maintainers.
+# Copyright (C) 2007 Martyn Russell <martyn imendio com> 
+#
+#
+# This script will:
+#  - Prepare an announcement email ready for you to just click 'Send'
+#
+# Usage:
+#  - You should run this script from the directory of the project you maintain.
+#  - You need to specify an address to send to, this will NOT send it for you.
+#  
+# Changes:
+#  - If you make _ANY_ changes, please send them in so I can incorporate them.
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+import sys
+import os
+import re
+import optparse
+import gnomevfs, gobject
+import StringIO
+from string import Template
+
+# Script
+script_name = 'Release Mail Templater'
+script_version = '0.1'
+script_about = 'A script to create a release email templates.'
+
+# Email variables
+email_signature = '''--
+Regards,
+Martyn
+
+Imendio AB, http://www.imendio.com'''
+
+# Templates
+body_template = '''Hi,
+
+A new version of $product is now available:
+
+$release_url
+
+The changes are:
+
+$changes
+$signature'''
+
+
+def get_svn_root():
+        info = os.popen('svn info --xml').read()
+
+        key = '<root>'
+        start = info.find(key)
+        if start == -1:
+                print 'Could not get Root (start) for subversion details'
+                sys.exit(1)
+
+        start += len(key)
+
+        key = '</root>'
+        end = info.find(key, start)
+        if end == -1:
+                print 'Could not get Root (end) for subversion details'
+                sys.exit(1)
+
+        return info[start:end]
+
+def get_debian_product():
+	f = open('debian/changelog', 'r')
+	s = f.readline()
+	f.close()
+
+	exp = '^(?P<product>.*) \((?P<release>.*)\)'
+	pattern = re.compile(exp, re.S | re.M)
+	match = pattern.match(s)
+
+	if match:
+		product = match.group('product')
+	else:
+                print 'Could not get product and release from debian/changelog'
+                sys.exit()
+
+	return product
+
+def get_debian_release():
+        f = open('debian/changelog', 'r')
+        s = f.readline()
+        f.close()
+
+        exp = '^(?P<product>.*) \((?P<release>.*)\) '
+        pattern = re.compile(exp, re.S | re.M)
+        match = pattern.match(s)
+
+        if match:
+                release = match.group('release')
+        else:   
+                print 'Could not get product and release from debian/changelog'
+                sys.exit()
+
+        return release
+
+def get_debian_changes():
+        f = open('debian/changelog', 'r')
+        s = f.read()
+        f.close()
+
+        exp = '\A.*\n\n(?P<changes>(  \* .*\n)+)'
+        pattern = re.compile(exp)
+        match = pattern.match(s)
+
+        if match:
+                changes = match.group('changes')
+        else:
+                print 'Could not get changes from debian/changelog'
+                sys.exit()
+
+        return changes
+
+def get_release_url():
+	root = get_svn_root()
+	release = get_debian_release()
+	product = get_debian_product()
+
+	url = "%s/tags/%s/%s" % (root, product, release)
+	
+	return url
+
+def get_release_body(product, release_url, changes, signature):
+        t = Template(body_template)
+        text = t.substitute(locals())
+
+	body = ''
+
+ 	for line in text.splitlines():
+		body = body + line + '%0d'
+
+	return body
+
+
+# Start
+usage = "usage: %s -t <email-address> [options]" % sys.argv[0]
+
+popt = optparse.OptionParser(usage)
+popt.add_option('-v', '--version',
+                action = 'count',
+                dest = 'version',
+                help = 'show version information')
+popt.add_option('-t', '--to',
+                action = 'store',
+                dest = 'to',
+                help = 'Who to send the mail to')
+popt.add_option('-c', '--cc',
+                action = 'store',
+                dest = 'cc',
+                help = 'Who to cc the mail to')
+
+(opts, args) = popt.parse_args()
+
+if opts.version:
+        print '%s %s\n%s\n' % (script_name, script_version, script_about)
+        sys.exit()
+
+if not opts.to:
+	print 'No address to send the mail to specified'
+	print usage
+	sys.exit()
+
+# Create template
+product = get_debian_product()
+release = get_debian_release()
+changes = get_debian_changes()
+release_url = get_release_url()
+body = get_release_body(product, release_url, changes, email_signature)
+
+subject = 'ANNOUNCE: %s %s released' % (product, release)
+
+if opts.cc:
+	url = 'mailto:%s?cc=%s&subject=%s&body=%s' % (opts.to, opts.cc, subject, body)
+else:
+	url = 'mailto:%s?subject=%s&body=%s' % (opts.to, subject, body)
+	
+gnomevfs.url_show(url)
+

Added: trunk/tools/maintainer/maintainer.py
==============================================================================
--- (empty file)
+++ trunk/tools/maintainer/maintainer.py	Wed Jan 16 09:43:18 2008
@@ -0,0 +1,1097 @@
+#!/usr/bin/env python
+#
+# Python script useful to maintainers.
+# Copyright (C) 2006-2007 Martyn Russell <martyn imendio com> 
+#
+# This script will:
+#  - Summarise bugs mentioned in the ChangeLog (from Bugzilla)
+#  - List translation updates
+#  - List bugs fixed
+#  - Output the summary and translations using a template (in HTML too)
+#  - Upload your tarball and install the module.
+#  - Create the email for you just to send it.
+#
+# Usage:
+#  - You should run this script from the directory of the project you maintain.
+#  - You need to specify a revision to compare the HEAD/TRUNK.
+#  
+# Changes:
+#  - If you make _ANY_ changes, please send them in so I can incorporate them.
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+import sys
+import os
+import string
+import re
+import urllib
+import csv
+import optparse
+import time
+import datetime 
+import gnomevfs, gobject
+import StringIO
+from string import Template
+
+# Script
+script_name = 'Maintainer'
+script_version = '0.7'
+script_about = 'A script to do the laborious tasks when releasing a GNOME project.'
+
+# Translation directories
+po_dir = 'po'
+help_dir = 'help'
+
+# Commands
+vc_command = ''
+vc_parameters = ''
+
+# Addresses
+upload_server = 'master.gnome.org'
+
+# Formatting 
+format_bullet = '-'
+format_date = '%d %B %Y'
+
+# Cached bug IDs to names
+bug_names = {}
+
+# Cached package info
+package_name = ''
+package_version = ''
+package_module = ''
+
+# Default templates
+template = '''
+$name $version is now available for download from:
+$download
+
+$md5sums
+
+What is it?
+===========
+$about
+
+Where can I find out more?
+==========================
+You can visit the project web site:
+$website
+
+What's New?
+===========
+$news
+
+Bugs Fixed:
+===========
+$fixed
+
+Translations:
+=============
+$translations
+
+Manual Translations:
+====================
+$help_translations
+
+
+$footer
+'''
+
+template_in_html = '''
+<p>$name $version is now available for download from:</p>
+<ul>
+  <li><a href="$download">$download</a></li>
+</ul>
+<p>$md5sums</p>
+
+<h3>What is it?</h3>
+<p>$about</p>
+
+<h3>Where can I find out more?</h3>
+<p>You can visit the project web site:</p>
+<ul>
+  <li><a href="$website">$website</a></li>
+</ul>
+
+<h3>What's New</h3>
+$news
+
+<h3>Bugs Fixed</h3>
+$fixed
+
+<h3>Translations</h3>
+$translations
+
+<h3>Help Manual Translations</h3>
+$help_translations
+
+$footer
+'''
+
+template_update_news = '''
+NEW in %s:
+==============
+%s
+
+Translations:
+%s
+
+Help Manual Translations:
+%s
+
+'''
+
+def get_package_info():
+        global package_name
+        global package_version
+        global package_module
+        global vc_command
+        global vc_paramters
+
+        # Don't do this ALL over again if we already have the information
+        if len(package_name) > 0:
+                return
+
+        if os.path.exists('CVS'):
+		if opts.debug: 
+			print 'Version control system is CVS'
+
+		vc_command = 'cvs'
+		vc_parameters = '-u'
+	elif os.path.exists('.svn'):
+		if opts.debug: 
+			print 'Version control system is SVN'
+
+		vc_command = 'svn'
+		vc_parameters = ''
+	else:
+		print 'Version control system unrecognised, not cvs or svn'
+		sys.exit(1)
+
+        if not os.path.exists('config.h'):
+                print 'Could not find config.h in current directory'
+                sys.exit(1)
+        
+        f = open('config.h', 'r')
+        s = f.read()
+        f.close()
+
+        key = {}
+        key['package'] = '#define PACKAGE_NAME "'
+        key['version'] = '#define PACKAGE_VERSION "'
+        key['bugreport'] = '#define PACKAGE_BUGREPORT "'
+
+        for line in s.splitlines(1):
+                if line.startswith(key['package']):
+                        p1 = len(key['package'])
+                        p2 = line.rfind('"')
+                        p_name = line[p1:p2] 		
+                elif line.startswith(key['version']):
+                        p1 = len(key['version'])
+                        p2 = line.rfind('"')
+                        p_version = line[p1:p2] 		
+                elif line.startswith(key['bugreport']):
+                        p2 = line.rfind('"')
+                        p1 = line.rfind('=') + 1
+                        p_module = line[p1:p2] 		
+
+        if len(p_name) < 1:
+                print 'Could not obtain package name from config.h'
+                sys.exit(1)
+
+        if len(p_version) < 1:
+                print 'Could not obtain package version from config.h'
+                sys.exit(1)
+
+        package_name = p_name;
+        package_version = p_version;
+        package_module = p_module;
+
+def get_svn_root():
+	info = os.popen('svn info --xml').read()
+
+	key = '<root>'
+	start = info.find(key)
+	if start == -1:
+		print 'Could not get Root (start) for subversion details'
+		sys.exit(1)
+
+	start += len(key)	
+		
+	key = '</root>'
+	end = info.find(key, start)
+	if end == -1:	
+		print 'Could not get Root (end) for subversion details'
+		sys.exit(1)
+
+	return info[start:end]
+
+def get_svn_url():
+	info = os.popen('svn info --xml').read()
+
+	key = '<url>'
+	start = info.find(key)
+	if start == -1:
+		print 'Could not get URL (start) for subversion details'
+		sys.exit(1)
+
+	start += len(key)	
+		
+	key = '</url>'
+	end = info.find(key, start)
+	if end == -1:	
+		print 'Could not get URL (end) for subversion details'
+		sys.exit(1)
+
+	return info[start:end]
+
+def get_bugs(tag):
+        get_package_info()
+
+	if vc_command == 'cvs':
+		cmd = '%s diff %s -r %s ChangeLog' % (vc_command, vc_parameters, tag)
+	elif vc_command == 'svn':
+                url = get_svn_url()
+                root = get_svn_root()
+
+		revision = "%s/tags/%s" % (root, tag)
+		if opts.debug: 
+	        	print 'Using SVN root: %s...' % (root) 
+	        	print 'Using SVN diff url1: %s...' % (url) 
+	        	print 'Using SVN diff url2: %s...' % (revision) 
+
+		cmd = '%s diff %s %s/ChangeLog %s/ChangeLog' % (vc_command, vc_parameters, revision, url)
+	else:
+		print 'Version control system unrecognised, not cvs or svn'
+		sys.exit(1)
+
+        bugs = ''
+        
+        # Pattern to match ChangeLog entry
+        exp = '^\+(?P<date>[0-9][0-9][0-9][0-9]\-[0-9][0-9]\-[0-9][0-9]) ' \
+              '(?P<name>.*) <* *>*'
+        changelog_pattern = re.compile(exp, re.S | re.M)
+
+        # Patter to match bug fixers name, e.g.: "#123456 (Martyn Russell)"
+        exp = '.*#(?P<bug>[0-9]+)(.*\((?P<name>.*)\))?'
+        bugfix_pattern = re.compile(exp, re.S | re.M)
+
+	if opts.debug: 
+	        print 'Retrieving bug changes since tag: %s...' % (tag) 
+
+	pos = 0
+	changes = os.popen(cmd).read()
+
+	while not pos == -1:
+		start = pos
+
+		# Find end of first line
+		end = changes.find('\n', pos)
+		line = changes[pos:end]
+
+		pos = end + 1
+
+		# Try and get the second line
+		end = changes.find('\n', pos)
+		if not end == -1:
+			line = changes[start:end]
+
+		if len(line) < 1:
+			break
+
+		# Check this is a change 	
+                if not line[0] == '+':
+                        continue
+
+		# Get committer details
+                match = changelog_pattern.match(line)
+		if match:
+			last_committer = match.group('name')	
+			continue
+
+		# Get bug fix details
+		match = bugfix_pattern.match(line)
+		if not match:
+			continue
+
+		bug = match.group('bug')
+		name = match.group('name')
+
+		if bug == '':
+			continue
+		
+		if name == None:	
+			name = last_committer.strip()
+			method = 'cvs user'
+		else:
+			name = name.replace('\n', '')
+			name = name.replace('\t', '')
+			name = name.replace('+', ' ')
+			name = name.strip()
+			method = 'patch'
+
+		# Set name for bug
+                bug_names[bug] = name
+
+		if bugs.find(bug) > -1:
+			continue
+
+		# Add bug to list
+                if not bugs == '':
+                       	bugs = bugs + ','
+
+               	bugs = bugs + bug
+                
+        return bugs
+
+def get_summary(bugs):
+	if bugs == '':
+		return 'No summary due to no bugs';
+
+        # Bugzilla query to use
+        query = 'http://bugzilla.gnome.org/buglist.cgi?ctype=csv' \
+                '&bug_status=RESOLVED,CLOSED,VERIFIED' \
+                '&resolution=FIXED' \
+                '&bug_id='
+        query = query + bugs.replace(',', '%2c')
+
+	if opts.debug:
+	        print 'Retrieving bug information for: %s...' % (bugs)
+
+        f = urllib.urlopen(query)
+        s = f.read()
+        f.close()
+
+        col_bug_id = -1
+        col_description = -1
+
+        reader = csv.reader(s.splitlines(1))
+        header = reader.next()
+        i = 0
+
+        for col in header:
+                if col == 'bug_id':
+                        col_bug_id = i
+                if col == 'short_short_desc':
+                        col_description = i
+
+                i = i + 1
+
+        if col_bug_id == -1 or col_description == -1:
+                print 'Could not identify the bug id or description columns'
+                sys.exit()
+
+        summary = ''
+
+	if opts.html:
+		summary += '<ul>'
+	
+        for row in reader:
+                bug_number = row[col_bug_id]
+                description = row[col_description]
+                who = bug_names[bug_number]
+
+                if len(summary) > 0:
+                        summary += '\n'
+
+                if opts.html:
+                        link = "http://bugzilla.gnome.org/show_bug.cgi?id=%s"; % (bug_number)
+                        bug = "<a href=\"%s\">#%s</a>" % (link, bug_number)
+                else:
+                        bug = "#%s" % (bug_number)
+
+	        text = 'Fixed %s, %s (%s)' % (bug, description, who)
+
+		if opts.html:
+			summary += '<li>%s</li>' % (text)
+		else: 
+			summary += '%s %s' % (format_bullet, text)
+
+	if opts.html:
+		summary += '\n</ul>'
+
+	if summary == '':
+		summary = 'None'
+
+        return summary
+
+def get_translators(tag, dir):
+        get_package_info()
+
+	if vc_command == 'cvs':
+                cmd = '%s diff -u -r %s %s/ChangeLog' % (vc_command, tag, dir)
+	elif vc_command == 'svn':
+                url = get_svn_url()
+                root = get_svn_root()
+
+		revision = "%s/tags/%s" % (root, tag)
+		if opts.debug: 
+	        	print 'Using SVN root: %s...' % (root) 
+	        	print 'Using SVN diff url1: %s...' % (url) 
+	        	print 'Using SVN diff url2: %s...' % (revision) 
+
+		cmd = '%s diff %s %s/%s/ChangeLog %s/%s/ChangeLog' % (vc_command, vc_parameters, revision, dir, url, dir)
+	else:
+		print 'Version control system unrecognised, not cvs or svn'
+		sys.exit(1)
+
+
+        translators = {}
+
+        # Pattern to match ChangeLog entry
+        exp = '^\+(?P<date>[0-9][0-9][0-9][0-9]\-[0-9][0-9]\-[0-9][0-9]) ' \
+              '(?P<name>.*) <* *>*'
+        changelog_pattern = re.compile(exp, re.S | re.M)
+
+        # Pattern to match language and sponsored name for change, e.g.: 
+        # "en_GB.po: Updated by (Martyn Russell)"
+        exp = '.*\* (.*/)?(?P<lang>.*).po: (.*\((?P<name>.*)\))?'
+        lang_pattern = re.compile(exp, re.S | re.M)
+
+        if opts.debug:
+		print 'Retrieving PO changes for %s dir since tag: %s...' % (dir, tag) 
+
+	pos = 0
+	changes = os.popen(cmd).read()
+
+	while not pos == -1:
+		start = pos
+
+		# Find end of first line
+		end = changes.find('\n', pos)
+		line = changes[pos:end]
+
+		pos = end + 1
+
+		# Try and get the second line
+		end = changes.find('\n', pos)
+		if not end == -1:
+			line = changes[start:end]
+
+		if len(line) < 1:
+			break
+
+		# Check this is a change 	
+                if not line[0] == '+':
+                        continue
+
+		# Get committer details
+                match = changelog_pattern.match(line)
+		if match:
+			last_committer = match.group('name')	
+			continue
+
+		# Get bug fix details
+		match = lang_pattern.match(line)
+		if not match:
+			continue
+
+		lang = match.group('lang')
+		name = match.group('name')
+
+		if lang == '':
+			continue
+		
+		if name == None:	
+			name = last_committer.strip()
+		else:
+			name = name.replace('\n', '')
+			name = name.replace('\t', '')
+			name = name.replace('+', ' ')
+			name = name.strip()
+
+                if translators.has_key(lang):
+                        if translators[lang].find(name) > -1:
+                                continue;	
+
+                        translators[lang] += ', ' + name 
+                else:
+                        translators[lang] = name
+
+	summary = ''
+
+	if opts.html:
+		summary += '<ul>'
+	
+        for lang in translators:
+                if len(summary) > 0:
+                        summary += '\n'
+
+                text = 'Updated %s: %s' % (lang, translators[lang])
+
+		if opts.html:
+			summary += '<li>%s</li>' % (text)
+		else: 
+			summary += '%s %s' % (format_bullet, text)
+
+	if opts.html:
+		summary += '\n</ul>'
+
+	if summary == '':
+		summary = 'None'
+
+        return summary
+
+def get_description():
+        get_package_info()
+
+	if opts.debug:
+	        print 'Retrieving product descripton for %s ...' % (package_name)
+
+	query = 'http://bugzilla.gnome.org/browse.cgi?product=%s' % (package_module)
+        f = urllib.urlopen(query)
+        s = f.read()
+        f.close()
+
+        if len(s) < 1:
+                return ''
+        
+        #
+        # HACK ALERT! HACK ALERT!
+        #
+        # This is likely to change if the Bugzilla page formatting changes, so 
+        # we put a lot of debugging in here.
+
+        s1 = '<p><i>'
+        i = s.find(s1)
+        if i == -1:
+        	if opts.debug:
+        	       	print 'Could not find string "%s"' % (s1) 
+        
+                return ''
+	
+	start = i + len(s1)
+
+        s2 = '</i></p>'
+        end = s.find(s2, i + 1)
+        if end == -1:
+        	if opts.debug:
+        	       	print 'Could not find string "%s"' % (s2) 
+        
+                return ''
+	
+	# Get description
+	description = s[start:end]
+
+	return description
+
+def get_website():
+        get_package_info()
+
+	if opts.debug:
+	        print 'Retrieving product website for %s ...' % (package_name)
+
+	query = 'http://bugzilla.gnome.org/browse.cgi?product=%s' % (package_module)
+        f = urllib.urlopen(query)
+        s = f.read()
+        f.close()
+
+        if len(s) < 1:
+                return ''
+
+	# Get Homepage
+	s1 = "GNOME SVN"
+	i = s.find(s1)
+        if i == -1:
+                if opts.debug:
+        	       	print 'Could not find string "%s"' % (s1) 
+        
+                return ''
+
+	s1 = "href"
+	i = s.find(s1, i)
+        if i == -1:
+        	if opts.debug:
+        	       	print 'Could not find string "%s"' % (s1) 
+        
+                return ''
+        
+        start = i + 6
+
+        s2 = '">'
+        end = s.find(s2, start)
+        if end == -1:
+        	if opts.debug:
+        	       	print 'Could not find string "%s"' % (s2) 
+        
+                return ''
+	
+	return s[start:end]
+
+def get_default_template():
+        if opts.html:
+                return template_in_html
+
+        return template
+
+def get_news():
+	f = open ('NEWS', 'r')
+	s = f.read()
+	f.close()
+	start = s.find ('NEW in '+ package_version)
+	start = s.find ('\n', start) + 1
+	start = s.find ('\n', start) + 1
+        end = s.find ('NEW in', start) - 1
+        return s[start:end]
+
+def get_news():
+	f = open ('NEWS', 'r')
+	s = f.read()
+	f.close()
+	start = s.find ('NEW in '+ package_version)
+	start = s.find ('\n', start) + 1
+	start = s.find ('\n', start) + 1
+        end = s.find ('NEW in', start) - 1
+        return s[start:end]
+
+def create_release_note(tag, template_file):
+        # Open template file
+        if template_file == '' or template_file == 'DEFAULT':
+                if opts.debug:
+                        print 'Using DEFAULT template'
+
+                s = get_default_template()
+        else:
+                if opts.debug:
+                        print 'Using template file "%s"' % (template_file)
+
+                f = open(template_file, 'r')
+                s = f.read()
+                f.close()
+
+        if len(s) < 1: 
+                print 'Template file was empty or does not exist'
+                sys.exit(1)
+
+        # Check we have everything
+        if s.find('$download') == -1:
+                print 'Could not find "$download" in template'
+                sys.exit(1)
+
+        if s.find('$news') == -1:
+                print 'Could not find "$news" in template'
+                sys.exit(1)
+
+        if s.find('$fixed') == -1:
+                print 'Could not find "$fixed" in template'
+                sys.exit(1)
+
+        if s.find('$translations') == -1:
+                print 'Could not find "$translations" in template'
+                sys.exit(1)
+
+        if s.find('$help_translations') == -1:
+                print 'Could not find "$help_translations" in template'
+                sys.exit(1)
+
+        # Get date for footer
+        today = datetime.date.today()
+        date = today.strftime(format_date) 
+
+        # Get package name and version
+        get_package_info()
+
+        # Set up variables
+        name = package_name
+        version = package_version
+
+        bugs = get_bugs(tag)
+       
+        download = 'http://download.gnome.org/sources/%s/%s/' % (package_name.lower(), 
+                                                                 package_version)
+
+        # Get an MD5 sum of the tarballs.
+        md5sums = ''
+        
+        cmd = 'md5sum %s-%s.tar.gz' % (package_name.lower(), package_version)
+        md5sums += os.popen(cmd).read()
+
+        cmd = 'md5sum %s-%s.tar.bz2' % (package_name.lower(), package_version)
+        md5sums += os.popen(cmd).read()
+
+        if opts.html:
+                md5sums = md5sums.replace('\n', '<br>\n')
+        
+        about = get_description()
+        website = get_website()
+
+	news = get_news()
+
+        fixed = get_summary(bugs)
+        translations = get_translators(tag, po_dir)
+        help_translations = get_translators(tag, help_dir)
+        
+        footer = '%s\n%s team' % (date, package_name)
+
+        if opts.html:
+                footer = footer.replace('\n', '<br>\n')
+                footer = '<p>%s</p>' % footer
+
+        # Substitute variables
+        t = Template(s)
+        text = t.substitute(locals())
+
+        return text
+
+def create_release_email(to, tag, template_file):
+        release_note = create_release_note(tag, template_file)
+
+        t = Template(release_note)
+        text = t.substitute(locals())
+
+	body = ''
+
+ 	for line in text.splitlines():
+		body = body + line + '%0d'
+
+        # Get package name and version
+        get_package_info()
+
+        subject = 'ANNOUNCE: %s %s released' % (package_name, package_version)
+
+	url = 'mailto:%s?subject=%s&body=%s' % (to, subject, body)
+	
+        return url;
+
+def upload_tarball():
+        get_package_info()
+
+        # This is the tarball we are going to upload
+        username = opts.upload
+        tarball = '%s-%s.tar.gz' % (package_name.lower(), package_version)
+
+        print 'Attempting to upload tarball: %s to master.gnome.org...' % (tarball)
+                
+        cmd = 'scp %s %s %s:' % (tarball, username, upload_server)
+        fp = os.popen(cmd)
+	retval = fp.read()
+	status = fp.close()
+
+        if status and (not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0):
+                print 'Unable to upload your tarball'
+        else:
+                print 'Sucessfully uploaded tarball'
+
+        print 'Attempting to install-module using tarball: %s...' % (tarball)
+                
+        cmd = 'ssh %s %s install-module -u %s' % (username, upload_server, tarball)
+        success = os.popen(cmd).read()
+
+        # Make sure we check the return value
+        fp = os.popen(cmd)
+	retval = fp.read()
+	status = fp.close()
+
+        if status and (not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0):
+                print 'Unable to install module'
+        else:
+                print 'Sucessfully installed module'
+
+
+def update_news():
+        get_package_info()
+
+        bugs = get_bugs(opts.revision)
+	if len(bugs) < 1:
+                print 'No bugs were found to update the NEWS file with'
+                sys.exit()
+
+        summary = get_summary(bugs)
+	if len(summary) < 1:
+                print 'No summary was available to update the NEWS file with'
+                sys.exit()
+
+        po_translators = get_translators(opts.revision, po_dir)
+        help_translators = get_translators(opts.revision, help_dir)
+        output = template_update_news % (package_version, summary, po_translators, help_translators)
+        
+        f = open('NEWS', 'r')
+        s = f.read()
+        f.close()
+
+        output += s;
+
+        f = open('NEWS', 'w')
+        f.write(output)
+        f.close()
+
+def tag_svn():
+	get_package_info()
+
+	new_version = opts.tag[opts.tag.find ('_')+1:].replace ('_', '.')
+	url1 = get_svn_url()
+	url2 = get_svn_root() + '/tags/' + opts.tag
+
+	cmd = 'svn copy %s %s -m "Tagged for release %s."' % (url1, url2, new_version)
+
+	if opts.debug:
+		print 'Tagging using command: ' + cmd
+
+	success = os.popen(cmd).read()
+
+	# Make sure we check the return value
+	fp = os.popen('{ %s; } 2>&1' % cmd, 'r')
+	retval = fp.read()
+	status = fp.close()
+
+	if status and (not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0):
+		print 'Unable to tag SVN'
+	else:
+		print 'Sucessfully tagged SVN'
+
+#
+# Start
+#
+usage = "usage: %s -r <revision or tag> [options]\n" \
+        "       %s --help" % (sys.argv[0], sys.argv[0])
+
+popt = optparse.OptionParser(usage)
+popt.add_option('-v', '--version',
+                action = 'count', 
+                dest = 'version',
+                help = 'show version information')
+popt.add_option('-d', '--debug',
+                action = 'count', 
+                dest = 'debug',
+                help = 'show additional debugging')
+popt.add_option('-l', '--html',
+                action = 'count', 
+                dest = 'html',
+                help = 'write output in HTML')
+popt.add_option('-c', '--confirm',
+                action = 'count', 
+                dest = 'confirm',
+                help = 'this is required for some actions as confirmation')
+popt.add_option('-b', '--get-bugs',
+                action = 'count', 
+                dest = 'get_bugs', 
+                help = 'get a list of bugs fixed')
+popt.add_option('-s', '--get-summary',
+                action = 'count', 
+                dest = 'get_summary',
+                help = 'get summary of bugs from Bugzilla')
+popt.add_option('-t', '--get-translators',
+                action = 'count', 
+                dest = 'get_translators',
+                help = 'get translation updates')
+popt.add_option('-o', '--get-manual-translators',
+                action = 'count', 
+                dest = 'get_manual_translators',
+                help = 'get manual translation updates')
+popt.add_option('-e', '--get-description',
+                action = 'count', 
+                dest = 'get_description',
+                help = 'get the description in bugzilla for this product')
+popt.add_option('-i', '--get-website',
+                action = 'count', 
+                dest = 'get_website',
+                help = 'get the website in bugzilla for this product')
+popt.add_option('-w', '--update-news',
+                action = 'count', 
+                dest = 'update_news',
+                help = 'update the news with the bugs fixed and translations')
+popt.add_option('-a', '--create-release-note',
+                action = 'count',
+                dest = 'create_release_note',
+                help = 'create a release note (can be used with -n)')
+popt.add_option('-n', '--release-note-template',
+                action = 'store', 
+                dest = 'release_note_template',
+                help = 'file to use for release note template or "DEFAULT"')
+popt.add_option('-m', '--create-release-email',
+                action = 'store',
+                dest = 'create_release_email',
+                help = 'who to address the mail to (can be used with -n)')
+popt.add_option('-u', '--upload',
+                action = 'store', 
+                dest = 'upload',
+                help = 'user name to use when uploading tarball to master.gnome.org')
+popt.add_option('-g', '--tag',
+                action = 'store', 
+                dest = 'tag',
+                help = 'Tag to add in SVN')
+popt.add_option('-r', '--revision',
+                action = 'store', 
+                dest = 'revision',
+                help = 'revision or tag to use with -s, -t and -o')
+
+errors = False
+need_tag = False
+
+(opts, args) = popt.parse_args()
+
+if opts.version:
+	print '%s %s\n%s\n' % (script_name, script_version, script_about)
+	sys.exit()
+
+if not opts.get_bugs and not opts.get_summary and \
+   not opts.get_translators and not opts.get_manual_translators and \
+   not opts.release_note_template and not opts.create_release_note and \
+   not opts.create_release_email and not opts.upload and \
+   not opts.get_description and not opts.get_website and \
+   not opts.update_news and not opts.tag:
+        print 'No option specified'
+        print usage
+        sys.exit()       
+
+if opts.get_bugs or opts.get_summary or \
+   opts.get_translators or opts.get_manual_translators or \
+   opts.create_release_note or opts.create_release_email or \
+   opts.update_news:
+        need_tag = True
+
+if need_tag and not opts.revision:
+        print 'No tag specified'
+        print usage
+        sys.exit()
+
+if opts.upload and not opts.confirm:
+	print 'Uploading WILL *INSTALL* your tarball with install-module!!'
+	print 'Are you sure you want to continue?'
+	print
+	print 'To continue, you must supply the --confirm option'
+	sys.exit()
+
+if opts.tag and not opts.confirm:
+	print 'This will create a new tag on your SVN repository!!'
+	print 'Are you sure you want to continue?'
+	print
+	print 'To continue, you must supply the --confirm option'
+	sys.exit()
+
+if opts.tag and not opts.confirm:
+	print 'This will create a new tag on your SVN repository!!'
+	print 'Are you sure you want to continue?'
+	print
+	print 'To continue, you must supply the --confirm option'
+	sys.exit()
+
+if opts.get_bugs:
+        bugs = get_bugs(opts.revision)
+	if len(bugs) < 1:
+        	print 'No bugs found fixed'
+                sys.exit(0)
+
+        if opts.debug:
+        	print '\nBugs:'
+
+        print bugs
+
+if opts.get_summary:
+        bugs = get_bugs(opts.revision)
+	if len(bugs) < 1:
+        	print 'No bugs found fixed'
+                sys.exit(0)
+
+        summary = get_summary(bugs)
+	if len(summary) < 1:
+        	print 'Could not get summary for bug fixes: %s' % (bugs)
+                sys.exit(0)
+
+       	if opts.debug:
+       		print '\nSummary:' 
+
+       	print summary
+
+if opts.get_translators:
+        translators = get_translators(opts.revision, po_dir)
+	if len(translators) < 1:
+		print 'No translation updates found'
+		sys.exit(0)
+
+        if opts.debug:
+        	print '\nTranslators:' 
+
+        print translators
+
+if opts.get_manual_translators:
+        translators = get_translators(opts.revision, help_dir)
+	if len(translators) < 1:
+		print 'No manual translation updates found'
+		sys.exit(0)
+
+        if opts.debug:
+        	print '\nManual Translators:' 
+
+        print translators
+
+if opts.get_description:
+        description = get_description()
+        if len(description) < 1:
+                print 'No description was found in bugzilla'
+                sys.exit(0)
+
+        if opts.debug:
+                print '\nDescription:'
+
+        print description
+
+if opts.get_website:
+        website = get_website()
+        if len(website) < 1:
+                print 'No website was found in bugzilla'
+                sys.exit(0)
+
+        if opts.debug:
+                print '\nWebsite:'
+
+        print website
+
+if opts.create_release_note:
+        if opts.release_note_template:
+                release_note = create_release_note(opts.revision, 
+                                                   opts.release_note_template)
+        else:
+                release_note = create_release_note(opts.revision, 
+                                                   'DEFAULT')
+
+
+        if opts.debug:
+	        print '\nRelease Note:' 
+
+        print release_note
+        
+if opts.create_release_email:
+        if opts.release_note_template:
+                url = create_release_email(opts.create_release_email, 
+                                           opts.revision, 
+                                           opts.release_note_template)
+        else:
+                url = create_release_email(opts.create_release_email, 
+                                           opts.revision, 
+                                           'DEFAULT')
+
+        if opts.debug:
+	        print '\nCreating email...' 
+
+        gnomevfs.url_show(url)
+        
+if opts.upload:
+        upload_tarball()
+
+if opts.update_news:
+        if opts.debug:
+	        print '\nUpdating News:' 
+
+        update_news()
+
+        if opts.debug:
+	        print '\nUpdated!' 
+
+if opts.tag:
+        tag_svn()
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]