diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/ftppoller.py b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/ftppoller.py
new file mode 100644
index 00000000000..5ec92447a73
--- /dev/null
+++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/ftppoller.py
@@ -0,0 +1,167 @@
+import time
+import re
+
+from urllib2 import urlopen, unquote
+from twisted.python import log, failure
+from twisted.internet import defer, reactor
+from twisted.internet.task import LoopingCall
+
+from buildbot.changes import base, changes
+
+class InvalidResultError(Exception):
+ def __init__(self, value="InvalidResultError"):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+class EmptyResult(Exception):
+ pass
+
+class FtpParser:
+ """I parse the web page for possible builds to test"""
+ findBuildDirs = re.compile('^.*"(\d{10})\/".*$')
+
+ def __init__(self, query, searchString):
+ url = query.geturl()
+ pageContents = query.read()
+ query.close()
+ self.dirs = []
+ self.dates = []
+ lines = pageContents.split('\n')
+ #for parsing lists of directories
+ for line in lines:
+ if line == "": continue
+ match = re.match(self.findBuildDirs, line)
+ if match:
+ self.dirs.append(match.group(1))
+ #for parsing lists of files
+ findLastDate = re.compile('^.*"([^"]*' + searchString + ')".*(\d\d-[a-zA-Z]{3}-\d\d\d\d \d\d:\d\d).*$')
+ for line in lines:
+ match = re.match(findLastDate, line)
+ if match:
+ self.dates.append([match.group(1), url + match.group(1), time.mktime(time.strptime(match.group(2), "%d-%b-%Y %H:%M"))])
+
+ def getDirs(self):
+ return self.dirs
+
+ def getDates(self):
+ return self.dates
+
+
+class FtpPoller(base.ChangeSource):
+ """This source will poll an ftp directory for changes and submit
+ them to the change master."""
+
+ compare_attrs = ["ftpURLs", "pollInterval", "tree", "branch"]
+
+ parent = None # filled in when we're added
+ loop = None
+ volatile = ['loop']
+ working = 0
+
+ def __init__(self, branch="", tree="Firefox", pollInterval=30, ftpURLs=[], searchString=""):
+ """
+ @type ftpURLs: list of strings
+ @param ftpURLs: The ftp directories to monitor
+
+ @type tree: string
+ @param tree: The tree to look for changes in.
+ For example, Firefox trunk is 'Firefox'
+ @type branch: string
+ @param branch: The branch to look for changes in. This must
+ match the 'branch' option for the Scheduler.
+ @type pollInterval: int
+ @param pollInterval: The time (in seconds) between queries for
+ changes
+ @type searchString: string
+ @param searchString: file type of the build we are looking for
+ """
+
+ self.ftpURLs = ftpURLs
+ self.tree = tree
+ self.branch = branch
+ self.pollInterval = pollInterval
+ self.lastChanges = {}
+ for url in self.ftpURLs:
+ self.lastChanges[url] = time.time() - 3600
+ self.searchString = searchString
+
+ def startService(self):
+ self.loop = LoopingCall(self.poll)
+ base.ChangeSource.startService(self)
+
+ reactor.callLater(0, self.loop.start, self.pollInterval)
+
+ def stopService(self):
+ self.loop.stop()
+ return base.ChangeSource.stopService(self)
+
+ def describe(self):
+ str = ""
+ str += "Getting changes from ftp directory %s " \
+ % str(self.ftpURLs)
+ str += "
Using tree: %s, branch %s" % (self.tree, self.branch)
+ return str
+
+ def poll(self):
+ if self.working > 0:
+ log.msg("Not polling Tinderbox because last poll is still working (%s)" % (str(self.working)))
+ else:
+ for url in self.ftpURLs:
+ self.working = self.working + 1
+ d = self._get_changes(url)
+ d.addCallback(self._process_changes, 0)
+ d.addBoth(self._finished)
+ return
+
+ def _finished(self, res):
+ self.working = self.working - 1
+
+ def _get_changes(self, url):
+ log.msg("Polling ftp dir %s" % url)
+ return defer.maybeDeferred(urlopen, url)
+
+ def _process_changes(self, query, forceDate):
+
+ try:
+ url = query.geturl()
+ parser = FtpParser(query, self.searchString)
+ dirList = parser.getDirs()
+ dateList = parser.getDates()
+ except InvalidResultError, e:
+ log.msg("Could not process Tinderbox query: " + e.value)
+ return
+ except EmptyResult:
+ return
+
+
+ #figure out if there is a new directory that needs searching
+ for dir in dirList:
+ buildDate = int(dir)
+ if self.lastChanges[url] >= buildDate:
+ # change too old
+ continue
+ self.lastChanges[url] = buildDate
+ self.working = self.working + 1
+ d = self._get_changes(url + dir + '/')
+ d.addBoth(self._process_changes, buildDate)
+ d.addBoth(self._finished)
+
+ #if we have a new browser to test, test it
+ for buildname, fullpath, buildDate in dateList:
+ if (url in self.lastChanges):
+ if (self.lastChanges[url] >= buildDate):
+ # change too old
+ continue
+ if forceDate > 0:
+ buildDate = forceDate
+ else:
+ self.lastChanges[url] = buildDate
+ c = changes.Change(who = url,
+ comments = "success",
+ files = [buildname,],
+ branch = self.branch,
+ when = buildDate,
+ links = fullpath)
+ self.parent.addChange(c)
+ log.msg("found a browser to test (%s)" % (fullpath))
diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/master.cfg b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/master.cfg
index 3030c9cebb3..f95f5a14b25 100644
--- a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/master.cfg
+++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/master.cfg
@@ -8,6 +8,7 @@
import os.path
# from buildbot.changes.freshcvs import FreshCVSSource
+from buildbot.buildslave import BuildSlave
from buildbot.process import factory
from buildbot.scheduler import Scheduler, Periodic
from buildbot.status import html
@@ -49,22 +50,24 @@ c['slavePortnum'] = 9987
## Slaves
##
-c['bots'] = [("qm-pubuntu-stage01", "l1nux"),
- ("qm-ptiger-stage01", "mac1nt0sh"),
- ("qm-pxp-stage01", "w1nd3rs"),
- ("qm-pvista-stage01", "w1nd3rs"),
- ("qm-pleopard-stage01", "mac1nt0sh")]
+c['slaves'] = [BuildSlave(name, password, max_builds=1) for (name, password) in [
+ ("qm-pubuntu-stage01", "l1nux"),
+ ("qm-ptiger-stage01", "mac1nt0sh"),
+ ("qm-pxp-stage01", "w1nd3rs"),
+ ("qm-pvista-stage01", "w1nd3rs"),
+ ("qm-pleopard-stage01", "mac1nt0sh")
+ ]]
##
## Status
##
c['status'] = []
-c['status'].append(html.Waterfall(http_port=2008,
- css="/build/perf-staging/waterfall.css"))
+c['status'].append(html.WebStatus(http_port=2008, allowForce=True))
from buildbot.status import tinderbox
from buildbot.status.mail import MailNotifier
+from tinderboxmailnotifier import TinderboxMailNotifier
c['status'].append(MailNotifier(
fromaddr="talos.buildbot@build.mozilla.org",
@@ -80,16 +83,14 @@ c['status'].append(tinderbox.TinderboxMailNotifier(
tree="MozillaTest",
extraRecipients=["tinderbox-daemon@tinderbox.mozilla.org",],
relayhost="smtp.mozilla.org",
- builders=["Linux talos trunk stage",
- "MacOSX Darwin 8.8.1 talos trunk stage",
- "MacOSX Darwin 9.0.0 talos trunk stage",
- "WINNT 5.1 talos trunk stage",
- "WINNT 6.0 talos trunk stage"],
+ builders=["Linux talos mozilla-central stage",
+ "MacOSX Darwin 8.8.1 talos mozilla-central stage",
+ "MacOSX Darwin 9.0.0 talos mozilla-central stage",
+ "WINNT 5.1 talos mozilla-central stage",
+ "WINNT 6.0 talos mozilla-central stage"],
# useChangeTime=True,
logCompression="bzip2"))
-
-
##
## Sources
##
@@ -98,9 +99,9 @@ import ftppoller
reload(ftppoller)
from ftppoller import FtpPoller
-c['sources'] = []
+c['change_source'] = []
-c['sources'].append(FtpPoller(
+c['change_source'].append(FtpPoller(
tree = "Firefox",
branch = "MOZ2-WIN32-CENTRAL",
pollInterval = 2 * 60,
@@ -108,15 +109,15 @@ c['sources'].append(FtpPoller(
searchString = WIN32_SEARCHSTRING)
)
-c['sources'].append(FtpPoller(
+c['change_source'].append(FtpPoller(
tree = "Firefox",
branch = "MOZ2-LINUX-CENTRAL",
pollInterval = 2 * 60,
ftpURLs = LINUX_MOZ2_CENTRAL_BUILDDIRS,
searchString = LINUX_SEARCHSTRING)
)
-
-c['sources'].append(FtpPoller(
+
+c['change_source'].append(FtpPoller(
tree = "Firefox",
branch = "MOZ2-MAC-CENTRAL",
pollInterval = 2 * 60,
@@ -129,25 +130,23 @@ c['sources'].append(FtpPoller(
c['schedulers'] = []
-## WINDOWS
-c['schedulers'].append(Scheduler(name="head perfrun scheduler",
- branch="HEAD",
+#mozilla-central
+c['schedulers'].append(Scheduler(name="moz2 central win32 scheduler",
+ branch="MOZ2-WIN32-CENTRAL",
treeStableTimer=5*60,
- builderNames=["WINNT 5.1 talos trunk stage",
- "WINNT 6.0 talos trunk stage"]
+ builderNames=["WINNT 5.1 talos mozilla-central stage",
+ "WINNT 6.0 talos mozilla-central stage"]
))
-## LINUX
-c['schedulers'].append(Scheduler(name="head perfrun linux scheduler",
- branch="HEAD_LINUX",
+c['schedulers'].append(Scheduler(name="moz2 central perfrun linux scheduler",
+ branch="MOZ2-LINUX-CENTRAL",
treeStableTimer=5*60,
- builderNames=["Linux talos trunk stage"]
+ builderNames=["Linux talos mozilla-central stage"]
))
-## MAC
-c['schedulers'].append(Scheduler(name="head perfrun scheduler mac",
- branch="HEAD-MAC",
+c['schedulers'].append(Scheduler(name="moz2 central perfrun mac scheduler",
+ branch="MOZ2-MAC-CENTRAL",
treeStableTimer=5*60,
- builderNames=["MacOSX Darwin 8.8.1 talos trunk stage",
- "MacOSX Darwin 9.0.0 talos trunk stage"]
+ builderNames=["MacOSX Darwin 8.8.1 talos mozilla-central stage",
+ "MacOSX Darwin 9.0.0 talos mozilla-central stage"]
))
# the 'builders' list defines the Builders. Each one is configured with a
@@ -161,87 +160,96 @@ c['schedulers'].append(Scheduler(name="head perfrun scheduler mac",
#STAGING MACHINES
graphConfig = ['--resultsServer', 'graphs-stage.mozilla.org', '--resultsLink', '/server/bulk.cgi']
-
-stageConfig = graphConfig + ['--activeTests', 'ts:tsspider:twinopen']
+stageConfig = graphConfig + ['--activeTests', 'tdhtml:ts:tsspider:tp']
+nochromeConfig = graphConfig + ['--activeTests', 'tdhtml:ts:tsspider', '--noChrome']
+
+basicConfig = 'configs/production.sample.config'
+branchConfig = 'configs/production.sample.config.nogfx'
+#nochromeConfig = 'configs/production.sample.config.nochrome'
+fastConfig = 'configs/fast.production.sample.config'
+fastManifest = 'configs/historic_manifest.txt'
+jssConfig = 'configs/jss.production.sample.config'
basicTalosCmd = ['python', 'run_tests.py', '--noisy']
-win32_trunk_stage_steps = TalosFactory(OS = 'win',
+
+win32_moz2_stage_steps = TalosFactory(OS = 'win',
envName='vc8perf',
- buildBranch="1.9",
+ buildBranch="moz-central-stage",
configOptions=stageConfig,
buildPath="..\\firefox\\firefox.exe",
talosCmd=basicTalosCmd)
-vista_trunk_stage_steps = TalosFactory(OS = 'win',
+vista_moz2_stage_steps = TalosFactory(OS = 'win',
envName='vc8perf',
- buildBranch="1.9",
+ buildBranch="moz-central-stage",
configOptions=stageConfig,
buildPath="..\\firefox\\firefox.exe",
talosCmd=basicTalosCmd)
-linux_trunk_stage_steps = TalosFactory(OS = 'linux',
+linux_moz2_stage_steps = TalosFactory(OS = 'linux',
envName='linux',
- buildBranch="1.9",
+ buildBranch="moz-central-stage",
configOptions=stageConfig,
buildPath="../firefox/firefox",
talosCmd=basicTalosCmd)
-mac_trunk_stage_steps = TalosFactory(OS = 'tiger',
+mac_moz2_stage_steps = TalosFactory(OS = 'tiger',
envName='mac',
- buildBranch="1.9",
+ buildBranch="moz-central-stage",
configOptions=stageConfig,
- buildPath="../GranParadiso.app/Contents/MacOS/firefox",
+ buildPath="../Minefield.app/Contents/MacOS/firefox",
talosCmd=basicTalosCmd)
-leopard_trunk_stage_steps = TalosFactory(OS = 'leopard',
+leopard_moz2_stage_steps = TalosFactory(OS = 'leopard',
envName='mac',
- buildBranch="1.9",
+ buildBranch="moz-central-stage",
configOptions=stageConfig,
- buildPath="../GranParadiso.app/Contents/MacOS/firefox",
+ buildPath="../Minefield.app/Contents/MacOS/firefox",
talosCmd=basicTalosCmd)
+
#STAGING
-win32_trunk_stage_builder = {
- 'name': "WINNT 5.1 talos trunk stage",
+win32_moz2_stage_builder = {
+ 'name': "WINNT 5.1 talos mozilla-central stage",
'slavenames': ['qm-pxp-stage01'],
'builddir': "win32-trunk",
- 'factory': win32_trunk_stage_steps,
+ 'factory': win32_moz2_stage_steps,
'category': "Firefox Trunk"
}
-vista_trunk_stage_builder = {
- 'name': "WINNT 6.0 talos trunk stage",
+vista_moz2_stage_builder = {
+ 'name': "WINNT 6.0 talos mozilla-central stage",
'slavenames': ['qm-pvista-stage01'],
'builddir': "vista-trunk",
- 'factory': vista_trunk_stage_steps,
+ 'factory': vista_moz2_stage_steps,
'category': "Firefox Trunk"
}
-linux_trunk_stage_builder = {
- 'name': "Linux talos trunk stage",
+linux_moz2_stage_builder = {
+ 'name': "Linux talos mozilla-central stage",
'slavenames': ['qm-pubuntu-stage01'],
'builddir': "linux-trunk",
- 'factory': linux_trunk_stage_steps,
+ 'factory': linux_moz2_stage_steps,
'category': "Firefox Trunk"
}
-mac_trunk_stage_builder = {
- 'name': "MacOSX Darwin 8.8.1 talos trunk stage",
+mac_moz2_stage_builder = {
+ 'name': "MacOSX Darwin 8.8.1 talos mozilla-central stage",
'slavenames': ['qm-ptiger-stage01'],
'builddir': "mac-trunk",
- 'factory': mac_trunk_stage_steps,
+ 'factory': mac_moz2_stage_steps,
'category': "Firefox Trunk"
}
-leopard_trunk_stage_builder = {
- 'name': "MacOSX Darwin 9.0.0 talos trunk stage",
+leopard_moz2_stage_builder = {
+ 'name': "MacOSX Darwin 9.0.0 talos mozilla-central stage",
'slavenames': ['qm-pleopard-stage01'],
'builddir': "leopard-trunk",
- 'factory': leopard_trunk_stage_steps,
+ 'factory': leopard_moz2_stage_steps,
'category': "Firefox Trunk"
}
c['builders'] = []
#STAGING
-c['builders'].append(win32_trunk_stage_builder)
-c['builders'].append(vista_trunk_stage_builder)
-c['builders'].append(linux_trunk_stage_builder)
-c['builders'].append(mac_trunk_stage_builder)
-c['builders'].append(leopard_trunk_stage_builder)
+c['builders'].append(win32_moz2_stage_builder)
+c['builders'].append(vista_moz2_stage_builder)
+c['builders'].append(linux_moz2_stage_builder)
+c['builders'].append(mac_moz2_stage_builder)
+c['builders'].append(leopard_moz2_stage_builder)
diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/perfrunner.py b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/perfrunner.py
new file mode 100644
index 00000000000..919879dadc3
--- /dev/null
+++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/perfrunner.py
@@ -0,0 +1,715 @@
+# -*- Python -*-
+
+from twisted.python import log
+from buildbot import buildset
+from buildbot.scheduler import Scheduler
+from buildbot.process.buildstep import BuildStep
+from buildbot.process.factory import BuildFactory
+from buildbot.buildset import BuildSet
+from buildbot.sourcestamp import SourceStamp
+from buildbot.steps.shell import ShellCommand
+from buildbot.steps.transfer import FileDownload
+from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, SKIPPED, EXCEPTION
+import re, urllib, sys, os
+from time import strptime, strftime, localtime
+from datetime import datetime
+from os import path
+import copy
+
+MozillaEnvironments = { }
+
+# platform SDK location. we can build both from one generic template.
+# modified from vc8 environment
+MozillaEnvironments['vc8perf'] = {
+ "MOZ_CRASHREPORTER_NO_REPORT": '1',
+ "MOZ_NO_REMOTE": '1',
+ "NO_EM_RESTART": '1',
+ "XPCOM_DEBUG_BREAK": 'warn',
+ "CYGWINBASE": 'C:\\cygwin',
+ "PATH": 'C:\\Python24;' + \
+ 'C:\\Python24\\Scripts;' + \
+ 'C:\\cygwin\\bin;' + \
+ 'C:\\WINDOWS\\System32;' + \
+ 'C:\\program files\\gnuwin32\\bin;' + \
+ 'C:\\WINDOWS;'
+}
+
+MozillaEnvironments['linux'] = {
+ "MOZ_CRASHREPORTER_NO_REPORT": '1',
+ "MOZ_NO_REMOTE": '1',
+ "NO_EM_RESTART": '1',
+ "XPCOM_DEBUG_BREAK": 'warn',
+ "DISPLAY": ":0",
+}
+
+MozillaEnvironments['mac'] = {
+ "MOZ_NO_REMOTE": '1',
+ "NO_EM_RESTART": '1',
+ "XPCOM_DEBUG_BREAK": 'warn',
+ "MOZ_CRASHREPORTER_NO_REPORT": '1',
+ # for extracting dmg's
+ "PAGER": '/bin/cat',
+}
+
+class MultiBuildScheduler(Scheduler):
+ """Trigger N (default three) build requests based upon the same change request"""
+ def __init__(self, numberOfBuildsToTrigger=3, **kwargs):
+ self.numberOfBuildsToTrigger = numberOfBuildsToTrigger
+ Scheduler.__init__(self, **kwargs)
+
+ def fireTimer(self):
+ self.timer = None
+ self.nextBuildTime = None
+ changes = self.importantChanges + self.unimportantChanges
+ self.importantChanges = []
+ self.unimportantChanges = []
+
+ # submit
+ for i in range(0, self.numberOfBuildsToTrigger):
+ ss = UnmergableSourceStamp(changes=changes)
+ bs = buildset.BuildSet(self.builderNames, ss)
+ self.submit(bs)
+
+
+class LatestFileURL:
+ sortByDateString = "?C=M;O=A"
+
+ def _retrievePageAtURL(self):
+ content = []
+ try:
+ opener = urllib.URLopener()
+ page = opener.open(self.url + self.sortByDateString)
+ content = page.readlines()
+ opener.close()
+ except:
+ print "unable to retrieve page at: " + self.url + " dated: " + self.sortByDateString
+ return content
+
+ def _populateDict(self):
+ '''Extract the latest filename from the given URL
+ * retrieve page at URL
+ * for each line
+ * grab filename URL
+ * if filename matches filenameSearchString
+ * grab datetime
+ * store date and filename URL in dictionary
+ * return latest filenameURL matching date'''
+
+ reDatestamp = re.compile('\d\d-[a-zA-Z]{3,3}-\d\d\d\d \d\d:\d\d')
+ reHREF = re.compile('href\="((?:\w|[.-])*)"')
+ content = self._retrievePageAtURL()
+ for line in content:
+ matchHREF = re.search(reHREF, line)
+ if matchHREF:
+ if self.filenameSearchString in matchHREF.group(1):
+ datetimeMatch = re.search(reDatestamp, line)
+ if datetimeMatch:
+ dts = line[datetimeMatch.start():datetimeMatch.end()]
+ timestamp = datetime(*strptime(dts, '%d-%b-%Y %H:%M')[0:6])
+ self.dateFileDict[timestamp] = matchHREF.group(1)
+
+
+ def _getDateKeys(self):
+ dbKeys = self.dateFileDict.keys()
+ if not dbKeys:
+ return []
+ return dbKeys
+
+ def getLatestFilename(self):
+ dateKeys = self._getDateKeys()
+ if not dateKeys: return ""
+ return self.dateFileDict[max(dateKeys)]
+
+ def _printDictionary(self):
+ keys = self._getDateKeys()
+ for timestamp in keys:
+ print "%s : %s" % (timestamp, self.dateFileDict[timestamp])
+
+ def testrun(self):
+ self._populateDict()
+ self._printDictionary()
+ name = self.getLatestFilename()
+ print self.url + name
+
+ def __init__(self, url, filenameSearchString):
+ self.url = url
+ self.filenameSearchString = filenameSearchString
+ self.dateFileDict = {}
+ self._populateDict()
+
+class MozillaWgetLatestDated(ShellCommand):
+ """Download built Firefox client from dated staging directory."""
+ haltOnFailure = True
+
+ def __init__(self, **kwargs):
+ self.branch = "HEAD"
+ if 'branch' in kwargs:
+ self.branch = kwargs['branch']
+ if not 'command' in kwargs:
+ kwargs['command'] = ["wget"]
+ ShellCommand.__init__(self, **kwargs)
+
+ def setBuild(self, build):
+ ShellCommand.setBuild(self, build)
+ self.changes = build.source.changes
+ #a full path is always provided by the poller
+ self.fileURL = self.changes[-1].links
+ self.filename = self.changes[-1].files[0]
+
+ def getFilename(self):
+ return self.filename
+
+ def describe(self, done=False):
+ return ["Wget Download"]
+
+ def start(self):
+ #urlGetter = LatestFileURL(self.url, self.filenameSearchString)
+ #self.filename = urlGetter.getLatestFilename()
+ #self.fileURL = self.url + self.filename
+ if self.branch:
+ self.setProperty("fileURL", self.fileURL)
+ self.setProperty("filename", self.filename)
+ self.setCommand(["wget", "-nv", "-N", self.fileURL])
+ ShellCommand.start(self)
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ if SUCCESS != superResult:
+ return FAILURE
+ if None != re.search('ERROR', cmd.logs['stdio'].getText()):
+ return FAILURE
+ return SUCCESS
+
+
+class MozillaWgetLatest(ShellCommand):
+ """Download built Firefox client from nightly staging directory."""
+ haltOnFailure = True
+
+ def __init__(self, **kwargs):
+ assert kwargs['url'] != ""
+ assert kwargs['filenameSearchString'] != ""
+ #if this change includes a link use it
+ if self.changes[-1].links:
+ self.url = self.changes[-1].links
+ else:
+ self.url = kwargs['url']
+ self.filenameSearchString = kwargs['filenameSearchString']
+ self.branch = "HEAD"
+ self.fileURL = ""
+ if 'branch' in kwargs:
+ self.branch = kwargs['branch']
+ if not 'command' in kwargs:
+ kwargs['command'] = ["wget"]
+ ShellCommand.__init__(self, **kwargs)
+
+ def getFilename(self):
+ return self.filename
+
+ def describe(self, done=False):
+ return ["Wget Download"]
+
+ def start(self):
+ urlGetter = LatestFileURL(self.url, self.filenameSearchString)
+ self.filename = urlGetter.getLatestFilename()
+ self.fileURL = self.url + self.filename
+ if self.branch:
+ self.setProperty("fileURL", self.fileURL)
+ self.setProperty("filename", self.filename)
+ self.setCommand(["wget", "-nv", "-N", self.fileURL])
+ ShellCommand.start(self)
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ if SUCCESS != superResult:
+ return FAILURE
+ if None != re.search('ERROR', cmd.logs['stdio'].getText()):
+ return FAILURE
+ return SUCCESS
+
+
+class MozillaInstallZip(ShellCommand):
+ """Install given file, unzipping to executablePath"""
+
+ def __init__(self, **kwargs):
+ self.filename = ""
+ self.branch = ""
+ if 'branch' in kwargs:
+ self.branch = kwargs['branch']
+ if 'filename' in kwargs:
+ self.filename = kwargs['filename']
+ if not 'command' in kwargs:
+ kwargs['command'] = ["unzip", "-o"]
+ ShellCommand.__init__(self, **kwargs)
+
+ def describe(self, done=False):
+ return ["Install zip"]
+
+ def start(self):
+ # removed the mkdir because this happens on the master, not the slave
+ if not self.filename:
+ if self.branch:
+ self.filename = self.getProperty("filename")
+ else:
+ return FAILURE
+ if self.filename:
+ self.command = self.command[:] + [self.filename]
+ ShellCommand.start(self)
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ if SUCCESS != superResult:
+ return FAILURE
+ if None != re.search('ERROR', cmd.logs['stdio'].getText()):
+ return FAILURE
+ if None != re.search('Usage:', cmd.logs['stdio'].getText()):
+ return FAILURE
+ return SUCCESS
+
+
+class MozillaUpdateConfig(ShellCommand):
+ """Configure YAML file for run_tests.py"""
+
+ def __init__(self, **kwargs):
+ self.addOptions = []
+ assert 'executablePath' in kwargs
+ assert 'branch' in kwargs
+ self.branch = kwargs['branch']
+ self.exePath = kwargs['executablePath']
+ if 'addOptions' in kwargs:
+ self.addOptions = kwargs['addOptions']
+ ShellCommand.__init__(self, **kwargs)
+
+ def setBuild(self, build):
+ ShellCommand.setBuild(self, build)
+ self.title = build.slavename
+ self.changes = build.source.changes
+ self.buildid = strftime("%Y%m%d%H%M", localtime(self.changes[-1].when))
+ if not self.command:
+ self.setCommand(["python", "PerfConfigurator.py", "-v", "-e", self.exePath, "-t", self.title, "-b", self.branch, "-d", self.buildid] + self.addOptions)
+
+ def describe(self, done=False):
+ return ["Update config"]
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ if SUCCESS != superResult:
+ return FAILURE
+ stdioText = cmd.logs['stdio'].getText()
+ if None != re.search('ERROR', stdioText):
+ return FAILURE
+ if None != re.search('USAGE:', stdioText):
+ return FAILURE
+ configFileMatch = re.search('outputName\s*=\s*(\w*?.yml)', stdioText)
+ if not configFileMatch:
+ return FAILURE
+ else:
+ self.setProperty("configFile", configFileMatch.group(1))
+ return SUCCESS
+
+
+class MozillaRunPerfTests(ShellCommand):
+ """Run the performance tests"""
+
+ def __init__(self, **kwargs):
+ if 'branch' in kwargs:
+ self.branch = kwargs['branch']
+ if not 'command' in kwargs:
+ kwargs['command'] = ["python", "run_tests.py"]
+ ShellCommand.__init__(self, **kwargs)
+
+ def describe(self, done=False):
+ return ["Run performance tests"]
+
+ def createSummary(self, log):
+ summary = []
+ for line in log.readlines():
+ if "RETURN:" in line:
+ summary.append(line.replace("RETURN:", "TinderboxPrint:"))
+ if "FAIL:" in line:
+ summary.append(line.replace("FAIL:", "TinderboxPrint:FAIL:"))
+ self.addCompleteLog('summary', "\n".join(summary))
+
+ def start(self):
+ """docstring for start"""
+ self.command = copy.copy(self.command)
+ self.command.append(self.getProperty("configFile"))
+ ShellCommand.start(self)
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ stdioText = cmd.logs['stdio'].getText()
+ if SUCCESS != superResult:
+ return FAILURE
+ if None != re.search('ERROR', stdioText):
+ return FAILURE
+ if None != re.search('USAGE:', stdioText):
+ return FAILURE
+ if None != re.search('FAIL:', stdioText):
+ return WARNINGS
+ return SUCCESS
+
+class MozillaInstallTarBz2(ShellCommand):
+ """Install given file, unzipping to executablePath"""
+
+ def __init__(self, **kwargs):
+ self.filename = ""
+ self.branch = ""
+ if 'branch' in kwargs:
+ self.branch = kwargs['branch']
+ if 'filename' in kwargs:
+ self.filename = kwargs['filename']
+ if not 'command' in kwargs:
+ kwargs['command'] = ["tar", "-jvxf"]
+ ShellCommand.__init__(self, **kwargs)
+
+ def describe(self, done=False):
+ return ["Install tar.bz2"]
+
+ def start(self):
+ if not self.filename:
+ if self.branch:
+ self.filename = self.getProperty("filename")
+ else:
+ return FAILURE
+ if self.filename:
+ self.command = self.command[:] + [self.filename]
+ ShellCommand.start(self)
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ if SUCCESS != superResult:
+ return FAILURE
+ return SUCCESS
+
+class MozillaInstallTarGz(ShellCommand):
+ """Install given file, unzipping to executablePath"""
+
+ def __init__(self, **kwargs):
+ self.filename = ""
+ self.branch = ""
+ if 'branch' in kwargs:
+ self.branch = kwargs['branch']
+ if 'filename' in kwargs:
+ self.filename = kwargs['filename']
+ if not 'command' in kwargs:
+ kwargs['command'] = ["tar", "-zvxf"]
+ ShellCommand.__init__(self, **kwargs)
+
+ def describe(self, done=False):
+ return ["Install tar.gz"]
+
+ def start(self):
+ if not self.filename:
+ if self.branch:
+ self.filename = self.getProperty("filename")
+ else:
+ return FAILURE
+ if self.filename:
+ self.command = self.command[:] + [self.filename]
+ ShellCommand.start(self)
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ if SUCCESS != superResult:
+ return FAILURE
+ return SUCCESS
+
+class MozillaWgetFromChange(ShellCommand):
+ """Download built Firefox client from current change's filenames."""
+ haltOnFailure = True
+
+ def __init__(self, **kwargs):
+ self.branch = "HEAD"
+ self.fileURL = ""
+ self.filename = ""
+ self.filenameSearchString = "en-US.win32.zip"
+ if 'filenameSearchString' in kwargs:
+ self.filenameSearchString = kwargs['filenameSearchString']
+ if 'url' in kwargs:
+ self.url = kwargs['url']
+ else:
+ self.url = kwargs['build'].source.changes[-1].files[0]
+ if 'branch' in kwargs:
+ self.branch = kwargs['branch']
+ if not 'command' in kwargs:
+ kwargs['command'] = ["wget"]
+ ShellCommand.__init__(self, **kwargs)
+
+ def getFilename(self):
+ return self.filename
+
+ def describe(self, done=False):
+ return ["Wget Download"]
+
+ def start(self):
+ urlGetter = LatestFileURL(self.url, self.filenameSearchString)
+ self.filename = urlGetter.getLatestFilename()
+ self.fileURL = self.url + self.filename
+ if self.branch:
+ self.setProperty("fileURL", self.fileURL)
+ self.setProperty("filename", self.filename)
+ self.setCommand(["wget", "-nv", "-N", self.fileURL])
+ ShellCommand.start(self)
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ if SUCCESS != superResult:
+ return FAILURE
+ if None != re.search('ERROR', cmd.logs['stdio'].getText()):
+ return FAILURE
+ return SUCCESS
+
+class MozillaUpdateConfigFromChange(ShellCommand):
+ """Configure YAML file for run_tests.py"""
+
+ def __init__(self, **kwargs):
+ self.title = "default"
+ self.branch = ""
+ self.currentDate = ""
+ if 'build' in kwargs:
+ self.title = kwargs['build'].slavename
+ self.changes = kwargs['build'].source.changes
+ self.buildid = self.changes[-1].comments.split(',')[0]
+ if 'branch' in kwargs:
+ self.branch = kwargs['branch']
+ assert 'configPath' in kwargs
+ assert 'executablePath' in kwargs
+ self.configPath = kwargs['configPath']
+ self.exePath = kwargs['executablePath']
+ if not 'command' in kwargs:
+ kwargs['command'] = ["python", "PerfConfigurator.py", "-v", "-e",
+ self.exePath, "-c", self.configPath,
+ "-t", self.title, "-b", self.branch,
+ "-d", self.buildid]
+ ShellCommand.__init__(self, **kwargs)
+
+ def describe(self, done=False):
+ return ["Update config"]
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ if SUCCESS != superResult:
+ return FAILURE
+ stdioText = cmd.logs['stdio'].getText()
+ if None != re.search('ERROR', stdioText):
+ return FAILURE
+ if None != re.search('USAGE:', stdioText):
+ return FAILURE
+ configFileMatch = re.search('outputName\s*=\s*(\w*?.yml)', stdioText)
+ if not configFileMatch:
+ return FAILURE
+ else:
+ self.setProperty("configFile", configFileMatch.group(1))
+ return SUCCESS
+
+class MozillaInstallDmg(ShellCommand):
+ """Install given file, copying to workdir"""
+
+ def __init__(self, **kwargs):
+ self.filename = ""
+ self.branch = ""
+ if 'branch' in kwargs:
+ self.branch = kwargs['branch']
+ if 'filename' in kwargs:
+ self.filename = kwargs['filename']
+ if not 'command' in kwargs:
+ kwargs['command'] = ["bash", "installdmg.sh", "$FILENAME"]
+ ShellCommand.__init__(self, **kwargs)
+
+ def describe(self, done=False):
+ return ["Install dmg"]
+
+ def start(self):
+ if not self.filename:
+ if self.branch:
+ self.filename = self.getProperty("filename")
+ else:
+ return FAILURE
+
+ for i in range(len(self.command)):
+ if self.command[i] == "$FILENAME":
+ self.command[i] = self.filename
+ ShellCommand.start(self)
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ if SUCCESS != superResult:
+ return FAILURE
+ return SUCCESS
+
+class MozillaInstallDmgEx(ShellCommand):
+ """Install given file, copying to workdir"""
+ #This is a temporary class to test the new InstallDmg script without affecting the production mac machines
+ # if this works everything should be switched over the using it
+
+ def __init__(self, **kwargs):
+ self.filename = ""
+ self.branch = ""
+ if 'branch' in kwargs:
+ self.branch = kwargs['branch']
+ if 'filename' in kwargs:
+ self.filename = kwargs['filename']
+ if not 'command' in kwargs:
+ kwargs['command'] = ["expect", "installdmg.ex", "$FILENAME"]
+ ShellCommand.__init__(self, **kwargs)
+
+ def describe(self, done=False):
+ return ["Install dmg"]
+
+ def start(self):
+ if not self.filename:
+ if self.branch:
+ self.filename = self.getProperty("filename")
+ else:
+ return FAILURE
+
+ for i in range(len(self.command)):
+ if self.command[i] == "$FILENAME":
+ self.command[i] = self.filename
+ ShellCommand.start(self)
+
+ def evaluateCommand(self, cmd):
+ superResult = ShellCommand.evaluateCommand(self, cmd)
+ if SUCCESS != superResult:
+ return FAILURE
+ return SUCCESS
+
+class TalosFactory(BuildFactory):
+
+ winClean = ["touch temp.zip &", "rm", "-rf", "*.zip", "talos/", "firefox/"]
+ macClean = "rm -vrf *"
+ linuxClean = "rm -vrf *"
+
+ def __init__(self, OS, envName, buildBranch, configOptions, buildPath, talosCmd, customManifest='', cvsRoot=":pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot"):
+ BuildFactory.__init__(self)
+ if OS in ('linux', 'linuxbranch',):
+ cleanCmd = self.linuxClean
+ elif OS in ('win',):
+ cleanCmd = self.winClean
+ else:
+ cleanCmd = self.macClean
+ self.addStep(ShellCommand(
+ workdir=".",
+ description="Cleanup",
+ command=cleanCmd,
+ env=MozillaEnvironments[envName]))
+#self.addStep(ShellCommand,
+# command=["cvs", "-d", cvsRoot, "co", "-d", "talos",
+# "mozilla/testing/performance/talos"],
+# workdir=".",
+# description="checking out talos",
+# haltOnFailure=True,
+# flunkOnFailure=True,
+# env=MozillaEnvironments[envName])
+ self.addStep(FileDownload(
+ mastersrc="talos.zip",
+ slavedest="talos.zip",
+ workdir="."))
+ self.addStep(FileDownload,
+ mastersrc="scripts/count_and_reboot.py",
+ slavedest="count_and_reboot.py",
+ workdir=".")
+ self.addStep(MozillaInstallZip(
+ workdir=".",
+ branch=buildBranch,
+ haltOnFailure=True,
+ env=MozillaEnvironments[envName],
+ filename="talos.zip"))
+ self.addStep(FileDownload(
+ mastersrc="scripts/generate-tpcomponent.py",
+ slavedest="generate-tpcomponent.py",
+ workdir="talos/page_load_test"))
+ if customManifest != '':
+ self.addStep(FileDownload(
+ mastersrc=customManifest,
+ slavedest="manifest.txt",
+ workdir="talos/page_load_test"))
+ self.addStep(ShellCommand(
+ command=["python", "generate-tpcomponent.py"],
+ workdir="talos/page_load_test",
+ description="setting up pageloader",
+ haltOnFailure=True,
+ flunkOnFailure=True,
+ env=MozillaEnvironments[envName]))
+ self.addStep(MozillaWgetLatestDated(
+ workdir=".",
+ branch=buildBranch,
+ env=MozillaEnvironments[envName]))
+ #install the browser, differs based upon platform
+ if OS == 'linux':
+ self.addStep(MozillaInstallTarBz2(
+ workdir=".",
+ branch=buildBranch,
+ haltOnFailure=True,
+ env=MozillaEnvironments[envName]))
+ elif OS == 'linuxbranch': #special case for old linux builds
+ self.addStep(MozillaInstallTarGz(
+ workdir=".",
+ branch=buildBranch,
+ haltOnFailure=True,
+ env=MozillaEnvironments[envName]))
+ elif OS == 'win':
+ self.addStep(MozillaInstallZip(
+ workdir=".",
+ branch="1.9",
+ haltOnFailure=True,
+ env=MozillaEnvironments[envName]))
+ self.addStep(ShellCommand(
+ workdir="firefox/",
+ flunkOnFailure=False,
+ warnOnFailure=False,
+ description="chmod files (see msys bug)",
+ command=["chmod", "-v", "-R", "a+x", "."],
+ env=MozillaEnvironments[envName]))
+ elif OS == 'tiger':
+ self.addStep(FileDownload(
+ mastersrc="scripts/installdmg.sh",
+ slavedest="installdmg.sh",
+ workdir="."))
+ self.addStep(MozillaInstallDmg(
+ workdir=".",
+ branch=buildBranch,
+ haltOnFailure=True,
+ env=MozillaEnvironments[envName]))
+ else: #leopard
+ self.addStep(FileDownload(
+ mastersrc="scripts/installdmg.ex",
+ slavedest="installdmg.ex",
+ workdir="."))
+ self.addStep(MozillaInstallDmgEx(
+ workdir=".",
+ branch=buildBranch,
+ haltOnFailure=True,
+ env=MozillaEnvironments[envName]))
+ self.addStep(MozillaUpdateConfig(
+ workdir="talos/",
+ branch=buildBranch,
+ haltOnFailure=True,
+ executablePath=buildPath,
+ addOptions=configOptions,
+ env=MozillaEnvironments[envName]))
+ self.addStep(MozillaRunPerfTests(
+ warnOnWarnings=True,
+ workdir="talos/",
+ branch=buildBranch,
+ timeout=21600,
+ haltOnFailure=True,
+ command=talosCmd,
+ env=MozillaEnvironments[envName]))
+ self.addStep(ShellCommand(
+ flunkOnFailure=False,
+ warnOnFailure=False,
+ workdir='.',
+ description="reboot after 5 test runs",
+ command=["python", "count_and_reboot.py", "-f", "../talos_count.txt", "-n", "5", "-z"],
+ env=MozillaEnvironments[envName]))
+
+def main(argv=None):
+ if argv is None:
+ argv = sys.argv
+ tester = LatestFileURL('http://ftp.mozilla.org/pub/mozilla.org/firefox/tinderbox-builds/mozilla-central-linux/1222921630/ ', "en-US.linux-i686.tar.bz2")
+ tester.testrun()
+ return 0
+
+if __name__ == '__main__':
+ main()
diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/count_and_reboot.py b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/count_and_reboot.py
new file mode 100644
index 00000000000..3b0dc2baa18
--- /dev/null
+++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/count_and_reboot.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Created by Chris AtLee on 2008-11-04
+"""count_and_reboot.py [-n maxcount] -f countfile
+
+Increments the value in countfile, and reboots the machine once the count
+reaches or exceeds maxcount."""
+
+import os, sys, time
+
+if sys.platform in ('darwin', 'linux2'):
+ def reboot():
+ # -S means to accept password from stdin, which we then redirect from
+ # /dev/null
+ # This results in sudo not waiting forever for a password. If sudoers
+ # isn't set up properly, this will fail immediately
+ os.system("sudo -S reboot < /dev/null")
+ # After starting the shutdown, we go to sleep since the system can
+ # take a few minutes to shut everything down and reboot
+ time.sleep(600)
+
+elif sys.platform == "win32":
+ # Windows
+ def reboot():
+ os.system("shutdown -r")
+ # After starting the shutdown, we go to sleep since the system can
+ # take a few minutes to shut everything down and reboot
+ time.sleep(600)
+
+def increment_count(fname):
+ try:
+ current_count = int(open(fname).read())
+ except:
+ current_count = 0
+ current_count += 1
+ open(fname, "w").write("%i\n" % current_count)
+ return current_count
+
+if __name__ == '__main__':
+ from optparse import OptionParser
+
+ parser = OptionParser(__doc__)
+ parser.add_option("-n", "--max-count", dest="maxcount", default=10,
+ help="reboot after runs", type="int")
+ parser.add_option("-f", "--count-file", dest="countfile", default=None,
+ help="file to record count in")
+ parser.add_option("-z", "--zero-count", dest="zero", default=False,
+ action="store_true", help="zero out the counter before rebooting")
+
+ options, args = parser.parse_args()
+
+ if not options.countfile:
+ parser.error("countfile is required")
+
+ if increment_count(options.countfile) >= options.maxcount:
+ if options.zero:
+ open(options.countfile, "w").write("0\n")
+ print "Reached max number of runs before reboot required, restarting machine..."
+ sys.stdout.flush()
+ reboot()
diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/generate-tpcomponent.py b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/generate-tpcomponent.py
new file mode 100644
index 00000000000..06c7c0555c4
--- /dev/null
+++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/generate-tpcomponent.py
@@ -0,0 +1,83 @@
+# Generates the proper chrome/ and component/ directories that can be dropped
+# into a profile to enable the pageloader
+# Original Author: Alice Nodelman (anodelman@mozilla.com)
+# Modified by: Ben Hearsum (bhearsum@mozilla.com)
+
+import os
+import sys
+import zipfile
+import shutil
+import tempfile
+
+# create the temp directory
+tmp_dir = tempfile.mkdtemp()
+pageloader_dir = os.path.join(tmp_dir, "pageloader")
+# where the chrome/ and component/ directories will be put
+working_dir = "."
+chrome_dir = os.path.join(working_dir, 'chrome')
+components_dir = os.path.join(working_dir, 'components')
+# where the pageloader will be checked out from
+cvsroot = ":pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot"
+module = "mozilla/layout/tools/pageloader"
+
+def removedir(rdir):
+ if os.path.isdir(rdir):
+ for root, dirs, files in os.walk(rdir, topdown=False):
+ for name in files:
+ os.remove(os.path.join(root, name))
+ for name in dirs:
+ os.rmdir(os.path.join(root, name))
+ os.rmdir(rdir)
+
+def zipdir(zip, zdir):
+ if os.path.isdir(zdir):
+ for root, dirs, files in os.walk(zdir, topdown=False):
+ for name in files:
+ zip.write(os.path.join(root, name), os.path.join(os.path.basename(zdir), name))
+ else:
+ zip.write(zdir)
+
+
+# bail if the directories already exist
+if os.path.exists(chrome_dir):
+ print "chrome/ directory exists, bailing out"
+ sys.exit(1)
+if os.path.exists(components_dir):
+ print "components/ directory exists, bailing out"
+ sys.exit(1)
+
+oldcwd = os.getcwd()
+os.chdir(tmp_dir)
+# exit if cvs throws an error
+if os.system("cvs -d%s co -d pageloader %s" % (cvsroot, module)):
+ print "could not retrieve pageloader, bailing out"
+ sys.exit(1)
+os.chdir(oldcwd)
+
+#create the directory structure in the working_dir
+os.mkdir(chrome_dir)
+os.mkdir(os.path.join(chrome_dir, 'content'))
+os.mkdir(components_dir)
+
+#create the pageloader.manifest file
+f = open(os.path.join(chrome_dir, 'pageloader.manifest'), 'w')
+f.write('content pageloader jar:pageloader.jar!/content/\n')
+f.close()
+
+shutil.copy(os.path.join(pageloader_dir, 'pageloader.xul'), os.path.join(chrome_dir, 'content', 'pageloader.xul'))
+shutil.copy(os.path.join(pageloader_dir, 'quit.js'), os.path.join(chrome_dir, 'content', 'quit.js'))
+shutil.copy(os.path.join(pageloader_dir, 'pageloader.js'), os.path.join(chrome_dir, 'content', 'pageloader.js'))
+shutil.copy(os.path.join(pageloader_dir, 'report.js'), os.path.join(chrome_dir, 'content', 'report.js'))
+
+# create pageloader.jar
+jar = zipfile.ZipFile(os.path.join(chrome_dir, 'pageloader.jar'), 'w')
+zipdir(jar, os.path.join(chrome_dir, 'content'))
+jar.close()
+
+removedir(os.path.join(chrome_dir, 'content'))
+
+shutil.copy(os.path.join(pageloader_dir, 'tp-cmdline.js'), os.path.join(components_dir, 'tp-cmdline.js'))
+
+#get rid of the temporary directory
+removedir(tmp_dir)
+
diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.ex b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.ex
new file mode 100755
index 00000000000..1bc610c69b8
--- /dev/null
+++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.ex
@@ -0,0 +1,49 @@
+#!/usr/bin/expect
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla Corporation Code.
+#
+# The Initial Developer of the Original Code is
+# Bob Clary.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Bob Clary
+# Clint Talbert
+# Alice Nodelman
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+system mkdir -p mnt
+spawn hdiutil attach -verbose -noautoopen -mountpoint ./mnt $argv
+expect {
+"byte" {send "G"; exp_continue}
+"END" {send "\r"; exp_continue}
+"Y/N?" {send "Y\r"; exp_continue}
+}
+system rsync -a ./mnt/* .
+system hdiutil detach mnt
+system rm -rdf ./mnt
diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.sh b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.sh
new file mode 100644
index 00000000000..830fd52490b
--- /dev/null
+++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+mkdir -p mnt
+echo "y" | PAGER="/bin/cat" hdiutil attach -verbose -noautoopen -mountpoint ./mnt $1
+rsync -a ./mnt/* .
+hdiutil detach mnt
diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/tinderboxmailnotifier.py b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/tinderboxmailnotifier.py
new file mode 100644
index 00000000000..d14c9030a6a
--- /dev/null
+++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/tinderboxmailnotifier.py
@@ -0,0 +1,13 @@
+from buildbot.status import tinderbox
+
+class TinderboxMailNotifier(tinderbox.TinderboxMailNotifier):
+ """
+ Subclass TinderboxMailNotifier to add the slave name to the build.
+ This makes tinderbox happy if we have more than one slave working
+ on one builder.
+ """
+ def buildMessage(self, name, build, results):
+ return tinderbox.TinderboxMailNotifier.buildMessage(self,
+ name + ' ' +
+ build.getSlavename(),
+ build, results)