merge commit THUNDERBIRD_3_0_1_RELEASE THUNDERBIRD_3_1_a1_RELEASE
authorPhilippe M. Chiasson <gozer@mozillamessaging.com>
Mon, 11 Jan 2010 11:49:14 -0500
changeset 465 d4e41139c42a1fdd3abcdfca6e2553fc8ba4b333
parent 464 b13aabf2dce014f1e4cc20757c17443dfbf5fc21 (current diff)
parent 463 0d56851a9aa3008a47c0b79d44c1f9cf05b34f95 (diff)
child 466 269b6c356ebe8a824fce16350a2260a1511ae4c9
push id260
push usergozer@mozillamessaging.com
push dateMon, 11 Jan 2010 16:49:25 +0000
merge commit
--- a/.hgtags
+++ b/.hgtags
@@ -27,8 +27,11 @@ ca19bb7cbe812fa535b6ffd7d58826754bebe8a2
 20fdfcda3f82fb6b5182f50fd6e6745954b7828b FIREFOX_3_5_5_RELEASE
 605b16dc7e05259ded836d91804087a59980e90a FIREFOX_3_6b2_RELEASE
 5dc265010f4a61522e691034a09329bf31266159 FIREFOX_3_6b3_RELEASE
 990ac8896f2bfe442a5418bb9e357b01dbe8945e THUNDERBIRD_3_0rc1_RELEASE
 aee8bf61808eca5b416bfbf905d6ec07f3b29d74 FIREFOX_3_6b4_RELEASE
 c9999d50660f3b07003bda5c3cd621232830e6f4 FIREFOX_3_5_6_RELEASE
 4ba469cb1bffcf55d35452a3a4fcc2fa7608d067 FIREFOX_3_0_16_RELEASE
 90434a7d07c5d37e0bedc131224af079d62b9359 FIREFOX_3_6b5_RELEASE
+5e2d9cb03e90ee9b541ed5f642841ed367394af7 FIREFOX_3_5_7_RELEASE
+7451ab038fe72a2629afa323c0b3d6e5b74790a2 FIREFOX_3_0_17_RELEASE
+2075516e371ac6aabc6ae41e4dad85b52035532b FIREFOX_3_6rc1_RELEASE
--- a/buildbot-helpers/buildbot-tac.py
+++ b/buildbot-helpers/buildbot-tac.py
@@ -1,11 +1,12 @@
 #!/usr/bin/python
 
 import re
+import os
 
 DEFAULT_HEADER = """\
 from twisted.application import service
 from buildbot.slave.bot import BuildSlave
 
 """
 DEFAULT_FOOTER = """
 application = service.Application('buildslave')
@@ -32,26 +33,27 @@ def quote_option(str, raw=False):
         return "r'%s'" % str
     else:
         return "'%s'" % str
 
 def get_default_options(slavename):
     d = {'slavename': quote_option(slavename)}
     basedir = None
     buildmaster_host = None
-    if 'moz2' in slavename or 'xserve' in slavename or 'try-' in slavename:
+    if 'moz2' in slavename or 'xserve' in slavename or 'try-' in slavename or \
+      slavename.startswith('win32'):
         if 'try-' in slavename:
             buildmaster_host = TRY_BUILDMASTER
             d['port'] = 9982
         else:
             buildmaster_host = BUILD_BUILDMASTER
         if 'linux' in slavename or 'darwin9' in slavename or \
           'xserve' in slavename or 'mac' in slavename:
             basedir = '/builds/slave'
-        elif 'win32' in slavename:
+        elif 'win32' in slavename or 'w32' in slavename:
             basedir = 'e:\\builds\\moz2_slave'
     elif 'talos' in slavename or '-try' in slavename:
         buildmaster_host = TALOS_BUILDMASTER
         if '-try' in slavename:
             d['port'] = 9011
         if 'linux' in slavename or 'ubuntu' in slavename:
             basedir = '/home/mozqa/talos-slave'
         elif 'tiger' in slavename or 'leopard' in slavename:
@@ -95,30 +97,33 @@ class BuildbotTac:
                  filename="buildbot.tac"):
         self.tacOptions = self.defaults.copy()
         self.tacOptions.update(tacOptions)
         self.header = header
         self.footer = footer
         self.filename = filename
 
     def save(self):
+        tmpfile = '%s.tmp' % self.filename
         # Look for necessary, but missing options
         missingOptions = []
         for o in self.requiredOptions:
             if o not in self.tacOptions:
                 missingOptions.append(o)
         if missingOptions:
             raise MissingOptionsError("Missing %s, cannot save %s" % \
               (missingOptions, self.filename))
         # If there wasn't any, save the file
-        f = open(self.filename, "w")
+        f = open(tmpfile, "w")
         f.write(self.header)
         for key,value in self.tacOptions.iteritems():
             f.write("%s = %s\n" % (key, value))
         f.write(self.footer)
+        f.close()
+        os.rename(tmpfile, self.filename)
 
 
 
 if __name__ == '__main__':
     from optparse import OptionParser
     import socket
 
     parser = OptionParser()
new file mode 100644
--- /dev/null
+++ b/buildfarm/maintenance/master_cleanup.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+"""Script to clean up buildbot master directories"""
+import os
+from cPickle import load
+
+def maybe_delete(filename, timestamp):
+    """Delete filename if it's older than timestamp"""
+    try:
+        if os.path.getmtime(filename) < timestamp:
+            os.unlink(filename)
+    except OSError:
+        # Ignore this error.  The file may have already been moved.
+        # We'll get it next time!
+        pass
+
+def clean_dir(dirname, timestamp):
+    """Delete old twisted log files, and old builder files from dirname"""
+    # Clean up files older than timestamp
+    files = os.listdir(dirname)
+    # Look for twistd.log files
+    for f in files:
+        p = os.path.join(dirname, f)
+        if f.startswith("twistd.log"):
+            maybe_delete(p, timestamp)
+
+        elif os.path.isdir(p):
+            builder_file = os.path.join(p, "builder")
+            # Don't clean out non-builder directories
+            if not os.path.exists(builder_file):
+                continue
+
+            try:
+                builder = load(open(builder_file))
+            except:
+                continue
+
+            # Don't clean out release builders
+            if builder and builder.category and \
+                    builder.category.endswith('release'):
+                continue
+
+            for build in os.listdir(p):
+                # Don't delete the 'builder' file
+                if build == "builder":
+                    continue
+                build = os.path.join(p, build)
+                if os.path.isfile(build):
+                    maybe_delete(build, timestamp)
+
+if __name__ == "__main__":
+    import time
+    from optparse import OptionParser
+    parser = OptionParser()
+    parser.add_option("-t", "--time", dest="time", type="int",
+        help="time, in days, for how old files have to be before being deleted",
+        default=4)
+
+    options, args = parser.parse_args()
+
+    if len(args) == 0:
+        parser.error("Must specify at least one directory to clean up")
+
+    for d in args:
+        clean_dir(d, time.time() - options.time * 24*3600)
new file mode 100644
--- /dev/null
+++ b/buildfarm/maintenance/purge_events.py
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+"""Run in a buildbot master directory once the master is shut down to
+purge old events from the builder files.
+
+NB: The master must be shut down for this to work!"""
+import cPickle, os, shutil
+
+for f in os.listdir("."):
+    builder_file = os.path.join(f, "builder")
+    if os.path.isdir(f) and os.path.exists(builder_file):
+        builder = cPickle.load(open(builder_file))
+        if builder.category == 'release':
+            print "Skipping", builder_file
+            continue
+        print "Backing up", builder_file
+        shutil.copyfile(builder_file, builder_file + ".bak")
+
+        # Set some dummy attributes that get deleted by __getstate__
+        builder.currentBigState = None
+        builder.basedir = None
+        builder.status = None
+        builder.nextBuildNumber = None
+
+        # Truncate to 500 events
+        builder.events = builder.events[-500:]
+        print "Writing", builder_file
+        cPickle.dump(builder, open(builder_file, "w"))
--- a/clobberer/clobberer.py
+++ b/clobberer/clobberer.py
@@ -1,33 +1,32 @@
-import sys, shutil, urllib2, urllib, os
-from datetime import datetime, timedelta
+#!/usr/bin/python
+# vim:sts=2 sw=2
+import sys, shutil, urllib2, urllib, os, traceback, time
 
 clobber_suffix='.deleteme'
 
-def str_to_datetime(s):
-  return datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
-
-def datetime_to_str(dt):
-  return dt.strftime("%Y-%m-%d %H:%M:%S")
+def ts_to_str(ts):
+  if ts is None:
+    return None
+  return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ts))
 
-def write_file(dt, fn):
-  assert isinstance(dt, datetime)
-  dt = datetime_to_str(dt)
+def write_file(ts, fn):
+  assert isinstance(ts, int)
   f = open(fn, "w")
-  f.write(dt)
+  f.write(str(ts))
   f.close()
 
 def read_file(fn):
   if not os.path.exists(fn):
     return None
 
   data = open(fn).read().strip()
   try:
-    return str_to_datetime(data)
+    return int(data)
   except ValueError:
     return None
 
 def rmdirRecursive(dir):
     """This is a replacement for shutil.rmtree that works better under
     windows. Thanks to Bear at the OSAF for the code.
     (Borrowed from buildbot.slave.commands)"""
     if not os.path.exists(dir):
