summaryrefslogtreecommitdiff
path: root/tools/regression/xsl_reports/email_maintainers.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/regression/xsl_reports/email_maintainers.py')
-rw-r--r--tools/regression/xsl_reports/email_maintainers.py840
1 files changed, 840 insertions, 0 deletions
diff --git a/tools/regression/xsl_reports/email_maintainers.py b/tools/regression/xsl_reports/email_maintainers.py
new file mode 100644
index 0000000000..308ab688f5
--- /dev/null
+++ b/tools/regression/xsl_reports/email_maintainers.py
@@ -0,0 +1,840 @@
+#
+# Copyright (C) 2005, 2007 The Trustees of Indiana University
+# Author: Douglas Gregor
+#
+# Distributed under the Boost Software License, Version 1.0. (See
+# accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+#
+import re
+import smtplib
+import os
+import time
+import string
+import datetime
+import sys
+
+report_author = "Douglas Gregor <dgregor@osl.iu.edu>"
+boost_dev_list = "Boost Developer List <boost@lists.boost.org>"
+boost_testing_list = "Boost Testing List <boost-testing@lists.boost.org>"
+
+def sorted_keys( dict ):
+ result = dict.keys()
+ result.sort()
+ return result
+
+
+class Platform:
+ """
+ All of the failures for a particular platform.
+ """
+ def __init__(self, name):
+ self.name = name
+ self.failures = list()
+ self.maintainers = list()
+ return
+
+ def addFailure(self, failure):
+ self.failures.append(failure)
+ return
+
+ def isBroken(self):
+ return len(self.failures) > 300
+
+ def addMaintainer(self, maintainer):
+ """
+ Add a new maintainer for this platform.
+ """
+ self.maintainers.append(maintainer)
+ return
+
+class Failure:
+ """
+ A single test case failure in the report.
+ """
+ def __init__(self, test, platform):
+ self.test = test
+ self.platform = platform
+ return
+
+class Test:
+ """
+ All of the failures for a single test name within a library.
+ """
+ def __init__(self, library, name):
+ self.library = library
+ self.name = name
+ self.failures = list()
+ return
+
+ def addFailure(self, failure):
+ self.failures.append(failure)
+ return
+
+ def numFailures(self):
+ return len(self.failures)
+
+ def numReportableFailures(self):
+ """
+ Returns the number of failures that we will report to the
+ maintainers of the library. This doesn't count failures on
+ broken platforms.
+ """
+ count = 0
+ for failure in self.failures:
+ if not failure.platform.isBroken():
+ count += 1
+ pass
+ pass
+ return count
+
+class Library:
+ """
+ All of the information about the failures in a single library.
+ """
+ def __init__(self, name):
+ self.name = name
+ self.maintainers = list()
+ self.tests = list()
+ return
+
+ def addTest(self, test):
+ """
+ Add another test to the library.
+ """
+ self.tests.append(test)
+ return
+
+ def addMaintainer(self, maintainer):
+ """
+ Add a new maintainer for this library.
+ """
+ self.maintainers.append(maintainer)
+ return
+
+ def numFailures(self):
+ count = 0
+ for test in self.tests:
+ count += test.numFailures()
+ pass
+ return count
+
+ def numReportableFailures(self):
+ count = 0
+ for test in self.tests:
+ count += test.numReportableFailures()
+ pass
+ return count
+
+class Maintainer:
+ """
+ Information about the maintainer of a library
+ """
+ def __init__(self, name, email):
+ self.name = name
+ self.email = email
+ self.libraries = list()
+ return
+
+ def addLibrary(self, library):
+ self.libraries.append(library)
+ return
+
+ def composeEmail(self, report):
+ """
+ Composes an e-mail to this maintainer with information about
+ the failures in his or her libraries, omitting those that come
+ from "broken" platforms. Returns the e-mail text if a message
+ needs to be sent, or None otherwise.
+ """
+
+ # Determine if we need to send a message to this developer.
+ requires_message = False
+ for library in self.libraries:
+ if library.numReportableFailures() > 0:
+ requires_message = True
+ break
+
+ if not requires_message:
+ return None
+
+ # Build the message header
+ message = """From: Douglas Gregor <dgregor@osl.iu.edu>
+To: """
+ message += self.name + ' <' + self.email + '>'
+ message += """
+Reply-To: boost@lists.boost.org
+Subject: Failures in your Boost libraries as of """
+ message += str(datetime.date.today()) + " [" + report.branch + "]"
+ message += """
+
+You are receiving this report because one or more of the libraries you
+maintain has regression test failures that are not accounted for.
+A full version of the report is sent to the Boost developer's mailing
+list.
+
+Detailed report:
+"""
+ message += ' ' + report.url + """
+
+There are failures in these libraries you maintain:
+"""
+
+ # List the libraries this maintainer is responsible for and
+ # the number of reportable failures in that library.
+ for library in self.libraries:
+ num_failures = library.numReportableFailures()
+ if num_failures > 0:
+ message += ' ' + library.name + ' (' + str(num_failures) + ')\n'
+ pass
+ pass
+
+ # Provide the details for the failures in each library.
+ for library in self.libraries:
+ if library.numReportableFailures() > 0:
+ message += '\n|' + library.name + '|\n'
+ for test in library.tests:
+ if test.numReportableFailures() > 0:
+ message += ' ' + test.name + ':'
+ for failure in test.failures:
+ if not failure.platform.isBroken():
+ message += ' ' + failure.platform.name
+ pass
+ pass
+ message += '\n'
+ pass
+ pass
+ pass
+ pass
+
+ return message
+
+class PlatformMaintainer:
+ """
+ Information about the platform maintainer of a library
+ """
+ def __init__(self, name, email):
+ self.name = name
+ self.email = email
+ self.platforms = list()
+ return
+
+ def addPlatform(self, runner, platform):
+ self.platforms.append(platform)
+ return
+
+ def composeEmail(self, report):
+ """
+ Composes an e-mail to this platform maintainer if one or more of
+ the platforms s/he maintains has a large number of failures.
+ Returns the e-mail text if a message needs to be sent, or None
+ otherwise.
+ """
+
+ # Determine if we need to send a message to this developer.
+ requires_message = False
+ for platform in self.platforms:
+ if platform.isBroken():
+ requires_message = True
+ break
+
+ if not requires_message:
+ return None
+
+ # Build the message header
+ message = """From: Douglas Gregor <dgregor@osl.iu.edu>
+To: """
+ message += self.name + ' <' + self.email + '>'
+ message += """
+Reply-To: boost@lists.boost.org
+Subject: Large number of Boost failures on a platform you maintain as of """
+ message += str(datetime.date.today()) + " [" + report.branch + "]"
+ message += """
+
+You are receiving this report because one or more of the testing
+platforms that you maintain has a large number of Boost failures that
+are not accounted for. A full version of the report is sent to the
+Boost developer's mailing list.
+
+Detailed report:
+"""
+ message += ' ' + report.url + """
+
+The following platforms have a large number of failures:
+"""
+
+ for platform in self.platforms:
+ if platform.isBroken():
+ message += (' ' + platform.name + ' ('
+ + str(len(platform.failures)) + ' failures)\n')
+
+ return message
+
+class Report:
+ """
+ The complete report of all failing test cases.
+ """
+ def __init__(self, branch = 'trunk'):
+ self.branch = branch
+ self.date = None
+ self.url = None
+ self.libraries = dict()
+ self.platforms = dict()
+ self.maintainers = dict()
+ self.platform_maintainers = dict()
+ return
+
+ def getPlatform(self, name):
+ """
+ Retrieve the platform with the given name.
+ """
+ if self.platforms.has_key(name):
+ return self.platforms[name]
+ else:
+ self.platforms[name] = Platform(name)
+ return self.platforms[name]
+
+ def getMaintainer(self, name, email):
+ """
+ Retrieve the maintainer with the given name and e-mail address.
+ """
+ if self.maintainers.has_key(name):
+ return self.maintainers[name]
+ else:
+ self.maintainers[name] = Maintainer(name, email)
+ return self.maintainers[name]
+
+ def getPlatformMaintainer(self, name, email):
+ """
+ Retrieve the platform maintainer with the given name and
+ e-mail address.
+ """
+ if self.platform_maintainers.has_key(name):
+ return self.platform_maintainers[name]
+ else:
+ self.platform_maintainers[name] = PlatformMaintainer(name, email)
+ return self.platform_maintainers[name]
+
+ def parseIssuesEmail(self):
+ """
+ Try to parse the issues e-mail file. Returns True if everything was
+ successful, false otherwise.
+ """
+ # See if we actually got the file
+ if not os.path.isfile('issues-email.txt'):
+ return False
+
+ # Determine the set of libraries that have unresolved failures
+ date_regex = re.compile('Report time: (.*)')
+ url_regex = re.compile(' (http://.*)')
+ library_regex = re.compile('\|(.*)\|')
+ failure_regex = re.compile(' ([^:]*): (.*)')
+ current_library = None
+ for line in file('issues-email.txt', 'r'):
+ # Check for the report time line
+ m = date_regex.match(line)
+ if m:
+ self.date = m.group(1)
+ continue
+
+ # Check for the detailed report URL
+ m = url_regex.match(line)
+ if m:
+ self.url = m.group(1)
+ continue
+
+ # Check for a library header
+ m = library_regex.match(line)
+ if m:
+ current_library = Library(m.group(1))
+ self.libraries[m.group(1)] = current_library
+ continue
+
+ # Check for a library test and its failures
+ m = failure_regex.match(line)
+ if m:
+ test = Test(current_library, m.group(1))
+ for platform_name in re.split('\s*', m.group(2)):
+ if platform_name != '':
+ platform = self.getPlatform(platform_name)
+ failure = Failure(test, platform)
+ test.addFailure(failure)
+ platform.addFailure(failure)
+ pass
+ current_library.addTest(test)
+ continue
+ pass
+
+ return True
+
+ def getIssuesEmail(self):
+ """
+ Retrieve the issues email from beta.boost.org, trying a few
+ times in case something wonky is happening. If we can retrieve
+ the file, calls parseIssuesEmail and return True; otherwise,
+ return False.
+ """
+ base_url = "http://beta.boost.org/development/tests/"
+ base_url += self.branch
+ base_url += "/developer/";
+ got_issues = False
+
+ # Ping the server by looking for an HTML file
+ print "Pinging the server to initiate extraction..."
+ ping_url = base_url + "issues.html"
+ os.system('curl -O ' + ping_url)
+ os.system('rm -f issues.html')
+
+ for x in range(30):
+ # Update issues-email.txt
+ url = base_url + "issues-email.txt"
+ print 'Retrieving issues email from ' + url
+ os.system('rm -f issues-email.txt')
+ os.system('curl -O ' + url)
+
+ if self.parseIssuesEmail():
+ return True
+
+ print 'Failed to fetch issues email. '
+ time.sleep (30)
+
+ return False
+
+ # Parses the file $BOOST_ROOT/libs/maintainers.txt to create a hash
+ # mapping from the library name to the list of maintainers.
+ def parseLibraryMaintainersFile(self):
+ """
+ Parse the maintainers file in ../../../libs/maintainers.txt to
+ collect information about the maintainers of broken libraries.
+ """
+ lib_maintainer_regex = re.compile('(\S+)\s*(.*)')
+ name_email_regex = re.compile('\s*(\w*(\s*\w+)+)\s*<\s*(\S*(\s*\S+)+)\S*>')
+ at_regex = re.compile('\s*-\s*at\s*-\s*')
+ for line in file('../../../libs/maintainers.txt', 'r'):
+ if line.startswith('#'):
+ continue
+ m = lib_maintainer_regex.match (line)
+ if m:
+ libname = m.group(1)
+ if self.libraries.has_key(m.group(1)):
+ library = self.libraries[m.group(1)]
+ for person in re.split('\s*,\s*', m.group(2)):
+ nmm = name_email_regex.match(person)
+ if nmm:
+ name = nmm.group(1)
+ email = nmm.group(3)
+ email = at_regex.sub('@', email)
+ maintainer = self.getMaintainer(name, email)
+ maintainer.addLibrary(library)
+ library.addMaintainer(maintainer)
+ pass
+ pass
+ pass
+ pass
+ pass
+ pass
+
+ # Parses the file $BOOST_ROOT/libs/platform_maintainers.txt to
+ # create a hash mapping from the platform name to the list of
+ # maintainers.
+ def parsePlatformMaintainersFile(self):
+ """
+ Parse the platform maintainers file in
+ ../../../libs/platform_maintainers.txt to collect information
+ about the maintainers of the various platforms.
+ """
+ platform_maintainer_regex = re.compile('([A-Za-z0-9_.-]*|"[^"]*")\s+(\S+)\s+(.*)')
+ name_email_regex = re.compile('\s*(\w*(\s*\w+)+)\s*<\s*(\S*(\s*\S+)+)\S*>')
+ at_regex = re.compile('\s*-\s*at\s*-\s*')
+ for line in file('../../../libs/platform_maintainers.txt', 'r'):
+ if line.startswith('#'):
+ continue
+ m = platform_maintainer_regex.match (line)
+ if m:
+ platformname = m.group(2)
+ if self.platforms.has_key(platformname):
+ platform = self.platforms[platformname]
+ for person in re.split('\s*,\s*', m.group(3)):
+ nmm = name_email_regex.match(person)
+ if nmm:
+ name = nmm.group(1)
+ email = nmm.group(3)
+ email = at_regex.sub('@', email)
+ maintainer = self.getPlatformMaintainer(name, email)
+ maintainer.addPlatform(m.group(1), platform)
+ platform.addMaintainer(maintainer)
+ pass
+ pass
+ pass
+ pass
+ pass
+
+ def numFailures(self):
+ count = 0
+ for library in self.libraries:
+ count += self.libraries[library].numFailures()
+ pass
+ return count
+
+ def numReportableFailures(self):
+ count = 0
+ for library in self.libraries:
+ count += self.libraries[library].numReportableFailures()
+ pass
+ return count
+
+ def composeSummaryEmail(self):
+ """
+ Compose a message to send to the Boost developer's
+ list. Return the message and return it.
+ """
+ message = """From: Douglas Gregor <dgregor@osl.iu.edu>
+To: boost@lists.boost.org
+Reply-To: boost@lists.boost.org
+Subject: [Report] """
+ message += str(self.numFailures()) + " failures on " + branch
+ if branch != 'trunk':
+ message += ' branch'
+ message += " (" + str(datetime.date.today()) + ")"
+ message += """
+
+Boost regression test failures
+"""
+ message += "Report time: " + self.date + """
+
+This report lists all regression test failures on high-priority platforms.
+
+Detailed report:
+"""
+
+ message += ' ' + self.url + '\n\n'
+
+ if self.numFailures() == 0:
+ message += "No failures! Yay!\n"
+ return message
+
+ # List the platforms that are broken
+ any_broken_platforms = self.numReportableFailures() < self.numFailures()
+ if any_broken_platforms:
+ message += """The following platforms have a large number of failures:
+"""
+ for platform in sorted_keys( self.platforms ):
+ if self.platforms[platform].isBroken():
+ message += (' ' + platform + ' ('
+ + str(len(self.platforms[platform].failures))
+ + ' failures)\n')
+
+ message += """
+Failures on these "broken" platforms will be omitted from the results below.
+Please see the full report for information about these failures.
+
+"""
+
+ # Display the number of failures
+ message += (str(self.numReportableFailures()) + ' failures in ' +
+ str(len(self.libraries)) + ' libraries')
+ if any_broken_platforms:
+ message += (' (plus ' + str(self.numFailures() - self.numReportableFailures())
+ + ' from broken platforms)')
+
+ message += '\n'
+
+ # Display the number of failures per library
+ for k in sorted_keys( self.libraries ):
+ library = self.libraries[k]
+ num_failures = library.numFailures()
+ message += ' ' + library.name + ' ('
+
+ if library.numReportableFailures() > 0:
+ message += (str(library.numReportableFailures())
+ + " failures")
+
+ if library.numReportableFailures() < num_failures:
+ if library.numReportableFailures() > 0:
+ message += ', plus '
+
+ message += (str(num_failures-library.numReportableFailures())
+ + ' failures on broken platforms')
+ message += ')\n'
+ pass
+
+ message += '\n'
+
+ # Provide the details for the failures in each library.
+ for k in sorted_keys( self.libraries ):
+ library = self.libraries[k]
+ if library.numReportableFailures() > 0:
+ message += '\n|' + library.name + '|\n'
+ for test in library.tests:
+ if test.numReportableFailures() > 0:
+ message += ' ' + test.name + ':'
+ for failure in test.failures:
+ platform = failure.platform
+ if not platform.isBroken():
+ message += ' ' + platform.name
+ message += '\n'
+
+ return message
+
+ def composeTestingSummaryEmail(self):
+ """
+ Compose a message to send to the Boost Testing list. Returns
+ the message text if a message is needed, returns None
+ otherwise.
+ """
+ brokenPlatforms = 0
+ for platform in sorted_keys( self.platforms ):
+ if self.platforms[platform].isBroken():
+ brokenPlatforms = brokenPlatforms + 1
+
+ if brokenPlatforms == 0:
+ return None;
+
+ message = """From: Douglas Gregor <dgregor@osl.iu.edu>
+To: boost-testing@lists.boost.org
+Reply-To: boost-testing@lists.boost.org
+Subject: [Report] """
+ message += str(brokenPlatforms) + " potentially broken platforms on " + branch
+ if branch != 'trunk':
+ message += ' branch'
+ message += " (" + str(datetime.date.today()) + ")"
+ message += """
+
+Potentially broken platforms for Boost regression testing
+"""
+ message += "Report time: " + self.date + """
+
+This report lists the high-priority platforms that are exhibiting a
+large number of regression test failures, which might indicate a problem
+with the test machines or testing harness.
+
+Detailed report:
+"""
+
+ message += ' ' + self.url + '\n'
+
+ message += """
+Platforms with a large number of failures:
+"""
+ for platform in sorted_keys( self.platforms ):
+ if self.platforms[platform].isBroken():
+ message += (' ' + platform + ' ('
+ + str(len(self.platforms[platform].failures))
+ + ' failures)\n')
+
+ return message
+
+# Send a message to "person" (a maintainer of a library that is
+# failing).
+# maintainers is the result of get_library_maintainers()
+def send_individualized_message (branch, person, maintainers):
+ # There are several states we could be in:
+ # 0 Initial state. Eat everything up to the "NNN failures in MMM
+ # libraries" line
+ # 1 Suppress output within this library
+ # 2 Forward output within this library
+ state = 0
+
+ failures_in_lib_regex = re.compile('\d+ failur.*\d+ librar')
+ lib_failures_regex = re.compile(' (\S+) \((\d+)\)')
+ lib_start_regex = re.compile('\|(\S+)\|')
+ general_pass_regex = re.compile(' http://')
+ for line in file('issues-email.txt', 'r'):
+ if state == 0:
+ lfm = lib_failures_regex.match(line)
+ if lfm:
+ # Pass the line through if the current person is a
+ # maintainer of this library
+ if lfm.group(1) in maintainers and person in maintainers[lfm.group(1)]:
+ message += line
+ print line,
+
+ elif failures_in_lib_regex.match(line):
+ message += "\nThere are failures in these libraries you maintain:\n"
+ elif general_pass_regex.match(line):
+ message += line
+
+ lib_start = lib_start_regex.match(line)
+ if lib_start:
+ if state == 0:
+ message += '\n'
+
+ if lib_start.group(1) in maintainers and person in maintainers[lib_start.group(1)]:
+ message += line
+ state = 2
+ else:
+ state = 1
+ else:
+ if state == 1:
+ pass
+ elif state == 2:
+ message += line
+
+ if '--debug' in sys.argv:
+ print '-----------------Message text----------------'
+ print message
+ else:
+ print
+
+ if '--send' in sys.argv:
+ print "Sending..."
+ smtp = smtplib.SMTP('milliways.osl.iu.edu')
+ smtp.sendmail(from_addr = 'Douglas Gregor <dgregor@osl.iu.edu>',
+ to_addrs = person[1],
+ msg = message)
+ print "Done."
+
+
+# Send a message to the developer's list
+def send_boost_developers_message(branch, maintainers, failing_libraries):
+ to_line = 'boost@lists.boost.org'
+ from_line = 'Douglas Gregor <dgregor@osl.iu.edu>'
+
+ message = """From: Douglas Gregor <dgregor@osl.iu.edu>
+To: boost@lists.boost.org
+Reply-To: boost@lists.boost.org
+Subject: Boost regression testing notification ("""
+
+ message += str(datetime.date.today()) + " [" + branch + "]"
+ message += ")"
+
+ message += """
+
+"""
+
+ for line in file('issues-email.txt', 'r'):
+ # Right before the detailed report, put out a warning message if
+ # any libraries with failures to not have maintainers listed.
+ if line.startswith('Detailed report:'):
+ missing_maintainers = False
+ for lib in failing_libraries:
+ if not(lib in maintainers) or maintainers[lib] == list():
+ missing_maintainers = True
+
+ if missing_maintainers:
+ message += """WARNING: The following libraries have failing regression tests but do
+not have a maintainer on file. Once a maintainer is found, add an
+entry to libs/maintainers.txt to eliminate this message.
+"""
+
+ for lib in failing_libraries:
+ if not(lib in maintainers) or maintainers[lib] == list():
+ message += ' ' + lib + '\n'
+ message += '\n'
+
+ message += line
+
+ if '--send' in sys.argv:
+ print 'Sending notification email...'
+ smtp = smtplib.SMTP('milliways.osl.iu.edu')
+ smtp.sendmail(from_addr = from_line, to_addrs = to_line, msg = message)
+ print 'Done.'
+
+ if '--debug' in sys.argv:
+ print "----------Boost developer's message text----------"
+ print message
+
+###############################################################################
+# Main program #
+###############################################################################
+
+# Parse command-line options
+branch = "trunk"
+for arg in sys.argv:
+ if arg.startswith("--branch="):
+ branch = arg[len("--branch="):]
+
+report = Report(branch)
+
+# Try to parse the issues e-mail
+if '--no-get' in sys.argv:
+ okay = report.parseIssuesEmail()
+else:
+ okay = report.getIssuesEmail()
+
+if not okay:
+ print 'Aborting.'
+ if '--send' in sys.argv:
+ message = """From: Douglas Gregor <dgregor@osl.iu.edu>
+ To: Douglas Gregor <dgregor@osl.iu.edu>
+ Reply-To: boost@lists.boost.org
+ Subject: Regression status script failed on """
+ message += str(datetime.date.today()) + " [" + branch + "]"
+ smtp = smtplib.SMTP('milliways.osl.iu.edu')
+ smtp.sendmail(from_addr = 'Douglas Gregor <dgregor@osl.iu.edu>',
+ to_addrs = 'dgregor@osl.iu.edu',
+ msg = message)
+ sys.exit(1)
+
+# Try to parse maintainers information
+report.parseLibraryMaintainersFile()
+report.parsePlatformMaintainersFile()
+
+# Generate individualized e-mail for library maintainers
+for maintainer_name in report.maintainers:
+ maintainer = report.maintainers[maintainer_name]
+
+ email = maintainer.composeEmail(report)
+ if email:
+ if '--send' in sys.argv:
+ print ('Sending notification email to ' + maintainer.name + '...')
+ smtp = smtplib.SMTP('milliways.osl.iu.edu')
+ smtp.sendmail(from_addr = report_author,
+ to_addrs = maintainer.email,
+ msg = email)
+ print 'done.\n'
+ else:
+ print 'Would send a notification e-mail to',maintainer.name
+
+ if '--debug' in sys.argv:
+ print ('Message text for ' + maintainer.name + ':\n')
+ print email
+
+# Generate individualized e-mail for platform maintainers
+for maintainer_name in report.platform_maintainers:
+ maintainer = report.platform_maintainers[maintainer_name]
+
+ email = maintainer.composeEmail(report)
+ if email:
+ if '--send' in sys.argv:
+ print ('Sending notification email to ' + maintainer.name + '...')
+ smtp = smtplib.SMTP('milliways.osl.iu.edu')
+ smtp.sendmail(from_addr = report_author,
+ to_addrs = maintainer.email,
+ msg = email)
+ print 'done.\n'
+ else:
+ print 'Would send a notification e-mail to',maintainer.name
+
+ if '--debug' in sys.argv:
+ print ('Message text for ' + maintainer.name + ':\n')
+ print email
+
+email = report.composeSummaryEmail()
+if '--send' in sys.argv:
+ print 'Sending summary email to Boost developer list...'
+ smtp = smtplib.SMTP('milliways.osl.iu.edu')
+ smtp.sendmail(from_addr = report_author,
+ to_addrs = boost_dev_list,
+ msg = email)
+ print 'done.\n'
+if '--debug' in sys.argv:
+ print 'Message text for summary:\n'
+ print email
+
+email = report.composeTestingSummaryEmail()
+if email:
+ if '--send' in sys.argv:
+ print 'Sending summary email to Boost testing list...'
+ smtp = smtplib.SMTP('milliways.osl.iu.edu')
+ smtp.sendmail(from_addr = report_author,
+ to_addrs = boost_testing_list,
+ msg = email)
+ print 'done.\n'
+ if '--debug' in sys.argv:
+ print 'Message text for testing summary:\n'
+ print email
+
+if not ('--send' in sys.argv):
+ print 'Chickening out and not sending any e-mail.'
+ print 'Use --send to actually send e-mail, --debug to see e-mails.'