@@ -84,93 +83,137 @@ def do_clobber(dir, dryrun=False, skip=N
       elif os.path.isdir(f):
         print "Removing %s/" % f
         if not dryrun:
           if os.path.exists(clobber_path):
             rmdirRecursive(clobber_path)
           # Prevent repeated moving.
           if f.endswith(clobber_suffix):
             rmdirRecursive(f)
-          else:              
+          else:
             shutil.move(f, clobber_path)
             rmdirRecursive(clobber_path)
   except:
     print "Couldn't clobber properly, bailing out."
     sys.exit(1)
 
-def getClobberDate(baseURL, branch, builder, slave):
-  url = "%s?%s" % (baseURL,
-      urllib.urlencode(dict(branch=branch, builder=builder, slave=slave)))
+def getClobberDates(clobberURL, branch, buildername, builddir, slave, master):
+  params = dict(branch=branch, buildername=buildername, builddir=builddir, slave=slave, master=master)
+  url = "%s?%s" % (clobberURL, urllib.urlencode(params))
   print "Checking clobber URL: %s" % url
   data = urllib2.urlopen(url).read().strip()
+
+  retval = {}
   try:
-    return str_to_datetime(data)
+    for line in data.split("\n"):
+      line = line.strip()
+      if not line:
+        continue
+      builddir, builder_time, who = line.split(":")
+      builder_time = int(builder_time)
+      retval[builddir] = (builder_time, who)
+    return retval
   except ValueError:
-    return None
+    print "Error parsing response from server"
+    print data
+    raise
 
 if __name__ == "__main__":
   from optparse import OptionParser
-  parser = OptionParser()
+  parser = OptionParser("%prog [options] clobberURL branch buildername builddir slave master")
   parser.add_option("-n", "--dry-run", dest="dryrun", action="store_true",
       default=False, help="don't actually delete anything")
   parser.add_option("-t", "--periodic", dest="period", type="float",
-      default=24*7, help="hours between periodic clobbers")
-  parser.add_option('-s', '--skip', help='do not delete this directory',
+      default=None, help="hours between periodic clobbers")
+  parser.add_option('-s', '--skip', help='do not delete this file/directory',
       action='append', dest='skip', default=['last-clobber'])
   parser.add_option('-d', '--dir', help='clobber this directory',
       dest='dir', default='.', type='string')
+  parser.add_option('-v', '--verbose', help='be more verbose',
+      dest='verbose', action='store_true', default=False)
 
   options, args = parser.parse_args()
-  periodicClobberTime = timedelta(hours = options.period)
+  if len(args) != 6:
+    parser.error("Incorrect number of arguments")
 
-  baseURL, branch, builder, slave = args
+  if options.period:
+    periodicClobberTime = options.period * 3600
+  else:
+    periodicClobberTime = None
+
+  clobberURL, branch, builder, my_builddir, slave, master = args
 
   try:
-    server_clobber_date = getClobberDate(baseURL, branch, builder, slave)
+    server_clobber_dates = getClobberDates(clobberURL, branch, builder, my_builddir, slave, master)
   except:
+    if options.verbose:
+      traceback.print_exc()
     print "Error contacting server"
     sys.exit(1)
 
-  our_clobber_date = read_file("last-clobber")
+  if options.verbose:
+    print "Server gave us", server_clobber_dates
+
+  now = int(time.time())
 
-  clobber = False
+  # Add ourself to the server_clobber_dates if it's not set
+  # This happens when this slave has never been clobbered
+  if my_builddir not in server_clobber_dates:
+    server_clobber_dates[my_builddir] = None, ""
 
-  print "Our last clobber date: ", our_clobber_date
-  print "Server clobber date:   ", server_clobber_date
+  root_dir = os.path.abspath(options.dir)
 
-  # If we don't have a last clobber date, then this is probably a fresh build.
-  # We should only do a forced server clobber if we know when our last clobber
-  # was, and if the server date is more recent than that.
-  if server_clobber_date is not None and our_clobber_date is not None:
-    # If the server is giving us a clobber date, compare the server's idea of
-    # the clobber date to our last clobber date
-    if server_clobber_date > our_clobber_date:
-      # If the server's clobber date is greater than our last clobber date,
-      # then we should clobber.
-      clobber = True
-      # We should also update our clobber date to match the server's
-      our_clobber_date = server_clobber_date
-      print "Server is forcing a clobber"
+  for builddir, (server_clobber_date, who) in server_clobber_dates.items():
+    builder_dir = os.path.join(root_dir, builddir)
+    if not os.path.isdir(builder_dir):
+      print "%s doesn't exist, skipping" % builder_dir
+      continue
+    os.chdir(builder_dir)
+
+    our_clobber_date = read_file("last-clobber")
+
+    clobber = False
+
+    print "%s:Our last clobber date: " % builddir, ts_to_str(our_clobber_date)
+    print "%s:Server clobber date:   " % builddir, ts_to_str(server_clobber_date)
 
-  if not clobber:
-    # Next, check if more than the periodicClobberTime period has passed since
-    # our last clobber
-    if our_clobber_date is None:
-      # We've never been clobbered
-      # Set our last clobber time to now, so that we'll clobber
-      # properly after periodicClobberTime
-      our_clobber_date = datetime.utcnow()
+    # If we don't have a last clobber date, then this is probably a fresh build.
+    # We should only do a forced server clobber if we know when our last clobber
+    # was, and if the server date is more recent than that.
+    if server_clobber_date is not None and our_clobber_date is not None:
+      # If the server is giving us a clobber date, compare the server's idea of
+      # the clobber date to our last clobber date
+      if server_clobber_date > our_clobber_date:
+        # If the server's clobber date is greater than our last clobber date,
+        # then we should clobber.
+        clobber = True
+        # We should also update our clobber date to match the server's
+        our_clobber_date = server_clobber_date
+        if who:
+          print "%s:Server is forcing a clobber, initiated by %s" % (builddir, who)
+        else:
+          print "%s:Server is forcing a clobber" % builddir
+
+    if not clobber:
+      # Disable periodic clobbers for builders that aren't my_builddir
+      if builddir != my_builddir:
+        continue
+
+      # Next, check if more than the periodicClobberTime period has passed since
+      # our last clobber
+      if our_clobber_date is None:
+        # We've never been clobbered
+        # Set our last clobber time to now, so that we'll clobber
+        # properly after periodicClobberTime
+        our_clobber_date = now
+        write_file(our_clobber_date, "last-clobber")
+      elif periodicClobberTime and now > our_clobber_date + periodicClobberTime:
+        # periodicClobberTime has passed since our last clobber
+        clobber = True
+        # Update our clobber date to now
+        our_clobber_date = now
+        print "%s:More than %s seconds have passed since our last clobber" % (builddir, periodicClobberTime)
+
+    if clobber:
+      # Finally, perform a clobber if we're supposed to
+      print "%s:Clobbering..." % builddir
+      do_clobber(builder_dir, options.dryrun, options.skip)
       write_file(our_clobber_date, "last-clobber")
-    elif datetime.utcnow() > our_clobber_date + periodicClobberTime:
-      # periodicClobberTime has passed since our last clobber
-      clobber = True
-      # Update our clobber date to now
-      our_clobber_date = datetime.utcnow()
-      print "More than %s have passed since our last clobber" % periodicClobberTime
-
-  if clobber:
-    # Finally, perform a clobber if we're supposed to
-    if os.path.exists(options.dir):
-      print "Clobbering..."
-      do_clobber(options.dir, options.dryrun, options.skip)
-    else:
-      print "Clobber failed because '%s' doesn't exist" % options.dir
-    write_file(our_clobber_date, "last-clobber")
--- a/clobberer/index.php
+++ b/clobberer/index.php
@@ -3,81 +3,271 @@
 This is a web interface that allows developers to clobber buildbot
 builds on a per-slave/per-builder basis.
 
 This script simply updates a database that Buildbot reads from at the start of
 every build.
 http://hg.mozilla.org/build/buildbotcustom/file/default/process/factory.py
 */
 
-$CLOBBERER_DB = '/var/www/html/build/stage-clobberer/db/clobberer.db';
-//$CLOBBERER_DB = '/var/www/html/build/clobberer/clobberer.db';
+$CLOBBERER_DB = 'db/clobberer.db';
+
+$RELEASE_BUILDERS = array(
+  'linux_build',
+  'macosx_build',
+  'win32_build',
+  'wince_build',
+
+  'linux_repack',
+  'macosx_repack',
+  'win32_repack',
+  'wince_repack',
+
+  'linux_update_verify',
+  'macosx_update_verify',
+  'win32_update_verify',
+  'wince_update_verify',
+
+  'release-linux-unittest-mochitests',
+  'release-linux-unittest-everythingelse',
+  'release-win32-unittest-mochitests',
+  'release-win32-unittest-everythingelse',
+  'release-macosx-unittest-mochitests',
+  'release-macosx-unittest-everythingelse',
+
+  'final_verification',
+  'l10n_verification',
+  'tag',
+  'source',
+  'updates',
+);
+
+// TODO: Figure out if we can use LDAP to do this
+$SPECIAL_PEOPLE = array(
+  'anodelman@mozilla.com',
+  'armenzg@mozilla.com',
+  'asasaki@mozilla.com',
+  'bhearsum@mozilla.com',
+  'catlee@mozilla.com',
+  'coop@mozilla.com',
+  'jhford@mozilla.com',
+  'joduinn@mozilla.com',
+  'lsblakk@mozilla.com',
+  'nthomas@mozilla.com',
+);
 
 $dbh = new PDO("sqlite:$CLOBBERER_DB");
 if (!$dbh) {
   header('HTTP/1.0 500 Internal Server Error');
   print("<h1>Error: couldn't connect</h1>");
   print($error);
   exit(0);
 }
 
 $q = $dbh->query('SELECT count(*) FROM sqlite_master WHERE NAME="clobber_times"');
 $exists = $q->fetch(PDO::FETCH_NUM);
 if (!$exists or !$exists[0]) {
+  $res = $dbh->exec('CREATE TABLE builds ('
+                   .'id INTEGER PRIMARY KEY AUTOINCREMENT,'
+                   .'master VARCHAR(100),'
+                   .'branch VARCHAR(50),'
+                   .'buildername VARCHAR(100),'
+                   .'builddir VARCHAR(100),'
+                   .'slave VARCHAR(30),'
+                   .'last_build_time INTEGER)');
+  if ($res === FALSE) {
+    die(print_r($dbh->errorInfo(), TRUE));
+  }
+
   $res = $dbh->exec('CREATE TABLE clobber_times ('
                    .'id INTEGER PRIMARY KEY AUTOINCREMENT,'
+                   .'master VARCHAR(100),'
                    .'branch VARCHAR(50),'
-                   .'builder VARCHAR(50),'
+                   .'builddir VARCHAR(100),'
                    .'slave VARCHAR(30),'
-                   .'lastclobber VARCHAR(30),'
-                   .'clobberer VARCHAR(50))');
+                   .'lastclobber INTEGER,'
+                   .'who VARCHAR(50))');
   if ($res === FALSE) {
     die(print_r($dbh->errorInfo(), TRUE));
   }
   chmod($CLOBBERER_DB, 0660);
 }
 
+function isSpecial($user)
+{
+  // TODO: Figure out if we can use LDAP to get the group of $user
+  global $SPECIAL_PEOPLE;
+  return in_array($user, $SPECIAL_PEOPLE);
+}
+
+function canSee($builddir, $user)
+{
+  global $RELEASE_BUILDERS;
+  if (!in_array($builddir, $RELEASE_BUILDERS)) {
+    return true;
+  }
+
+  return isSpecial($user);
+}
+
 function b64_encode($s)
 {
   return rtrim(base64_encode($s), "=");
 }
 
 function e($str)
 {
   global $dbh;
   return $dbh->quote($str);
 }
 
+function getBuilders($slave)
+{
+  global $dbh;
+  $slave = e($slave);
+  $retval = array();
+  $builders = $dbh->query("SELECT DISTINCT builddir from builds where slave=$slave");
+  while ($r = $builders->fetch(PDO::FETCH_ASSOC)) {
+    // Find the most recent build for this builder
+    $builddir = e($r['builddir']);
+    $build = $dbh->query("SELECT buildername, builddir, branch FROM builds WHERE builddir = $builddir ORDER by last_build_time DESC LIMIT 1");
+    $r = $build->fetch(PDO::FETCH_ASSOC);
+    if ($r) {
+      $retval[] = $r;
+    }
+  }
+  return $retval;
+}
+
+function getMasters()
+{
+  global $dbh;
+  $retval = array();
+  $masters = $dbh->query("SELECT DISTINCT master from builds");
+  while ($r = $masters->fetch(PDO::FETCH_ASSOC)) {
+    $retval[] = $r['master'];
+  }
+  return $retval;
+}
+
+function updateBuildTime($master, $branch, $buildername, $builddir, $slave)
+{
+  global $dbh;
+  $master = e($master);
+  $branch = e($branch);
+  $buildername = e($buildername);
+  $builddir = e($builddir);
+  $slave = e($slave);
+  $now = time();
+
+  $rows = $dbh->exec("UPDATE builds SET last_build_time = $now WHERE master=$master AND "
+      ."branch=$branch AND buildername=$buildername AND slave=$slave");
+  if ($rows == 0) {
+      $dbh->exec("INSERT INTO builds "
+          ."(master, branch, buildername, builddir, slave, last_build_time) VALUES "
+          ."($master, $branch, $buildername, $builddir, $slave, $now)");
+      return true;
+  }
+  return false;
+}
+
+function getClobberTime($master, $branch, $builddir, $slave)
+{
+  global $dbh;
+  $master = e($master);
+  $branch = e($branch);
+  $builddir = e($builddir);
+  $slave = e($slave);
+  $q = "SELECT id, who, lastclobber FROM clobber_times WHERE "
+      ."builddir = $builddir AND (branch IS NULL OR branch = $branch) AND "
+      ."(master IS NULL OR master = $master) AND (slave IS NULL OR slave = $slave) "
+      ."ORDER BY lastclobber DESC LIMIT 1";
+  $s = $dbh->query($q);
+  $r = $s->fetch(PDO::FETCH_ASSOC);
+  if (!$r) {
+    return null;
+  }
+  else
+  {
+    return $r;
+  }
+}
+
 //
 // Handle form submission
 //
 if ($_POST['form_submitted']) {
   $clobbers = array();
   $slaves = array();
+  $user = $_SERVER['REMOTE_USER'];
+  $e_user = e($user);
+  $now = time();
   foreach ($_POST as $k => $v) {
+    if ($k == "master") {
+      if (isSpecial($user)) {
+        $branch = $_POST['branch'];
+        if ($branch != '') {
+          $branch = e($branch);
+        } else {
+          $branch = 'NULL';
+        }
+        $builddir = $_POST['builddir'];
+        if ($builddir != '') {
+            $builders = array($builddir);
+        } else {
+            $builders = $RELEASE_BUILDERS;
+        }
+        if ($v != '') {
+          $master = e($v);
+        } else {
+          $master = 'NULL';
+        }
+        foreach ($builders as $builddir) {
+          $builddir = e($builddir);
+          $q = "INSERT INTO clobber_times "
+              ."(master, branch, builddir, slave, who, lastclobber) VALUES "
+              ."($master, $branch, $builddir, NULL, $e_user, $now)";
+          $dbh->exec($q) or die(print_r($dbh->errorInfo(), TRUE));
+        }
+      }
+      continue;
+    }
     $t = explode('-', $k, 2);
     // We only care about slave-<$row_id>
     // This corresponds to a row that specifies which branch/builder/slave to clobber
     if ($t[0] == 'slave') {
       $row_id = e($t[1]);
-      $user = e($_SERVER['REMOTE_USER']);
-      $dbh->exec("UPDATE clobber_times SET lastclobber = DATETIME(\"NOW\"), clobberer = $user WHERE id = $row_id");
+      $s = $dbh->query("SELECT * from builds where id = $row_id");
+      $r = $s->fetch(PDO::FETCH_ASSOC);
+      if ($r)
+      {
+        $builddir = e($r['builddir']);
+        $branch = e($r['branch']);
+        $slave = e($r['slave']);
+        if (canSee($builddir, $user)) {
+            $dbh->exec("INSERT INTO clobber_times "
+                ."(master, branch, builddir, slave, who, lastclobber) VALUES "
+                ."(NULL, $branch, $builddir, $slave, $e_user, $now)") or die(print_r($$dbh->errorInfo(), TRUE));
+        }
+      }
     }
   }
   // Redirect the user to the main page
   // This prevents accidentally resubmitting the form if the user reloads the 
   // page
   header("Location: " . $_SERVER['REQUEST_URI']);
 }
 
-$builder = $_GET['builder'];
-$slave = $_GET['slave'];
-$branch = $_GET['branch'];
+$buildername = urldecode($_GET['buildername']);
+$builddir = urldecode($_GET['builddir']);
+$slave = urldecode($_GET['slave']);
+$branch = urldecode($_GET['branch']);
+$master = urldecode($_GET['master']);
 // Show the administration page if no clobber time is being queried
-if (!$builder) {
+if (!$buildername) {
 ?>
 <html>
 <head>
 <title>Mozilla Buildbot Clobberer</title>
 <link rel="stylesheet" href="clobberer.css" type="text/css" />
 <script src="jquery.min.js" language="javascript"></script>
 <script language="javascript">
 function toggleall(node, klass)
@@ -118,89 +308,148 @@ function toggleall(node, klass)
 </script>
 </head>
 <body>
 <p>This page is used for clobbering buildbot-based builds.</p>
 <p>Please read
 <a href="https://wiki.mozilla.org/Build:ClobberingATinderbox">Build:ClobberingATinderbox</a>
 and/or <a href="https://wiki.mozilla.org/Clobbering_the_Tree">Clobbering the Tree</a>
 for more information about what this page is for, and how to use it.</p>
+<?php
+  if (in_array($_SERVER['REMOTE_USER'], $SPECIAL_PEOPLE)) {
+?>
+<h1>Release Clobbers</h1>
+<form method="POST">
+<input type="hidden" name="form_submitted" value="true">
+Clobber all release builders on <select name="master">
+<option value="">Any master</option>
+<?php
+  $masters = getMasters();
+  foreach ($masters as $master) {
+    $e_master = htmlspecialchars($master);
+    print "<option value=\"$e_master\">$master</option>\n";
+  }
+?>
+</select>
+<select name="branch">
+<option value="">Any release</option>
+<?php
+  $builders = "";
+  $first = true;
+  foreach ($RELEASE_BUILDERS as $b) {
+    if (!$first) {
+      $builders .= ",";
+    }
+    $first = false;
+    $builders .= e($b);
+  }
+  $releases = $dbh->query("SELECT DISTINCT branch FROM builds WHERE builddir IN ($builders)");
+  while ($release = $releases->fetch(PDO::FETCH_ASSOC)) {
+    $release = $release['branch'];
+    $e_release = htmlspecialchars($release);
+    print "<option value=\"$e_release\">$release</option>\n";
+  }
+?>
+</select>
+<select name="builddir">
+<option value="">Any builder</option>
+<?php
+  $builders = "";
+  $first = true;
+  foreach ($RELEASE_BUILDERS as $b) {
+    $e_b = htmlspecialchars($b);
+    print "<option value=\"$e_b\">$b</option>\n";
+  }
+?>
+</select>
+
+<input type="submit" value="Wipe them out!">
+</form>
+
+<h1>Regular Clobbers</h1>
+
+<?php } ?>
+
 <form method="POST">
 <table border="1" cellspacing="0" cellpadding="1">
  <thead>
   <tr><td>Branch</td><td>Builder Name</td><td>Slaves</td><td>Last clobbered</td></tr>
  </thead>
  <tbody>
 <?php
-  $allbuilders = $dbh->query('SELECT * FROM clobber_times ORDER BY branch ASC, builder ASC');
+  $allbuilders = $dbh->query('SELECT DISTINCT id, branch, builddir, buildername, slave FROM builds ORDER BY branch ASC, buildername ASC');
   if ($allbuilders) {
     $last_branch = null;
     $last_builder = null;
-    // First pass: count the number of rows for each branch / builder so we can 
+    // First pass: count the number of rows for each branch / buildername so we can 
     // set the 'rowspan' attribute
     $rows_per_branch = array();
     $rows_per_builder = array();
     $rows = array();
     while ($r = $allbuilders->fetch(PDO::FETCH_ASSOC)) {
+      if (!canSee($r['builddir'], $_SERVER['REMOTE_USER'])) {
+        continue;
+      }
       $rows[] = $r;
-      $builder = $r['builder'];
+      $buildername = $r['buildername'];
       $branch = $r['branch'];
-      if (!array_key_exists($builder, $rows_per_builder)) {
-        $rows_per_builder[$builder] = 1;
+      if (!array_key_exists($buildername, $rows_per_builder)) {
+        $rows_per_builder[$buildername] = 1;
       } else {
-        $rows_per_builder[$builder] += 1;
+        $rows_per_builder[$buildername] += 1;
       }
       if (!array_key_exists($branch, $rows_per_branch)) {
         $rows_per_branch[$branch] = 1;
       } else {
         $rows_per_branch[$branch] += 1;
       }
     }
     // Sort the results
     function sort_func($r1, $r2) {
       $c1 = strnatcmp($r1['branch'], $r2['branch']);
       if ($c1 != 0) {
         return $c1;
       }
-      $c2 = strnatcmp($r1['builder'], $r2['builder']);
+      $c2 = strnatcmp($r1['buildername'], $r2['buildername']);
       if ($c2 != 0) {
         return $c2;
       }
       return strnatcmp($r1['slave'], $r2['slave']);
     }
     usort($rows, sort_func);
     // Second pass we output the HTML
     foreach ($rows as $r) {
       print "<tr>";
       if ($last_branch != $r['branch']) {
         $branch_id = b64_encode($r['branch']);
         $rowspan = $rows_per_branch[$r['branch']];
         print "<td rowspan=\"$rowspan\">";
         print "<input type=\"checkbox\" id=\"$branch_id\" onchange=\"toggleall(this, &quot;$branch_id&quot;)\" />";
         print htmlspecialchars($r['branch']) . "</td>\n";
       }
-      if ($last_builder != $r['builder']) {
-        $rowspan = $rows_per_builder[$r['builder']];
-        $builder_id = b64_encode($r['builder']);
+      if ($last_builder != $r['buildername']) {
+        $rowspan = $rows_per_builder[$r['buildername']];
+        $builder_id = b64_encode($r['buildername']);
         $classes = b64_encode($r['branch']);
         print "<td rowspan=\"$rowspan\"><input type=\"checkbox\" id=\"$builder_id\" class=\"$classes\" onchange=\"toggleall(this, &quot;$builder_id&quot;)\" />";
-        print htmlspecialchars($r['builder']) . "</td>\n";
+        print htmlspecialchars($r['buildername']) . "</td>\n";
       }
-      $classes = b64_encode($r['builder']) . " " . b64_encode($r['branch']);
+      $classes = b64_encode($r['buildername']) . " " . b64_encode($r['branch']);
       $name = "slave-" . $r['id'];
       print "<td><input type=\"checkbox\" name=\"$name\" class=\"$classes\" onchange=\"toggleall(this)\" />";
       print htmlspecialchars($r['slave']) . "</td>\n";
-      if ($r['lastclobber']) {
-        print "<td>" . htmlspecialchars($r['lastclobber']) . "(UTC) by " . htmlspecialchars($r['clobberer']) . "</td>\n";
+      $lastclobber = getClobberTime(null, $r['branch'], $r['builddir'], $r['slave']);
+      if ($lastclobber) {
+        print "<td>" . strftime("%Y-%m-%d %H:%M:%S %Z", $lastclobber['lastclobber']) . " by " . htmlspecialchars($lastclobber['who']) . "</td>\n";
       } else {
         print "<td></td>\n";
       }
       print "</tr>\n";
       $last_branch = $r['branch'];
-      $last_builder = $r['builder'];
+      $last_builder = $r['buildername'];
     }
   } else {
     print "<tr><td colspan=\"9\">No data</td></tr>\n";
   }
 ?>
  </tbody>
 </table>
 <input type="hidden" name="form_submitted" value="true">
@@ -208,27 +457,51 @@ for more information about what this pag
 </form>
 </body>
 </html>
 <?php
   exit(0);
 }
 
 // Handle requests from slaves asking about their last clobber date
-$e_builder = e($builder);
-$e_slave = e($slave);
-$e_branch = e($branch);
-$s = $dbh->query("SELECT id, lastclobber FROM clobber_times WHERE builder = $e_builder AND slave = $e_slave AND branch = $e_branch");
-$r = $s->fetch(PDO::FETCH_ASSOC);
-if (!$r) {
-  // If this branch/builder/slave combination doesn't yet exist in the 
-  // database, then insert it
-  $res = $dbh->exec("INSERT INTO clobber_times (branch, builder, slave) VALUES ($e_branch, $e_builder, $e_slave)");
-  if ($res === false) {
-    header("HTTP/1.x 500 Internal Server Error");
-    print "Couldn't insert row<br/>\n";
-    die(print_r($dbh->errorInfo(), TRUE));
+
+// First, find the list of builders for this slave
+$slave_builders = getBuilders($slave);
+
+// Make sure that the current branch/builder is in that list
+$found = false;
+foreach ($slave_builders as $sb) {
+    if ($sb['builddir'] == $builddir && $sb['branch'] == $branch) {
+        $found = true;
+        break;
+    }
+}
+if (!$found) {
+    $slave_builders[] = array('builddir' => $builddir, 'branch' => $branch);
+}
+
+// And check the clobber time for each buildername
+$clobber_times = array();
+foreach ($slave_builders as $sb) {
+  $r = getClobberTime($master, $sb['branch'], $sb['builddir'], $slave);
+  if ($r) {
+    if (!array_key_exists($sb['builddir'], $clobber_times)) {
+      $clobber_times[$sb['builddir']] = array('lastclobber'=>$r['lastclobber'], 'who'=>$r['who']);
+    } else {
+      $t = $clobber_times[$sb['builddir']]['lastclobber'];
+      if ($r['lastclobber'] > $t) {
+        $clobber_times[$sb['builddir']] = array('lastclobber'=>$r['lastclobber'], 'who'=>$r['who']);
+      }
+    }
   }
 }
-else {
-  print $r['lastclobber'];
+
+// Tell the slave what to clobber
+foreach ($clobber_times as $b => $r) {
+  $lastclobber = $r['lastclobber'];
+  $who = $r['who'];
+  print "$b:$lastclobber:$who\n";
 }
+
+// Finally, update our table of when builds are happening
+$new = updateBuildTime($master, $branch, $buildername, $builddir, $slave);
+
 ?>
new file mode 100644
--- /dev/null
+++ b/clobberer/test_clobberer.py
@@ -0,0 +1,357 @@
+from unittest import TestCase
+import sqlite3
+import os
+import subprocess
+import urllib
+import time
+import shutil
+
+###
+# For testing, update the values below to be suitable to your testing
+# environment
+###
+clobberURL = "http://localhost/~catlee/index.php"
+dbFile = "/home/catlee/public_html/db/clobberer.db"
+testDir = 'test-dir'
+
+###
+# Various utility functions for setting up a test case
+###
+def updateBuild(branch, buildername, builddir, slave, master):
+    """Send an update to the server to indicate that a slave is doing a build.
+    Returns the server's response."""
+    params = dict(branch=branch, buildername=buildername, builddir=builddir,
+            slave=slave, master=master)
+    url = "%s?%s" % (clobberURL, urllib.urlencode(params))
+    data = urllib.urlopen(url).read().strip()
+    return data
+
+def setClobber(branch, builddir, slave, master, now):
+    """Schedules a clobber by inserting data directly into the database."""
+    db = sqlite3.connect(dbFile)
+    db.execute("""INSERT INTO clobber_times
+            (master, branch, builddir, slave, lastclobber, who)
+            VALUES (?, ?, ?, ?, ?, 'testuser')""",
+        (master, branch, builddir, slave, now))
+    db.commit()
+
+def getClobbers():
+    """Returns a list of all entries in the clobber_times table"""
+    db = sqlite3.connect(dbFile)
+    res = db.execute("SELECT * FROM clobber_times")
+    return res.fetchall()
+
+def getBuilds():
+    """Returns a list of all entries in the builds table"""
+    db = sqlite3.connect(dbFile)
+    res = db.execute("SELECT * FROM builds")
+    return res.fetchall()
+
+def makeBuildDir(name, t):
+    """Create a fake build directory in our testDir, with last-clobber set to
+    `t`"""
+    builddir = os.path.join(testDir, name)
+    if not os.path.exists(builddir):
+        os.makedirs(builddir)
+    open(os.path.join(builddir, 'last-clobber'), "w").write(str(t))
+
+def runClobberer(branch, buildername, builddir, slave, master, periodic=None,
+        dry_run=True):
+    """Run the clobberer.py script, and return the output"""
+    if not os.path.exists(testDir):
+        os.makedirs(testDir)
+    cmd = ['python', os.path.abspath('clobberer.py'), '-v']
+    if periodic:
+        cmd.extend(['-t', str(periodic)])
+    if dry_run:
+        cmd.append('-n')
+    cmd.extend([clobberURL, branch, buildername, builddir, slave, master])
+    p = subprocess.Popen(cmd, cwd=testDir, stdout=subprocess.PIPE)
+    p.wait()
+    return p.stdout.read()
+
+###
+# Test cases
+###
+class TestClobber(TestCase):
+    def setUp(self):
+        if os.path.exists(dbFile):
+            os.unlink(dbFile)
+        # Hit the clobberURL to create the database file
+        urllib.urlopen(clobberURL).read()
+
+        # Create a working directory
+        if os.path.exists(testDir):
+            shutil.rmtree(testDir)
+        os.makedirs(testDir)
+
+    def tearDown(self):
+        if os.path.exists(testDir):
+            shutil.rmtree(testDir)
+
+    def testUpdateBuild(self):
+        # Test that build entries are getting into the DB properly
+        updateBuild("branch1", "My Builder", "mybuilder", "slave01", "master01");
+        updateBuild("branch1", "My Builder 2", "mybuilder2", "slave01", "master01");
+
+        builds = getBuilds()
+        # Strip out db id and time
+        builds = [b[1:-1] for b in builds]
+        builds.sort()
+        self.assertEquals(len(builds), 2)
+        self.assertEquals(builds[0],
+                ("master01", "branch1", "My Builder", "mybuilder", "slave01"))
+        self.assertEquals(builds[1],
+                ("master01", "branch1", "My Builder 2", "mybuilder2", "slave01")
+                )
+
+    def testUpdateBuildWithClobber(self):
+        # Test that build entries are getting into the DB properly
+        # this time when a clobber is set
+        now = int(time.time())
+        setClobber("branch1", "mybuilder", "slave01", None, now)
+        updateBuild("branch1", "My Builder", "mybuilder", "slave01", "master01");
+        updateBuild("branch1", "My Builder 2", "mybuilder2", "slave01", "master01");
+
+        builds = getBuilds()
+        # Strip out db id and time
+        builds = [b[1:-1] for b in builds]
+        builds.sort()
+        self.assertEquals(len(builds), 2)
+        self.assertEquals(builds[0],
+                ("master01", "branch1", "My Builder", "mybuilder", "slave01"))
+        self.assertEquals(builds[1],
+                ("master01", "branch1", "My Builder 2", "mybuilder2", "slave01")
+                )
+
+    def testSetSlaveClobber(self):
+        # Clobber one builder on one slave, regardless of master
+        now = int(time.time())
+        setClobber("branch1", "mybuilder", "slave01", None, now)
+
+        # Add a build on another builder, to make sure it's not getting
+        # clobbered
+        data = updateBuild("branch1", "My Builder 2", "mybuilder2", "slave01",
+                "master01")
+        self.assert_("mybuilder2" not in data, data)
+
+        # Check that build on master01 gets clobbered
+        data = updateBuild("branch1", "My Builder", "mybuilder", "slave01",
+                "master01")
+        self.assertEquals(data, "mybuilder:%s:testuser" % now)
+
+        # Check that build on master02 gets clobbered
+        data = updateBuild("branch1", "My Builder", "mybuilder", "slave01",
+                "master02")
+        self.assertEquals(data, "mybuilder:%s:testuser" % now)
+
+    def testSetMasterClobber(self):
+        # Clobber one builder on any slave on one master
+        now = int(time.time())
+        setClobber("branch1", "mybuilder", None, "master01", now)
+
+        # Add a build on another builder, to make sure it's not getting
+        # clobbered
+        data = updateBuild("branch1", "My Builder 2", "mybuilder2", "slave01",
+                "master01")
+        self.assert_("mybuilder2" not in data, data)
+
+        # Check that the build is clobbered on all slaves on master01
+        data = updateBuild("branch1", "My Builder", "mybuilder", "slave01",
+                "master01")
+        self.assertEquals(data, "mybuilder:%s:testuser" % now)
+        data = updateBuild("branch1", "My Builder", "mybuilder", "slave02",
+                "master01")
+        self.assertEquals(data, "mybuilder:%s:testuser" % now)
+
+        # But not on master02
+        data = updateBuild("branch1", "My Builder", "mybuilder", "slave01",
+                "master02")
+        self.assertEquals(data, "")
+        data = updateBuild("branch1", "My Builder", "mybuilder", "slave02",
+                "master02")
+        self.assertEquals(data, "")
+
+    def testSetSlaveMasterClobber(self):
+        # Clobber one builder on one slave on one master
+        now = int(time.time())
+        setClobber("branch1", "mybuilder", "slave01", "master01", now)
+
+        # Add a build on another builder, to make sure it's not getting
+        # clobbered
+        data = updateBuild("branch1", "My Builder 2", "mybuilder2", "slave01",
+                "master01")
+        self.assert_("mybuilder2" not in data, data)
+
+        # Check that the build is clobbered on master01
+        data = updateBuild("branch1", "My Builder", "mybuilder", "slave01",
+                "master01")
+        self.assertEquals(data, "mybuilder:%s:testuser" % now)
+
+        # But not on the other slave
+        data = updateBuild("branch1", "My Builder", "mybuilder", "slave02",
+                "master01")
+        self.assertEquals(data, "")
+
+        # Or on the other master
+        data = updateBuild("branch1", "My Builder", "mybuilder", "slave01",
+                "master02")
+        self.assertEquals(data, "")
+        data = updateBuild("branch1", "My Builder", "mybuilder", "slave02",
+                "master02")
+        self.assertEquals(data, "")
+
+    def testSlaveClobber(self):
+        # Test that the client will do a clobber if we tell it to
+        now = int(time.time())
+
+        makeBuildDir('mybuilder', now)
+        setClobber('branch1', 'mybuilder', 'slave01', 'master01', now+1)
+
+        data = runClobberer('branch1', 'My Builder', 'mybuilder', 'slave01',
+                'master01')
+        self.assert_('mybuilder:Server is forcing a clobber' in data, data)
+
+    def testSlaveNoClobber(self):
+        # Test that the client won't clobber if the server's clobber date is
+        # too old
+        now = int(time.time())
+
+        makeBuildDir('mybuilder', now+1)
+        setClobber('branch1', 'mybuilder', 'slave01', 'master01', now)
+
+        data = runClobberer('branch1', 'My Builder', 'mybuilder', 'slave01',
+                'master01')
+        self.assert_('mybuilder:Server is forcing a clobber' not in data, data)
+
+    def testSlaveClobberOther(self):
+        # Test that other builders than the one we're running will get
+        # clobbered
+        now = int(time.time())
+
+        makeBuildDir('mybuilder', now)
+        makeBuildDir('linux_build', now)
+        updateBuild('branch1', 'linux_build', 'linux_build', 'slave01',
+                'master01')
+
+        setClobber('branch1', 'mybuilder', 'slave01', 'master01', now-1)
+        setClobber('branch1', 'linux_build', None, 'master01', now+1)
+
+        data = runClobberer('branch1', 'My Builder', 'mybuilder', 'slave01',
+                'master01')
+        self.assert_('mybuilder:Server is forcing a clobber' not in data, data)
+        self.assert_('linux_build:Server is forcing a clobber' in data, data)
+
+    def testSlavePeriodicClobber(self):
+        # Test that periodic clobbers happen if it's been longer than the
+        # specified time since our last clobber
+        now = int(time.time())
+
+        makeBuildDir('mybuilder', now-3601)
+
+        data = runClobberer('branch1', 'My Builder', 'mybuilder', 'slave01',
+                'master01', 1)
+        self.assert_('mybuilder:More than' in data, data)
+
+    def testSlaveNoPeriodicClobber(self):
+        # Test that periodic clobbers don't happen if it hasn't been longer
+        # than the specified time since our last clobber
+        now = int(time.time())
+
+        makeBuildDir('mybuilder', now-3599)
+
+        data = runClobberer('branch1', 'My Builder', 'mybuilder', 'slave01',
+                'master01', 1)
+        self.assert_('mybuilder:More than' not in data, data)
+
+    def testSlaveNoPeriodicClobberOther(self):
+        # Test that periodic clobbers don't happen on builders other than the
+        # 'current' builder
+        now = int(time.time())
+
+        makeBuildDir('mybuilder', now-3599)
+        makeBuildDir('mybuilder2', now-3601)
+
+        data = runClobberer('branch1', 'My Builder', 'mybuilder', 'slave01',
+                'master01', 1)
+        self.assert_('mybuilder:More than' not in data, data)
+        self.assert_('mybuilder2:More than' not in data, data)
+
+        data = runClobberer('branch1', 'My Builder', 'mybuilder2', 'slave01',
+                'master01', 1)
+        self.assert_('mybuilder2:More than' in data, data)
+
+    def testSlaveClobberRelease(self):
+        # Test that clobbers on release builders work
+        now = int(time.time())
+        makeBuildDir('linux_build', now-10)
+        updateBuild('branch1', 'linux_build', 'linux_build', 'slave01',
+                'master01')
+        time.sleep(1)
+        updateBuild('branch2', 'linux_build', 'linux_build', 'slave01',
+                'master01')
+        time.sleep(1)
+        now = int(time.time())
+        setClobber('branch2', 'linux_build', None, None, now)
+
+        data = runClobberer('branch2', 'Linux Release Build', 'linux_build',
+                'slave01', 'master01')
+        self.assert_('linux_build:Server is forcing' in data, data)
+
+    def testSlaveClobberReleaseOtherBranch(self):
+        # Test that clobbers on release builders work
+        now = int(time.time())
+        makeBuildDir('linux_build', now-10)
+        updateBuild('branch1', 'linux_build', 'linux_build', 'slave01',
+                'master01')
+        time.sleep(1)
+        updateBuild('branch2', 'linux_build', 'linux_build', 'slave01',
+                'master01')
+        time.sleep(1)
+        setClobber('branch2', 'linux_build', None, None, now)
+
+        # Even though we're running a different branch for _this_ run, our last
+        # run was on branch2, so it should be clobbered
+        data = runClobberer('branch1', 'Linux Release Build', 'linux_build',
+                'slave01', 'master01')
+        self.assert_('linux_build:Server is forcing' in data, data)
+
+    def testSlaveClobberReleaseNotOtherBranch(self):
+        # Test that clobbers on release builders don't clobber builds from
+        # other branches
+        now = int(time.time())
+        makeBuildDir('linux_build', now-10)
+        updateBuild('branch2', 'linux_build', 'linux_build', 'slave01',
+                'master01')
+        time.sleep(1)
+        updateBuild('branch1', 'linux_build', 'linux_build', 'slave01',
+                'master01')
+        time.sleep(1)
+        now = int(time.time())
+        setClobber('branch2', 'linux_build', None, None, now)
+
+        data = runClobberer('branch1', 'Linux Release Build', 'linux_build',
+                'slave01', 'master01')
+        self.assert_('linux_build:Server is forcing' not in data, data)
+
+    def testSlaveClobberReleaseOtherBranchOtherBuilder(self):
+        # Test that clobbers on release builders don't clobber builds from
+        # other branches when run from another builder
+        now = int(time.time())
+        makeBuildDir('linux_build', now-10)
+        updateBuild('branch1', 'linux_build', 'linux_build', 'slave01',
+                'master01')
+        time.sleep(1)
+        updateBuild('branch2', 'linux_build', 'linux_build', 'slave01',
+                'master01')
+        time.sleep(1)
+        now = int(time.time())
+        setClobber('branch1', 'linux_build', None, None, now)
+
+        data = runClobberer('branch1', 'My Builder', 'mybuilder', 'slave01',
+                'master01')
+        self.assert_('linux_build:Server is forcing' not in data, data)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
--- a/release/signing/download-exclude.list
+++ b/release/signing/download-exclude.list
@@ -1,9 +1,10 @@
 - *.zip
 - *.partial.mar
 - *.asc
+- *.tests.tar.bz2
 - /contrib/
 - /contrib-localized/
 # Skip the root update directory
 - /update/
 # Skip previously signed windows builds
 - /win32/
--- a/release/signing/signdebs.mk
+++ b/release/signing/signdebs.mk
@@ -1,17 +1,18 @@
 RELEASE			?=
 BRANCH_NICK		?= $(error BRANCH_NICK must be defined)
 LOCALE			?= $(error LOCALE must be defined)
 SBOX_PATH		= /scratchbox/moz_scratchbox
 RSYNC_ARGS		?= --delete --progress --partial
 MAEMO_VERSION	?= chinook
 FENNEC_FILEURL	?= $(error FENNEC_FILEURL must be defined)
 XULRUNNER_VERSION	?=
-SBOX_WORKDIR	?= sign-debs/$(BRANCH_NICK)_$(LOCALE)
+SIGNDEBS_BASEDIR	?= sign-debs
+SBOX_WORKDIR	?= $(SIGNDEBS_BASEDIR)/$(BRANCH_NICK)_$(LOCALE)
 WORKDIR			?= /scratchbox/users/cltbld/home/cltbld/$(SBOX_WORKDIR)
 
 BASE_STAGE_PATH	?= /home/ftp/pub/mozilla.org/mobile/repos
 BASE_STAGE_URL	?= http://ftp.mozilla.org/pub/mozilla.org/mobile/repos
 STAGE_USERNAME	?= ffxbld
 STAGE_SERVER	?= stage.mozilla.org
 STAGE_PATH		?= $(BASE_STAGE_PATH)/$(BRANCH_NICK)_$(LOCALE)
 STAGE_URL       ?= $(BASE_STAGE_URL)/$(BRANCH_NICK)_$(LOCALE)
@@ -21,17 +22,17 @@ INSTALL_CONTENTS = "[install]\nrepo_deb_
 
 FENNEC_FILENAME	= $(notdir $(FENNEC_FILEURL))
 BASE_XULRUNNER_URL	?= $(dir $(FENNEC_FILEURL))
 FENNEC_FILEPATH	= $(WORKDIR)/dists/$(MAEMO_VERSION)/$(REPO_SECTION)/binary-armel/$(FENNEC_FILENAME)
 XULRUNNER_FILENAME	= xulrunner_$(XULRUNNER_VERSION)_armel.deb
 XULRUNNER_FILEURL	= $(BASE_XULRUNNER_URL)/$(XULRUNNER_FILENAME)
 XULRUNNER_FILEPATH	= $(WORKDIR)/dists/$(MAEMO_VERSION)/$(REPO_SECTION)/binary-armel/$(XULRUNNER_FILENAME)
 
-TARGETS = echo setup download-repository
+TARGETS = echo setup download-repository clean-install-file
 
 ifndef RELEASE
 REPO_SECTION	:= extras
 INSTALL_FILENAME	= $(BRANCH_NICK)_$(LOCALE)_nightly.install
 TARGETS += clean-repository
 else
 REPO_SECTION	:= release
 INSTALL_FILENAME	= $(BRANCH_NICK)_$(LOCALE).install
@@ -41,34 +42,40 @@ INSTALL_FILEPATH	= $(WORKDIR)/$(INSTALL_
 
 TARGETS += $(INSTALL_FILEPATH) download-fennec
 ifndef XULRUNNER_VERSION
 TARGETS += xulrunner-hack
 else
 TARGETS += download-xulrunner
 endif
 
-TARGETS += sign touch-repository upload
+TARGETS += sign upload
 
 all: $(TARGETS)
 
 setup:
 	mkdir -p $(WORKDIR)/dists/$(MAEMO_VERSION)/$(REPO_SECTION)/binary-armel
 
 download-repository:
-	rsync -azv -e 'ssh -i $(SSH_KEY)' $(RSYNC_ARGS) $(STAGE_USERNAME)@$(STAGE_SERVER):$(STAGE_PATH)/dists/. $(WORKDIR)/dists/.
+	ssh -i $(SSH_KEY) $(STAGE_USERNAME)@$(STAGE_SERVER) "test -d $(STAGE_PATH)/dists" && \
+	  rsync -azv -e 'ssh -i $(SSH_KEY)' $(RSYNC_ARGS) $(STAGE_USERNAME)@$(STAGE_SERVER):$(STAGE_PATH)/dists/. $(WORKDIR)/dists/. || \
+	  echo "No repository to download."
+
+clean-install-file:
+	rm -f $(WORKDIR)/*.install
 
 clean-repository:
 	find $(WORKDIR)/dists/$(MAEMO_VERSION)/$(REPO_SECTION)/binary-armel/. -name \*.deb -exec rm {} \;
 
 download-fennec:
 	rm -rf $(FENNEC_FILEPATH)
 	wget -O $(FENNEC_FILEPATH) $(FENNEC_FILEURL)
 
 xulrunner-hack:
+	if [ -e tmp.deb ] ; then rm -rf tmp.deb; fi
 	mkdir tmp.deb
 	(cd tmp.deb && ar xv $(FENNEC_FILEPATH) && tar zxvf control.tar.gz)
 	make -f signdebs.mk download-xulrunner XULRUNNER_VERSION=`grep xulrunner tmp.deb/control | sed -e 's/.*xulrunner (>= \([^)]*\)).*/\1/'`
 	rm -rf tmp.deb
 
 download-xulrunner:
 	rm -f $(XULRUNNER_FILEPATH)
 	wget -O $(XULRUNNER_FILEPATH) $(XULRUNNER_FILEURL)
@@ -89,21 +96,19 @@ echo:
 	@echo XULRUNNER_FILENAME: $(XULRUNNER_FILENAME)
 	@echo XULRUNNER_FILEPATH: $(XULRUNNER_FILEPATH)
 	@echo INSTALL_FILENAME: $(INSTALL_FILENAME)
 
 %.install:
 	@echo -e $(INSTALL_CONTENTS) > "$@"
 
 sign:
-	$(SBOX_PATH) -p -d $(SBOX_WORKDIR) dpkg-scanpackages dists/$(MAEMO_VERSION)/$(REPO_SECTION)/binary-armel/ /dev/null | gzip -9c > $(WORKDIR)/dists/$(MAEMO_VERSION)/$(REPO_SECTION)/binary-armel/Packages.gz
+	$(SBOX_PATH) -p -d $(SBOX_WORKDIR) apt-ftparchive packages dists/$(MAEMO_VERSION)/$(REPO_SECTION)/binary-armel | gzip -9c > $(WORKDIR)/dists/$(MAEMO_VERSION)/$(REPO_SECTION)/binary-armel/Packages.gz
 	for i in dists/$(MAEMO_VERSION)/$(REPO_SECTION)/binary-armel dists/$(MAEMO_VERSION)/$(REPO_SECTION) dists/$(MAEMO_VERSION); do \
 	  rm -f $(WORKDIR)/$${i}/Release.gpg; \
 	  $(SBOX_PATH) -p -d $(SBOX_WORKDIR)/$${i} apt-ftparchive release . > $(WORKDIR)/$${i}/Release; \
 	  gpg -abs -o $(WORKDIR)/$${i}/Release.gpg $(WORKDIR)/$${i}/Release; \
 	done
 
-touch-repository:
-	@touch $(WORKDIR)
-
 upload:
+	ssh -i $(SSH_KEY) $(STAGE_USERNAME)@$(STAGE_SERVER) "mkdir -p $(STAGE_PATH)"
 	rsync -e "ssh -i $(SSH_KEY)" -azv $(RSYNC_ARGS) $(WORKDIR)/dists $(WORKDIR)/$(INSTALL_FILENAME) \
 	  $(STAGE_USERNAME)@$(STAGE_SERVER):$(STAGE_PATH)/.
--- a/release/updates/moz19-firefox-linux-major.cfg
+++ b/release/updates/moz19-firefox-linux-major.cfg
@@ -1,2 +1,2 @@
-# 3.0.16 linux
-release="3.0.16" product="Firefox" platform="Linux_x86-gcc3" build_id="2009120206" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/nightly/3.0.16-candidates/build3/firefox-3.0.16.%locale%.linux-i686.tar.bz2" to="/firefox/nightly/3.5.6-candidates/build3/linux-i686/%locale%/firefox-3.5.6.tar.bz2"
+# 3.0.17 linux
+release="3.0.17" product="Firefox" platform="Linux_x86-gcc3" build_id="2009122115" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/nightly/3.0.17-candidates/build1/firefox-3.0.17.%locale%.linux-i686.tar.bz2" to="/firefox/nightly/3.5.7-candidates/build1/linux-i686/%locale%/firefox-3.5.7.tar.bz2"
--- a/release/updates/moz19-firefox-linux.cfg
+++ b/release/updates/moz19-firefox-linux.cfg
@@ -1,10 +1,12 @@
+# 3.0.16 linux
+release="3.0.16" product="Firefox" platform="Linux_x86-gcc3" build_id="2009120206" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.0.16-real/linux-i686/%locale%/firefox-3.0.16.tar.bz2" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.0.17-candidates/build1/firefox-3.0.17.%locale%.linux-i686.tar.bz2"
 # 3.0.15 linux
-release="3.0.15" product="Firefox" platform="Linux_x86-gcc3" build_id="2009101600" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.0.15/linux-i686/%locale%/firefox-3.0.15.tar.bz2" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.0.16-candidates/build3/firefox-3.0.16.%locale%.linux-i686.tar.bz2"
+release="3.0.15" product="Firefox" platform="Linux_x86-gcc3" build_id="2009101600" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.14 linux
 release="3.0.14" product="Firefox" platform="Linux_x86-gcc3" build_id="2009082707" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.13 linux
 release="3.0.13" product="Firefox" platform="Linux_x86-gcc3" build_id="2009073021" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.12 linux
 release="3.0.12" product="Firefox" platform="Linux_x86-gcc3" build_id="2009070610" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.11 linux
 release="3.0.11" product="Firefox" platform="Linux_x86-gcc3" build_id="2009060214" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
--- a/release/updates/moz19-firefox-mac-major.cfg
+++ b/release/updates/moz19-firefox-mac-major.cfg
@@ -1,2 +1,2 @@
-# 3.0.16 mac, (no gu-IN for 3.0.x on mac)
-release="3.0.16" product="Firefox" platform="Darwin_Universal-gcc3" build_id="2009120206" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl he hi-IN hu id is it ja-JP-mac ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/nightly/3.0.16-candidates/build3/firefox-3.0.16.%locale%.mac.dmg" to="/firefox/nightly/3.5.6-candidates/build3/mac/%locale%/Firefox 3.5.6.dmg"
+# 3.0.17 mac, (no gu-IN for 3.0.x on mac)
+release="3.0.17" product="Firefox" platform="Darwin_Universal-gcc3" build_id="2009122115" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl he hi-IN hu id is it ja-JP-mac ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/nightly/3.0.17-candidates/build1/firefox-3.0.17.%locale%.mac.dmg" to="/firefox/nightly/3.5.7-candidates/build1/mac/%locale%/Firefox 3.5.7.dmg"
--- a/release/updates/moz19-firefox-mac.cfg
+++ b/release/updates/moz19-firefox-mac.cfg
@@ -1,10 +1,12 @@
+# 3.0.16 macosx
+release="3.0.16" product="Firefox" platform="Darwin_Universal-gcc3" build_id="2009120206" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl he hi-IN hu id is it ja-JP-mac ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.0.16-real/mac/%locale%/Firefox 3.0.16.dmg" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.0.17-candidates/build1/firefox-3.0.17.%locale%.mac.dmg"
 # 3.0.15 macosx
-release="3.0.15" product="Firefox" platform="Darwin_Universal-gcc3" build_id="2009101600" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl he hi-IN hu id is it ja-JP-mac ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.0.15/mac/%locale%/Firefox 3.0.15.dmg" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.0.16-candidates/build3/firefox-3.0.16.%locale%.mac.dmg"
+release="3.0.15" product="Firefox" platform="Darwin_Universal-gcc3" build_id="2009101600" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl he hi-IN hu id is it ja-JP-mac ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.14 macosx
 release="3.0.14" product="Firefox" platform="Darwin_Universal-gcc3" build_id="2009082706" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl he hi-IN hu id is it ja-JP-mac ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.13 macosx
 release="3.0.13" product="Firefox" platform="Darwin_Universal-gcc3" build_id="2009073021" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl he hi-IN hu id is it ja-JP-mac ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.12 macosx
 release="3.0.12" product="Firefox" platform="Darwin_Universal-gcc3" build_id="2009070609" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl he hi-IN hu id is it ja-JP-mac ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.11 macosx
 release="3.0.11" product="Firefox" platform="Darwin_Universal-gcc3" build_id="2009060214" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl he hi-IN hu id is it ja-JP-mac ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
--- a/release/updates/moz19-firefox-win32-major.cfg
+++ b/release/updates/moz19-firefox-win32-major.cfg
@@ -1,2 +1,2 @@
-# 3.0.16 win32
-release="3.0.16" product="Firefox" platform="WINNT_x86-msvc" build_id="2009120208" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/nightly/3.0.16-candidates/build3/firefox-3.0.16.%locale%.win32.installer.exe" to="/firefox/nightly/3.5.6-candidates/build3/win32/%locale%/Firefox Setup 3.5.6.exe"
+# 3.0.17 win32
+release="3.0.17" product="Firefox" platform="WINNT_x86-msvc" build_id="2009122116" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/nightly/3.0.17-candidates/build1/firefox-3.0.17.%locale%.win32.installer.exe" to="/firefox/nightly/3.5.7-candidates/build1/win32/%locale%/Firefox Setup 3.5.7.exe"
--- a/release/updates/moz19-firefox-win32.cfg
+++ b/release/updates/moz19-firefox-win32.cfg
@@ -1,10 +1,12 @@
+# 3.0.16 win32
+release="3.0.16" product="Firefox" platform="WINNT_x86-msvc" build_id="2009120208" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.0.16-real/win32/%locale%/Firefox Setup 3.0.16.exe" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.0.17-candidates/build1/firefox-3.0.17.%locale%.win32.installer.exe"
 # 3.0.15 win32
-release="3.0.15" product="Firefox" platform="WINNT_x86-msvc" build_id="2009101601" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.0.15/win32/%locale%/Firefox Setup 3.0.15.exe" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.0.16-candidates/build3/firefox-3.0.16.%locale%.win32.installer.exe"
+release="3.0.15" product="Firefox" platform="WINNT_x86-msvc" build_id="2009101601" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.14 win32
 release="3.0.14" product="Firefox" platform="WINNT_x86-msvc" build_id="2009082707" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.13 win32
 release="3.0.13" product="Firefox" platform="WINNT_x86-msvc" build_id="2009073022" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.12 win32
 release="3.0.12" product="Firefox" platform="WINNT_x86-msvc" build_id="2009070611" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
 # 3.0.11 win32
 release="3.0.11" product="Firefox" platform="WINNT_x86-msvc" build_id="2009060215" locales="af ar be bg bn-IN ca cs cy da de el en-GB en-US eo es-AR es-ES et eu fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja ka kn ko ku lt lv mk mn mr nb-NO nl nn-NO oc pa-IN pl pt-BR pt-PT ro ru si sk sl sq sr sv-SE te th tr uk zh-CN zh-TW" channel="betatest" 
--- a/release/updates/moz19-thunderbird-linux.cfg
+++ b/release/updates/moz19-thunderbird-linux.cfg
@@ -1,10 +1,12 @@
+# 3.0rc2 linux
+release="3.0" product="Thunderbird" platform="Linux_x86-gcc3" build_id="20091130195224" locales="af ar be bg bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sr sv-SE ta-LK tr uk vi zh-CN zh-TW" channel="betatest" from="/thunderbird/releases/3.0rc2/linux-i686/%locale%/thunderbird-3.0rc2.tar.bz2" aus_server="https://aus2.mozillamessaging.com" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/thunderbird/nightly/3.0rc3-candidates/build1/linux-i686/%locale%/thunderbird-3.0rc3.tar.bz2"
 # 3.0rc1 linux
-release="3.0" product="Thunderbird" platform="Linux_x86-gcc3" build_id="20091121181041" locales="af ar be bg bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sr sv-SE ta-LK tr uk vi zh-CN zh-TW" channel="betatest" from="/thunderbird/releases/3.0rc1/linux-i686/%locale%/thunderbird-3.0rc1.tar.bz2" aus_server="https://aus2.mozillamessaging.com" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/thunderbird/nightly/3.0rc2-candidates/build1/linux-i686/%locale%/thunderbird-3.0rc2.tar.bz2"
+release="3.0" product="Thunderbird" platform="Linux_x86-gcc3" build_id="20091121181041" locales="af ar be bg bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sr sv-SE ta-LK tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.0b4 linux
 release="3.0b4" product="Thunderbird" platform="Linux_x86-gcc3" build_id="20090915180501" locales="af ar be bg bn-BD ca cs de el en-US es-AR es-ES et eu fi fr fy-NL ga-IE he hu id is it ja ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sr sv-SE ta-LK tr uk zh-TW" channel="betatest" 
 # 3.0b3 linux
 release="3.0b3" product="Thunderbird" platform="Linux_x86-gcc3" build_id="20090715134828" locales="af ar be bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl hu id is it ja ko lt nb-NO nl nn-NO pa-IN pl pt-BR ro ru si sk sq sv-SE ta-LK tr uk vi zh-CN" channel="betatest" 
 # 3.0b2 Linux
 release="3.0b2" product="Thunderbird" platform="Linux_x86-gcc3" build_id="20090223124157" locales="en-US af ar be bg ca cs de el es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sr sv-SE ta-LK uk vi zh-CN" channel="betatest" 
 release="3.0b1" product="Thunderbird" platform="Linux_x86-gcc3" build_id="20081204114258" locales="en-US af ar be cs de en-GB es-AR es-ES et eu fr fy-NL ga-IE he hu id it ja ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sv-SE uk zh-CN zh-TW" channel="betatest"
 release="3.0a3" product="Thunderbird" platform="Linux_x86-gcc3" build_id="20081006094447" locales="en-US be ca cs de es-AR es-ES fr fy-NL ga-IE hu id it ja lt nb-NO nl nn-NO pl pt-BR pt-PT ro ru si sk sv-SE zh-CN zh-TW" channel="betatest"
--- a/release/updates/moz19-thunderbird-mac.cfg
+++ b/release/updates/moz19-thunderbird-mac.cfg
@@ -1,10 +1,12 @@
+# 3.0rc2 macosx
+release="3.0" product="Thunderbird" platform="Darwin_Universal-gcc3" build_id="20091130225757" locales="af ar be bg bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja-JP-mac ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sr sv-SE ta-LK tr uk vi zh-CN zh-TW" channel="betatest" from="/thunderbird/releases/3.0rc2/mac/%locale%/Thunderbird 3.0 RC 2.dmg" aus_server="https://aus2.mozillamessaging.com" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/thunderbird/nightly/3.0rc3-candidates/build1/mac/%locale%/Thunderbird 3.0 RC 3.dmg"
 # 3.0rc1 macosx
-release="3.0" product="Thunderbird" platform="Darwin_Universal-gcc3" build_id="20091121212410" locales="af ar be bg bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja-JP-mac ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sr sv-SE ta-LK tr uk vi zh-CN zh-TW" channel="betatest" from="/thunderbird/releases/3.0rc1/mac/%locale%/Thunderbird 3.0 RC 1.dmg" aus_server="https://aus2.mozillamessaging.com" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/thunderbird/nightly/3.0rc2-candidates/build1/mac/%locale%/Thunderbird 3.0 RC 2.dmg"
+release="3.0" product="Thunderbird" platform="Darwin_Universal-gcc3" build_id="20091121212410" locales="af ar be bg bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja-JP-mac ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sr sv-SE ta-LK tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.0b4 macosx
 release="3.0b4" product="Thunderbird" platform="Darwin_Universal-gcc3" build_id="20090915182611" locales="af ar be bg bn-BD ca cs de el en-US es-AR es-ES et eu fi fr fy-NL ga-IE he hu id is it ja-JP-mac ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sr sv-SE ta-LK tr uk zh-TW" channel="betatest" 
 # 3.0b3 macosx
 release="3.0b3" product="Thunderbird" platform="Darwin_Universal-gcc3" build_id="20090715142648" locales="af ar be bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl hu id is it ja-JP-mac ko lt nb-NO nl nn-NO pa-IN pl pt-BR ro ru si sk sq sv-SE ta-LK tr uk vi zh-CN" channel="betatest" 
 # 3.0b2 macosx
 release="3.0b2" product="Thunderbird" platform="Darwin_Universal-gcc3" build_id="20090223121634" locales="en-US af ar be bg ca cs de el es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja-JP-mac ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sr sv-SE ta-LK uk vi zh-CN" channel="betatest" 
 release="3.0b1" product="Thunderbird" platform="Darwin_Universal-gcc3" build_id="20081204113938" locales="en-US af ar be cs de en-GB es-AR es-ES et eu fr fy-NL ga-IE he hu id it ja-JP-mac ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sv-SE uk zh-CN zh-TW" channel="betatest"
 release="3.0a3" product="Thunderbird" platform="Darwin_Universal-gcc3" build_id="20081006093807" locales="en-US be ca cs de es-AR es-ES fr fy-NL ga-IE hu id it ja-JP-mac lt nb-NO nl nn-NO pl pt-BR pt-PT ro ru si sk sv-SE zh-CN zh-TW" channel="betatest"
--- a/release/updates/moz19-thunderbird-win32.cfg
+++ b/release/updates/moz19-thunderbird-win32.cfg
@@ -1,10 +1,12 @@
+# 3.0rc2 win32
+release="3.0" product="Thunderbird" platform="WINNT_x86-msvc" build_id="20091130201643" locales="af ar be bg bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sr sv-SE ta-LK tr uk vi zh-CN zh-TW" channel="betatest" from="/thunderbird/releases/3.0rc2/win32/%locale%/Thunderbird Setup 3.0 RC 2.exe" aus_server="https://aus2.mozillamessaging.com" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/thunderbird/nightly/3.0rc3-candidates/build1/win32/%locale%/Thunderbird Setup 3.0 RC 3.exe"
 # 3.0rc1 win32
-release="3.0" product="Thunderbird" platform="WINNT_x86-msvc" build_id="20091121183158" locales="af ar be bg bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sr sv-SE ta-LK tr uk vi zh-CN zh-TW" channel="betatest" from="/thunderbird/releases/3.0rc1/win32/%locale%/Thunderbird Setup 3.0 RC 1.exe" aus_server="https://aus2.mozillamessaging.com" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/thunderbird/nightly/3.0rc2-candidates/build1/win32/%locale%/Thunderbird Setup 3.0 RC 2.exe"
+release="3.0" product="Thunderbird" platform="WINNT_x86-msvc" build_id="20091121183158" locales="af ar be bg bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sr sv-SE ta-LK tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.0b4 win32
 release="3.0b4" product="Thunderbird" platform="WINNT_x86-msvc" build_id="20090915181920" locales="af ar be bg bn-BD ca cs de el en-US es-AR es-ES et eu fi fr fy-NL ga-IE he hu id is it ja ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sr sv-SE ta-LK tr uk zh-TW" channel="betatest" 
 # 3.0b3 win32
 release="3.0b3" product="Thunderbird" platform="WINNT_x86-msvc" build_id="20090715140311" locales="af ar be bn-BD ca cs de el en-GB en-US es-AR es-ES et eu fi fr fy-NL ga-IE gl hu id is it ja ko lt nb-NO nl nn-NO pa-IN pl pt-BR ro ru si sk sq sv-SE ta-LK tr uk vi zh-CN" channel="betatest" 
 # 3.0b2 win32
 release="3.0b2" product="Thunderbird" platform="WINNT_x86-msvc" build_id="20090223175111" locales="en-US af ar be bg ca cs de el es-AR es-ES et eu fi fr fy-NL ga-IE gl he hu id is it ja ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sr sv-SE ta-LK uk vi zh-CN" channel="betatest" 
 release="3.0b1" product="Thunderbird" platform="WINNT_x86-msvc" build_id="20081204115318" locales="en-US af ar be cs de en-GB es-AR es-ES et eu fr fy-NL ga-IE he hu id it ja ka ko lt nb-NO nl nn-NO pa-IN pl pt-BR pt-PT ro ru si sk sq sv-SE uk zh-CN zh-TW" channel="betatest"
 release="3.0a3" product="Thunderbird" platform="WINNT_x86-msvc" build_id="20081006095651" locales="en-US be ca cs de es-AR es-ES fr fy-NL ga-IE hu id it ja lt nb-NO nl nn-NO pl pt-BR pt-PT ro ru si sk sv-SE zh-CN zh-TW" channel="betatest"
--- a/release/updates/moz191-firefox-linux.cfg
+++ b/release/updates/moz191-firefox-linux.cfg
@@ -1,10 +1,12 @@
+# 3.5.6 linux
+release="3.5.6" product="Firefox" platform="Linux_x86-gcc3" build_id="20091201204959" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.5.6/linux-i686/%locale%/firefox-3.5.6.tar.bz2" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.5.7-candidates/build1/linux-i686/%locale%/firefox-3.5.7.tar.bz2"
 # 3.5.5 linux
-release="3.5.5" product="Firefox" platform="Linux_x86-gcc3" build_id="20091102141836" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.5.5/linux-i686/%locale%/firefox-3.5.5.tar.bz2" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.5.6-candidates/build3/linux-i686/%locale%/firefox-3.5.6.tar.bz2"
+release="3.5.5" product="Firefox" platform="Linux_x86-gcc3" build_id="20091102141836" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.4 linux
 release="3.5.4" product="Firefox" platform="Linux_x86-gcc3" build_id="20091016081727" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.3 linux
 release="3.5.3" product="Firefox" platform="Linux_x86-gcc3" build_id="20090824085743" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.2 linux
 release="3.5.2" product="Firefox" platform="Linux_x86-gcc3" build_id="20090729211829" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.1 linux
 release="3.5.1" product="Firefox" platform="Linux_x86-gcc3" build_id="20090715083816" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
--- a/release/updates/moz191-firefox-mac.cfg
+++ b/release/updates/moz191-firefox-mac.cfg
@@ -1,10 +1,12 @@
+# 3.5.6 macosx
+release="3.5.6" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20091201203240" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja-JP-mac ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.5.6/mac/%locale%/Firefox 3.5.6.dmg" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.5.7-candidates/build1/mac/%locale%/Firefox 3.5.7.dmg"
 # 3.5.5 macosx
-release="3.5.5" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20091102134505" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja-JP-mac ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.5.5/mac/%locale%/Firefox 3.5.5.dmg" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.5.6-candidates/build3/mac/%locale%/Firefox 3.5.6.dmg"
+release="3.5.5" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20091102134505" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja-JP-mac ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.4 macosx
 release="3.5.4" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20091016081620" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja-JP-mac ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.3 macosx
 release="3.5.3" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20090824085414" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja-JP-mac ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.2 macosx
 release="3.5.2" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20090729211433" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja-JP-mac ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.1 macosx
 release="3.5.1" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20090715083437" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja-JP-mac ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
--- a/release/updates/moz191-firefox-win32.cfg
+++ b/release/updates/moz191-firefox-win32.cfg
@@ -1,10 +1,12 @@
+# 3.5.6 win32
+release="3.5.6" product="Firefox" platform="WINNT_x86-msvc" build_id="20091201220228" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.5.6/win32/%locale%/Firefox Setup 3.5.6.exe" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.5.7-candidates/build1/win32/%locale%/Firefox Setup 3.5.7.exe"
 # 3.5.5 win32
-release="3.5.5" product="Firefox" platform="WINNT_x86-msvc" build_id="20091102152451" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.5.5/win32/%locale%/Firefox Setup 3.5.5.exe" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.5.6-candidates/build3/win32/%locale%/Firefox Setup 3.5.6.exe"
+release="3.5.5" product="Firefox" platform="WINNT_x86-msvc" build_id="20091102152451" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.4 win32
 release="3.5.4" product="Firefox" platform="WINNT_x86-msvc" build_id="20091016092926" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.3 win32
 release="3.5.3" product="Firefox" platform="WINNT_x86-msvc" build_id="20090824101458" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.2 win32
 release="3.5.2" product="Firefox" platform="WINNT_x86-msvc" build_id="20090729225027" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.5.1 win32
 release="3.5.1" product="Firefox" platform="WINNT_x86-msvc" build_id="20090715094852" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko ku lt lv mk ml mn mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
--- a/release/updates/moz191-seamonkey-linux.cfg
+++ b/release/updates/moz191-seamonkey-linux.cfg
@@ -1,8 +1,12 @@
+# 2.0.1 linux
+release="2.0.1" product="SeaMonkey" platform="Linux_x86-gcc3" build_id="20091206080429" locales="be ca cs de en-US es-AR es-ES fr gl hu it ka lt nb-NO nl pl pt-PT ru sk sv-SE tr" channel="betatest" from="/seamonkey/releases/2.0.1/linux-i686/%locale%/seamonkey-2.0.1.tar.bz2" aus_server="https://aus2-community.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/seamonkey/nightly/2.0.2-candidates/build1/linux-i686/%locale%/seamonkey-2.0.2.tar.bz2"
+# 2.0rc2 linux
+release="2.0" product="SeaMonkey" platform="Linux_x86-gcc3" build_id="20091017083424" locales="be ca cs de en-US es-AR es-ES fr gl hu ka lt nb-NO nl pl pt-PT ru sk sv-SE tr" channel="betatest" 
 # 2.0rc1 linux
-release="2.0" product="SeaMonkey" platform="Linux_x86-gcc3" build_id="20091007202919" locales="be ca cs de en-US es-AR es-ES fr gl hu lt nb-NO nl pl pt-PT ru sk tr" channel="betatest" from="/seamonkey/releases/2.0rc1/linux-i686/%locale%/seamonkey-2.0rc1.tar.bz2" aus_server="https://aus2-community.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/seamonkey/nightly/2.0rc2-candidates/build3/linux-i686/%locale%/seamonkey-2.0rc2.tar.bz2"
+release="2.0" product="SeaMonkey" platform="Linux_x86-gcc3" build_id="20091007202919" locales="be ca cs de en-US es-AR es-ES fr gl hu lt nb-NO nl pl pt-PT ru sk tr" channel="betatest" 
 # 2.0b2 linux
 release="2.0b2" product="SeaMonkey" platform="Linux_x86-gcc3" build_id="20090903111222" locales="be ca de en-US es-AR es-ES fr gl hu lt nb-NO nl pl pt-PT ru sk tr" channel="betatest" 
 # 2.0b1 linux
 release="2.0b1" product="SeaMonkey" platform="Linux_x86-gcc3" build_id="20090717070825" locales="be ca cs de en-US es-AR es-ES fr gl hu lt nb-NO pl pt-PT ru sk tr" channel="betatest" 
 # 2.0a3 linux
 release="2.0a3" product="SeaMonkey" platform="Linux_x86-gcc3" build_id="20090223134517" locales="en-US" channel="betatest" 
--- a/release/updates/moz191-seamonkey-mac.cfg
+++ b/release/updates/moz191-seamonkey-mac.cfg
@@ -1,8 +1,12 @@
+# 2.0.1 macosx
+release="2.0.1" product="SeaMonkey" platform="Darwin_Universal-gcc3" build_id="20091206081659" locales="be ca cs de en-US es-AR es-ES fr gl hu it ka lt nb-NO nl pl pt-PT ru sk sv-SE tr" channel="betatest" from="/seamonkey/releases/2.0.1/mac/%locale%/SeaMonkey 2.0.1.dmg" aus_server="https://aus2-community.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/seamonkey/nightly/2.0.2-candidates/build1/mac/%locale%/SeaMonkey 2.0.2.dmg"
+# 2.0rc2 macosx
+release="2.0" product="SeaMonkey" platform="Darwin_Universal-gcc3" build_id="20091017101410" locales="be ca cs de en-US es-AR es-ES fr gl hu ka lt nb-NO nl pl pt-PT ru sk sv-SE tr" channel="betatest" 
 # 2.0rc1 macosx
-release="2.0" product="SeaMonkey" platform="Darwin_Universal-gcc3" build_id="20091007203500" locales="be ca cs de en-US es-AR es-ES fr gl hu lt nb-NO nl pl pt-PT ru sk tr" channel="betatest" from="/seamonkey/releases/2.0rc1/mac/%locale%/SeaMonkey 2.0 RC 1.dmg" aus_server="https://aus2-community.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/seamonkey/nightly/2.0rc2-candidates/build3/mac/%locale%/SeaMonkey 2.0 RC 2.dmg"
+release="2.0" product="SeaMonkey" platform="Darwin_Universal-gcc3" build_id="20091007203500" locales="be ca cs de en-US es-AR es-ES fr gl hu lt nb-NO nl pl pt-PT ru sk tr" channel="betatest" 
 # 2.0b2 macosx
 release="2.0b2" product="SeaMonkey" platform="Darwin_Universal-gcc3" build_id="20090903171148" locales="be ca de en-US es-AR es-ES fr gl hu lt nb-NO nl pl pt-PT ru sk tr" channel="betatest" 
 # 2.0b1 macosx
 release="2.0b1" product="SeaMonkey" platform="Darwin_Universal-gcc3" build_id="20090718072636" locales="be ca cs de en-US es-AR es-ES fr gl hu lt nb-NO pl pt-PT ru sk tr" channel="betatest" 
 # 2.0a3 macosx
 release="2.0a3" product="SeaMonkey" platform="Darwin_Universal-gcc3" build_id="20090223140441" locales="en-US" channel="betatest" 
--- a/release/updates/moz191-seamonkey-win32.cfg
+++ b/release/updates/moz191-seamonkey-win32.cfg
@@ -1,8 +1,12 @@
+# 2.0.1 win32
+release="2.0.1" product="SeaMonkey" platform="WINNT_x86-msvc" build_id="20091206075935" locales="be ca cs de en-US es-AR es-ES fr gl hu it ka lt nb-NO nl pl pt-PT ru sk sv-SE tr" channel="betatest" from="/seamonkey/releases/2.0.1/win32/%locale%/SeaMonkey Setup 2.0.1.exe" aus_server="https://aus2-community.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/seamonkey/nightly/2.0.2-candidates/build1/win32/%locale%/SeaMonkey Setup 2.0.2.exe"
+# 2.0rc2 win32
+release="2.0" product="SeaMonkey" platform="WINNT_x86-msvc" build_id="20091017081335" locales="be ca cs de en-US es-AR es-ES fr gl hu ka lt nb-NO nl pl pt-PT ru sk sv-SE tr" channel="betatest" 
 # 2.0rc1 win32
-release="2.0" product="SeaMonkey" platform="WINNT_x86-msvc" build_id="20091007205255" locales="be ca cs de en-US es-AR es-ES fr gl hu lt nb-NO nl pl pt-PT ru sk tr" channel="betatest" from="/seamonkey/releases/2.0rc1/win32/%locale%/SeaMonkey Setup 2.0 RC 1.exe" aus_server="https://aus2-community.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/seamonkey/nightly/2.0rc2-candidates/build3/win32/%locale%/SeaMonkey Setup 2.0 RC 2.exe"
+release="2.0" product="SeaMonkey" platform="WINNT_x86-msvc" build_id="20091007205255" locales="be ca cs de en-US es-AR es-ES fr gl hu lt nb-NO nl pl pt-PT ru sk tr" channel="betatest" 
 # 2.0b2 win32
 release="2.0b2" product="SeaMonkey" platform="WINNT_x86-msvc" build_id="20090903110303" locales="be ca de en-US es-AR es-ES fr gl hu lt nb-NO nl pl pt-PT ru sk tr" channel="betatest" 
 # 2.0b1 win32
 release="2.0b1" product="SeaMonkey" platform="WINNT_x86-msvc" build_id="20090717105808" locales="be ca cs de en-US es-AR es-ES fr gl hu lt nb-NO pl pt-PT ru sk tr" channel="betatest" 
 # 2.0a3 win32
 release="2.0a3" product="SeaMonkey" platform="WINNT_x86-msvc" build_id="20090223135443" locales="en-US" channel="betatest" 
--- a/release/updates/moz192-firefox-linux.cfg
+++ b/release/updates/moz192-firefox-linux.cfg
@@ -1,8 +1,12 @@
+# 3.6b5 linux
+release="3.6b5" product="Firefox" platform="Linux_x86-gcc3" build_id="20091204132459" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko lt lv mk ml mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.6b5/linux-i686/%locale%/firefox-3.6b5.tar.bz2" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.6rc1-candidates/build1/linux-i686/%locale%/firefox-3.6rc1.tar.bz2"
+# 3.6b4 linux
+release="3.6b4" product="Firefox" platform="Linux_x86-gcc3" build_id="20091124201751" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja kk kn ko lt lv mk ml mr nb-NO nl nn-NO or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.6b3 linux
-release="3.6b3" product="Firefox" platform="Linux_x86-gcc3" build_id="20091115172547" locales="ar be bn-BD ca cs cy de el en-GB en-US eo es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja kk kn ko lt lv mk ml mr nb-NO nl nn-NO or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sv-SE ta ta-LK te tr uk zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.6b3/linux-i686/%locale%/firefox-3.6b3.tar.bz2" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.6b4-candidates/build1/linux-i686/%locale%/firefox-3.6b4.tar.bz2"
+release="3.6b3" product="Firefox" platform="Linux_x86-gcc3" build_id="20091115172547" locales="ar be bn-BD ca cs cy de el en-GB en-US eo es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja kk kn ko lt lv mk ml mr nb-NO nl nn-NO or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sv-SE ta ta-LK te tr uk zh-CN zh-TW" channel="betatest" 
 # 3.6b2 linux
 release="3.6b2" product="Firefox" platform="Linux_x86-gcc3" build_id="20091108163911" locales="ar be bn-BD ca cs de el en-US es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl he hi-IN hu id is it ja lt lv mr nl or pa-IN pl pt-BR pt-PT rm ro ru sk sq sv-SE ta te tr uk zh-CN zh-TW" channel="betatest" 
 # 3.6b1 linux
 release="3.6b1" product="Firefox" platform="Linux_x86-gcc3" build_id="20091029152254" locales="af ar be bg bn-BD ca cs da de el en-US es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl he hu id is it ja ka kk ko lt lv mk nb-NO nl nn-NO pa-IN pl pt-BR pt-PT rm ro ru sk sl sq sv-SE te tr uk zh-CN zh-TW" channel="betatest" 
 # 3.6a1 linux
 release="3.6a1" product="Firefox" platform="Linux_x86-gcc3" build_id="20090806155851" locales="en-US" channel="betatest" 
--- a/release/updates/moz192-firefox-mac.cfg
+++ b/release/updates/moz192-firefox-mac.cfg
@@ -1,8 +1,12 @@
+# 3.6b5 macosx
+release="3.6b5" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20091204132509" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja-JP-mac ka kk kn ko lt lv mk ml mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.6b5/mac/%locale%/Firefox 3.6 Beta 5.dmg" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.6rc1-candidates/build1/mac/%locale%/Firefox 3.6 RC 1.dmg"
+# 3.6b4 macosx
+release="3.6b4" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20091124201530" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja-JP-mac kk kn ko lt lv mk ml mr nb-NO nl nn-NO or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.6b3 macosx
-release="3.6b3" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20091115172407" locales="ar be bn-BD ca cs cy de el en-GB en-US eo es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja-JP-mac kk kn ko lt lv mk ml mr nb-NO nl nn-NO or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sv-SE ta ta-LK te tr uk zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.6b3/mac/%locale%/Firefox 3.6 Beta 3.dmg" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.6b4-candidates/build1/mac/%locale%/Firefox 3.6 Beta 4.dmg"
+release="3.6b3" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20091115172407" locales="ar be bn-BD ca cs cy de el en-GB en-US eo es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja-JP-mac kk kn ko lt lv mk ml mr nb-NO nl nn-NO or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sv-SE ta ta-LK te tr uk zh-CN zh-TW" channel="betatest" 
 # 3.6b2 macosx
 release="3.6b2" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20091108163852" locales="ar be bn-BD ca cs de el en-US es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl he hi-IN hu id is it ja-JP-mac lt lv mr nl or pa-IN pl pt-BR pt-PT rm ro ru sk sq sv-SE ta te tr uk zh-CN zh-TW" channel="betatest" 
 # 3.6b1 macosx
 release="3.6b1" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20091029151354" locales="af ar be bg bn-BD ca cs da de el en-US es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl he hu id is it ja-JP-mac ka kk ko lt lv mk nb-NO nl nn-NO pa-IN pl pt-BR pt-PT rm ro ru sk sl sq sv-SE te tr uk zh-CN zh-TW" channel="betatest" 
 # 3.6a1 macosx
 release="3.6a1" product="Firefox" platform="Darwin_Universal-gcc3" build_id="20090806155510" locales="en-US" channel="betatest" 
--- a/release/updates/moz192-firefox-win32.cfg
+++ b/release/updates/moz192-firefox-win32.cfg
@@ -1,8 +1,12 @@
+# 3.6b5 win32
+release="3.6b5" product="Firefox" platform="WINNT_x86-msvc" build_id="20091204143806" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES es-MX et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hr hu id is it ja ka kk kn ko lt lv mk ml mr nb-NO nl nn-NO oc or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.6b5/win32/%locale%/Firefox Setup 3.6 Beta 5.exe" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.6rc1-candidates/build1/win32/%locale%/Firefox Setup 3.6 RC 1.exe"
+# 3.6b4 win32
+release="3.6b4" product="Firefox" platform="WINNT_x86-msvc" build_id="20091124213835" locales="af ar as be bg bn-BD bn-IN ca cs cy da de el en-GB en-US eo es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja kk kn ko lt lv mk ml mr nb-NO nl nn-NO or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sv-SE ta ta-LK te th tr uk vi zh-CN zh-TW" channel="betatest" 
 # 3.6b3 win32
-release="3.6b3" product="Firefox" platform="WINNT_x86-msvc" build_id="20091115182845" locales="ar be bn-BD ca cs cy de el en-GB en-US eo es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja kk kn ko lt lv mk ml mr nb-NO nl nn-NO or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sv-SE ta ta-LK te tr uk zh-CN zh-TW" channel="betatest" from="/firefox/releases/3.6b3/win32/%locale%/Firefox Setup 3.6 Beta 3.exe" aus_server="https://aus2.mozilla.org" ftp_server="stage-old.mozilla.org/pub/mozilla.org" to="/firefox/nightly/3.6b4-candidates/build1/win32/%locale%/Firefox Setup 3.6 Beta 4.exe"
+release="3.6b3" product="Firefox" platform="WINNT_x86-msvc" build_id="20091115182845" locales="ar be bn-BD ca cs cy de el en-GB en-US eo es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hu id is it ja kk kn ko lt lv mk ml mr nb-NO nl nn-NO or pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sv-SE ta ta-LK te tr uk zh-CN zh-TW" channel="betatest" 
 # 3.6b2 win32
 release="3.6b2" product="Firefox" platform="WINNT_x86-msvc" build_id="20091108181924" locales="ar be bn-BD ca cs de el en-US es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl he hi-IN hu id is it ja lt lv mr nl or pa-IN pl pt-BR pt-PT rm ro ru sk sq sv-SE ta te tr uk zh-CN zh-TW" channel="betatest" 
 # 3.6b1 win32
 release="3.6b1" product="Firefox" platform="WINNT_x86-msvc" build_id="20091029171059" locales="af ar be bg bn-BD ca cs da de el en-US es-AR es-CL es-ES et eu fa fi fr fy-NL ga-IE gl he hu id is it ja ka kk ko lt lv mk nb-NO nl nn-NO pa-IN pl pt-BR pt-PT rm ro ru sk sl sq sv-SE te tr uk zh-CN zh-TW" channel="betatest" 
 # 3.6a1 win32
 release="3.6a1" product="Firefox" platform="WINNT_x86-msvc" build_id="20090806165642" locales="en-US" channel="betatest" 
--- a/stage/post_upload.py
+++ b/stage/post_upload.py
@@ -2,30 +2,30 @@
 
 # This script expects a directory as its first non-option argument,
 # followed by a list of filenames.
 
 import sys, os, os.path, shutil
 from optparse import OptionParser
 from time import mktime, strptime
 
-NIGHTLY_PATH = "/home/ftp/pub/%(product)s/nightly"
+NIGHTLY_PATH = "/home/ftp/pub/%(product)s/%(nightly_dir)s"
 TINDERBOX_BUILDS_PATH = "/home/ftp/pub/%(product)s/tinderbox-builds/%(tinderbox_builds_dir)s"
 # For staging
 #TINDERBOX_URL_PATH = "http://staging-stage.build.mozilla.org/pub/mozilla.org/%(product)s/tinderbox-builds/%(tinderbox_builds_dir)s"
 # For production
 TINDERBOX_URL_PATH = "http://stage.mozilla.org/pub/mozilla.org/%(product)s/tinderbox-builds/%(tinderbox_builds_dir)s"
 LATEST_DIR = "latest-%(branch)s"
 LONG_DATED_DIR = "%(year)s/%(month)s/%(year)s-%(month)s-%(day)s-%(hour)s-%(branch)s"
 SHORT_DATED_DIR = "%(year)s-%(month)s-%(day)s-%(hour)s-%(branch)s"
 CANDIDATES_DIR = "%(version)s-candidates/build%(buildnumber)s"
 # For staging
-#CANDIDATES_URL_PATH = "http://staging-stage.build.mozilla.org/pub/mozilla.org/%(product)s/nightly/%(version)s-candidates/build%(buildnumber)s"
+#CANDIDATES_URL_PATH = "http://staging-stage.build.mozilla.org/pub/mozilla.org/%(product)s/%(nightly_dir)s/%(version)s-candidates/build%(buildnumber)s"
 # For production
-CANDIDATES_URL_PATH = "http://stage.mozilla.org/pub/mozilla.org/%(product)s/nightly/%(version)s-candidates/build%(buildnumber)s"
+CANDIDATES_URL_PATH = "http://stage.mozilla.org/pub/mozilla.org/%(product)s/%(nightly_dir)s/%(version)s-candidates/build%(buildnumber)s"
 
 def CopyFileToDir(original_file, source_dir, dest_dir, preserve_dirs=False):
     if not original_file.startswith(source_dir):
         print "%s is not in %s!" % (original_file, source_dir)
         return
     relative_path = os.path.basename(original_file)
     if preserve_dirs:
         # Add any dirs below source_dir to the final destination
@@ -119,16 +119,17 @@ def ReleaseToTinderboxBuilds(options, up
 def ReleaseToTinderboxBuildsOverwrite(options, upload_dir, files):
     ReleaseToTinderboxBuilds(options, upload_dir, files, dated=False)
 
 def ReleaseToCandidatesDir(options, upload_dir, files):
     candidatesDir = CANDIDATES_DIR % {'version': options.version,
                                       'buildnumber': options.build_number}
     candidatesPath = os.path.join(NIGHTLY_PATH, candidatesDir)
     candidatesUrl = CANDIDATES_URL_PATH % {
+            'nightly_dir': options.nightly_dir,
             'version': options.version,
             'buildnumber': options.build_number,
             'product': options.product,
             }
 
     for f in files:
         realCandidatesPath = candidatesPath
         if 'win32' in f:
@@ -161,37 +162,40 @@ if __name__ == '__main__':
     
     parser = OptionParser(usage="usage: %prog [options] <directory> <files>")
     parser.add_option("-p", "--product",
                       action="store", dest="product",
                       help="Set product name to build paths properly.")
     parser.add_option("-v", "--version",
                       action="store", dest="version",
                       help="Set version number to build paths properly.")
+    parser.add_option("--nightly-dir", default="nightly",
+                      action="store", dest="nightly_dir",
+                      help="Set the base directory for nightlies (ie $product/$nightly_dir/), and the parent directory for release candidates (default 'nightly').")
     parser.add_option("-b", "--branch",
                       action="store", dest="branch",
                       help="Set branch name to build paths properly.")
     parser.add_option("-i", "--buildid",
                       action="store", dest="buildid",
                       help="Set buildid to build paths properly.")
     parser.add_option("-n", "--build-number",
                       action="store", dest="build_number",
                       help="Set buildid to build paths properly.")
     parser.add_option("--tinderbox-builds-dir",
                       action="store", dest="tinderbox_builds_dir",
                       help="Set tinderbox builds dir to build paths properly.")
     parser.add_option("-l", "--release-to-latest",
                       action="store_true", dest="release_to_latest",
-                      help="Copy files to $product/nightly/latest-$branch")
+                      help="Copy files to $product/$nightly_dir/latest-$branch")
     parser.add_option("-d", "--release-to-dated",
                       action="store_true", dest="release_to_dated",
-                      help="Copy files to $product/nightly/$datedir-$branch")
+                      help="Copy files to $product/$nightly_dir/$datedir-$branch")
     parser.add_option("-c", "--release-to-candidates-dir",
                       action="store_true", dest="release_to_candidates_dir",
-                      help="Copy files to $product/nightly/$version-candidates/build$build_number")
+                      help="Copy files to $product/$nightly_dir/$version-candidates/build$build_number")
     parser.add_option("-t", "--release-to-tinderbox-builds",
                       action="store_true", dest="release_to_tinderbox_builds",
                       help="Copy files to $product/tinderbox-builds/$tinderbox_builds_dir")
     parser.add_option("--release-to-tinderbox-dated-builds",
                       action="store_true", dest="release_to_dated_tinderbox_builds",
                       help="Copy files to $product/tinderbox-builds/$tinderbox_builds_dir/$timestamp")
     (options, args) = parser.parse_args()
     
@@ -239,17 +243,18 @@ if __name__ == '__main__':
             error = True
     if len(releaseTo) == 0:
         print "Error, you must pass a --release-to option!"
         error = True
     
     if error:
         sys.exit(1)
     
-    NIGHTLY_PATH = NIGHTLY_PATH % {'product': options.product}
+    NIGHTLY_PATH = NIGHTLY_PATH % {'product': options.product,
+                                   'nightly_dir': options.nightly_dir}
     upload_dir = os.path.abspath(args[0])
     files = args[1:]
     if not os.path.isdir(upload_dir):
         print "Error, %s is not a directory!" % upload_dir
         sys.exit(1)
     for f in files:
         f = os.path.abspath(f)
         if not os.path.isfile(f):