bug 379278: bootstrap should support trunk releases. r=preed,rhelmer patch=me
authorbhearsum@mozilla.com
Thu, 06 Dec 2007 07:31:31 -0800
changeset 8792 9b2a28cec34ecc507824b151c5dc94c5a48d2446
parent 8791 c2aae2285c653e8a2d0fdbd0c2604299aeb5ba5b
child 8793 e785a936a4915a6ee0a97612487df43f63b687ee
push idunknown
push userunknown
push dateunknown
reviewerspreed, rhelmer
bugs379278
milestone1.9b2pre
bug 379278: bootstrap should support trunk releases. r=preed,rhelmer patch=me
tools/release/Bootstrap/Config.pm
tools/release/Bootstrap/Step.pm
tools/release/Bootstrap/Step/Build.pm
tools/release/Bootstrap/Step/PatcherConfig.pm
tools/release/Bootstrap/Step/Repack.pm
tools/release/Bootstrap/Step/Source.pm
tools/release/Bootstrap/Step/Stage.pm
tools/release/Bootstrap/Step/Tag.pm
tools/release/Bootstrap/Step/Tag/Bump.pm
tools/release/Bootstrap/Step/Tag/Talkback.pm
tools/release/Bootstrap/Step/Tag/l10n.pm
tools/release/Bootstrap/Step/TinderConfig.pm
tools/release/Bootstrap/Step/Updates.pm
tools/release/Bootstrap/Util.pm
tools/release/configs/fx-moz18-bootstrap.cfg
tools/release/configs/fx-moz18-staging-bootstrap.cfg
tools/release/configs/fx-moz180-bootstrap.cfg
tools/release/configs/tb-moz18-bootstrap.cfg
tools/release/configs/tb-moz180-bootstrap.cfg
--- a/tools/release/Bootstrap/Config.pm
+++ b/tools/release/Bootstrap/Config.pm
@@ -219,17 +219,17 @@ sub SystemInfo {
         return $hostname;
     } elsif ($var eq 'release') {
         return $release;
     } elsif ($var eq 'version') {
         return $version;
     } elsif ($var eq 'machine') {
         return $machine;
     } elsif ($var eq 'osname') {
-        if ($sysname =~ /cygwin/i) {
+        if ($sysname =~ /cygwin/i || $sysname =~ /mingw32/i) {
             return 'win32';
         } elsif ($sysname =~ /darwin/i) {
             return 'macosx';
         } elsif ($sysname =~ /linux/i) {
             return 'linux';
         } else {
             die("Unrecognized OS: $sysname");
         }
--- a/tools/release/Bootstrap/Step.pm
+++ b/tools/release/Bootstrap/Step.pm
@@ -246,9 +246,65 @@ sub GetBuildIDFromFTP() {
     if (! $buildID =~ /^\d+$/) {
         die("ASSERT: BumpPatcherConfig: $buildID is non-numerical");
     }
     chomp($buildID);
 
     return $buildID;
 }
 
+sub CvsCo {
+    my $this = shift;
+    my %args = @_;
+
+    # Required arguments
+    die "ASSERT: Bootstrap::Util::CvsCo(): null cvsroot" if
+     (!exists($args{'cvsroot'}));
+    my $cvsroot = $args{'cvsroot'};
+
+    die "ASSERT: Bootstrap::Util::CvsCo(): null modules" if
+     (!exists($args{'modules'}));
+    my $modules = $args{'modules'};
+
+    die "ASSERT: Bootstrap::Util::CvsCo(): bad modules data" if
+     (ref($modules) ne 'ARRAY');
+
+    # Optional arguments
+    my $logFile = $args{'logFile'};
+    my $tag = exists($args{'tag'}) ? $args{'tag'} : 0; 
+    my $date = exists($args{'date'}) ? $args{'date'} : 0;
+    my $checkoutDir = exists($args{'checkoutDir'}) ? $args{'checkoutDir'} : 0;
+    my $workDir = exists($args{'workDir'}) ? $args{'workDir'} : 0;
+    my $ignoreExitValue = exists($args{'ignoreExitValue'}) ?
+        $args{'ignoreExitValue'} : 0;
+    my $timeout = exists($args{'timeout'}) ? $args{'timeout'} :
+     $Bootstrap::Util::DEFAULT_SHELL_TIMEOUT;
+
+    my $config = new Bootstrap::Config();
+
+    my $useCvsCompression = 0;
+    if ($config->Exists(var => 'useCvsCompression')) {
+        $useCvsCompression = $config->Get(var => 'useCvsCompression');
+    }
+
+    my @cmdArgs;
+    push(@cmdArgs, '-z3') if ($useCvsCompression);
+    push(@cmdArgs, ('-d', $cvsroot));
+    push(@cmdArgs, 'co');
+    # Don't use a tag/branch if pulling from HEAD
+    push(@cmdArgs, ('-r', $tag)) if ($tag && $tag ne 'HEAD');
+    push(@cmdArgs, ('-D', $date)) if ($date);
+    push(@cmdArgs, ('-d', $checkoutDir)) if ($checkoutDir);
+    push(@cmdArgs, @{$modules});
+
+    my %cvsCoArgs = (cmd => 'cvs',
+                     cmdArgs => \@cmdArgs,
+                     dir => $workDir,
+                     timeout => $timeout,
+                     ignoreExitValue => $ignoreExitValue,
+    );
+    if ($logFile) {
+        $cvsCoArgs{'logFile'} = $logFile;
+    }
+
+    $this->Shell(%cvsCoArgs);
+}
 1;
--- a/tools/release/Bootstrap/Step/Build.pm
+++ b/tools/release/Bootstrap/Step/Build.pm
@@ -14,31 +14,31 @@ sub Execute {
     my $this = shift;
 
     my $config = new Bootstrap::Config();
     my $buildDir = $config->Get(sysvar => 'buildDir');
     my $productTag = $config->Get(var => 'productTag');
     my $rc = $config->Get(var => 'rc');
     my $buildPlatform = $config->Get(sysvar => 'buildPlatform');
     my $logDir = $config->Get(sysvar => 'logDir');
-    my $osname = $config->SystemInfo(var => 'osname');    
+    my $sysname = $config->SystemInfo(var => 'sysname');    
     my $rcTag = $productTag . '_RC' . $rc;
 
     my $lastBuilt = catfile($buildDir, $buildPlatform, 'last-built');
     if (! unlink($lastBuilt)) {
         $this->Log(msg => "Cannot unlink last-built file $lastBuilt: $!");
     } else {
         $this->Log(msg => "Unlinked $lastBuilt");
     }
 
     my $buildLog = catfile($logDir, 'build_' . $rcTag . '-build.log');
  
     # For Cygwin only, ensure that the system mount point is binmode
     # This forces CVS to use Unix-style linefeed EOL characters.
-    if ($osname eq 'win32') {
+    if ($sysname =~ /cygwin/i) {
         $this->Shell(
           cmd => 'mount',
           cmdArgs => ['-b', '-sc', '/cygdrive'],
           dir => $buildDir,
         );
     }
   
     $this->Shell(
--- a/tools/release/Bootstrap/Step/PatcherConfig.pm
+++ b/tools/release/Bootstrap/Step/PatcherConfig.pm
@@ -35,22 +35,21 @@ sub Execute {
 
     # Create patcher config area in the config bump area.
     if (not -d $configBumpDir) {
         MkdirWithPath(dir => $configBumpDir) 
           or die("Cannot mkdir $configBumpDir: $!");
     }
 
     # checkout config to bump
-    $this->Shell(
-      cmd => 'cvs',
-      cmdArgs => ['-d', $mofoCvsroot, 'co', '-d', 'patcher',  
-                    CvsCatfile('release', 'patcher', $patcherConfig)],
-      logFile => catfile($logDir, 'patcherconfig-checkout.log'),
-      dir => $configBumpDir,
+    $this->CvsCo(cvsroot => $mofoCvsroot,
+                 checkoutDir => 'patcher',
+                 modules => [CvsCatfile('release', 'patcher', $patcherConfig)],
+                 logFile => catfile($logDir, 'patcherconfig-checkout.log'),
+                 workDir => $configBumpDir
     );
 
     # Do all the work...
     $this->BumpPatcherConfig();
 
     # verify that BumpPatcherConfig() actually did something.
     $this->Log(msg=> 'Ignoring shell value here because cvs diff returns a ' .
      'non-zero value if a diff exists; this is an assertion that a diff does ' .
--- a/tools/release/Bootstrap/Step/Repack.pm
+++ b/tools/release/Bootstrap/Step/Repack.pm
@@ -13,28 +13,28 @@ sub Execute {
     my $this = shift;
 
     my $config = new Bootstrap::Config();
     my $l10n_buildDir = $config->Get(sysvar => 'l10n_buildDir');
     my $productTag = $config->Get(var => 'productTag');
     my $rc = $config->Get(var => 'rc');
     my $logDir = $config->Get(sysvar => 'logDir');
     my $l10n_buildPlatform = $config->Get(sysvar => 'l10n_buildPlatform');
-    my $osname = $config->SystemInfo(var => 'osname');    
+    my $sysname = $config->SystemInfo(var => 'sysname');
     my $rcTag = $productTag . '_RC' . $rc;
 
     my $buildLog = catfile($logDir, 'repack_' . $rcTag . '-build-l10n.log');
     my $lastBuilt = catfile($l10n_buildDir, $l10n_buildPlatform, 'last-built');
     unlink($lastBuilt) 
       or $this->Log(msg => "Cannot unlink last-built file $lastBuilt: $!");
     $this->Log(msg => "Unlinked $lastBuilt");
 
     # For Cygwin only, ensure that the system mount point is textmode
     # This forces CVS to use DOS-style carriage-return EOL characters.
-    if ($osname eq 'win32') {
+    if ($sysname =~ /cygwin/i) {
         $this->Shell(
           cmd => 'mount',
           cmdArgs => ['-t', '-sc', '/cygdrive'],
           dir => $buildDir,
         );
     }
 
     $this->Shell(
@@ -44,17 +44,17 @@ sub Execute {
                   catfile($l10n_buildDir, 'tinderbox-configs')],
       dir => $l10n_buildDir,
       logFile => $buildLog,
       timeout => 36000
     );
 
     # For Cygwin only, set the system mount point back to binmode
     # This forces CVS to use Unix-style linefeed EOL characters.
-    if ($osname eq 'win32') {
+    if ($sysname =~ /cygwin/i) {
         $this->Shell(
           cmd => 'mount',
           cmdArgs => ['-b', '-sc', '/cygdrive'],
           dir => $buildDir,
         );
     }
 }
 
@@ -67,47 +67,48 @@ sub Verify {
     my $rc = $config->Get(var => 'rc');
     my $oldRc = $config->Get(var => 'oldRc');
     my $logDir = $config->Get(sysvar => 'logDir');
     my $version = $config->Get(var => 'version');
     my $oldVersion = $config->Get(var => 'oldVersion');
     my $mozillaCvsroot = $config->Get(var => 'mozillaCvsroot');
     my $verifyDir = $config->Get(var => 'verifyDir');
     my $stagingServer = $config->Get(var => 'stagingServer');
-
+    my $useTarGz = $config->Exists(var => 'useTarGz') ?
+     $config->Get(var => 'useTarGz') : 0;
     my $rcTag = $productTag.'_RC'.$rc;
 
+    my $linuxExtension = ($useTarGz) ? '.gz' : '.bz2';
     # l10n metadiff test
 
     my $verifyDirVersion = catfile($verifyDir, $product . '-' . $version);
 
     MkdirWithPath(dir => $verifyDirVersion)
       or die("Cannot mkdir $verifyDirVersion: $!");
 
     # check out l10n verification scripts
     foreach my $dir ('common', 'l10n') {
-        $this->Shell(
-          cmd => 'cvs',
-          cmdArgs => ['-d', $mozillaCvsroot, 
-                      'co', '-d', $dir, 
-                      CvsCatfile('mozilla', 'testing', 'release', $dir)],
-          dir => $verifyDirVersion,
-          logFile => catfile($logDir, 
-                               'repack_checkout-l10n_verification.log'),
+        $this->CvsCo(cvsroot => $mozillaCvsroot,
+                     checkoutDir => $dir,
+                     modules => [CvsCatfile('mozilla', 'testing', 'release',
+                                            $dir)],
+                     workDir => $verifyDirVersion,
+                     logFile => catfile($logDir,
+                                 'repack_checkout-l10n_verification.log')
         );
     }
 
     # Download current release
     $this->Shell(
       cmd => 'rsync',
       cmdArgs => ['-Lav', 
                   '-e', 'ssh', 
                   '--include=*.dmg',
                   '--include=*.exe',
-                  '--include=*.tar.gz',
+                  '--include=*.tar'.$linuxExtension,
                   '--exclude=*',
                   $stagingServer . ':/home/ftp/pub/' . $product
                   . '/nightly/' . $version . '-candidates/rc' . $rc . '/*',
                   $product . '-' . $version . '-rc' . $rc . '/',
                  ],
       dir => catfile($verifyDirVersion, 'l10n'),
       logFile => 
         catfile($logDir, 'repack_verify-download_' . $version . '.log'),
@@ -116,17 +117,17 @@ sub Verify {
 
     # Download previous release
     $this->Shell(
       cmd => 'rsync',
       cmdArgs => ['-Lav', 
                   '-e', 'ssh', 
                   '--include=*.dmg',
                   '--include=*.exe',
-                  '--include=*.tar.gz',
+                  '--include=*.tar'.$linuxExtension,
                   '--exclude=*',
                   $stagingServer . ':/home/ftp/pub/' . $product
                   . '/nightly/' . $oldVersion . '-candidates/rc' 
                   . $oldRc . '/*',
                   $product . '-' . $oldVersion . '-rc' . $oldRc . '/',
                  ],
       dir => catfile($verifyDirVersion, 'l10n'),
       logFile => 
--- a/tools/release/Bootstrap/Step/Source.pm
+++ b/tools/release/Bootstrap/Step/Source.pm
@@ -28,25 +28,24 @@ sub Execute {
     my $stageDir = catfile($stageHome, $product . '-' . $version, 
                            'batch-source', 'rc' . $rc);
 
     if (not -d $stageDir) {
         MkdirWithPath(dir => $stageDir) 
           or die("Cannot create $stageDir: $!");
     }
 
-    $this->Shell(
-      cmd => 'cvs',
-      cmdArgs => ['-d', $mozillaCvsroot, 
-                  'co', '-r', $productTag . '_RELEASE',
-                  'mozilla/client.mk', catfile('mozilla', $appName, 'config')],
-      dir => $stageDir,
-      logFile => catfile($logDir, 'source.log'),
+    $this->CvsCo(cvsroot => $mozillaCvsroot,
+                 tag => $productTag . '_RELEASE',
+                 modules => ['mozilla/client.mk',
+                             catfile('mozilla', $appName, 'config')],
+                 workDir => $stageDir,
+                 logFile => catfile($logDir, 'source.log')
     );
-
+                 
     $this->Shell(
       cmd => 'make',
       cmdArgs => ['-f', 'client.mk', 'checkout',
                   'MOZ_CO_PROJECT=' . $appName],
       dir => catfile($stageDir, 'mozilla'),
       logFile => catfile($logDir, 'source.log'),
     );
 
--- a/tools/release/Bootstrap/Step/Stage.pm
+++ b/tools/release/Bootstrap/Step/Stage.pm
@@ -361,20 +361,25 @@ sub Execute {
     # dir -> directories under which those directories should be moved to;
     # the name will be "xpi", so windows-xpi becomes win32/xpi, etc.
     my %xpiDirs = ('windows-xpi' => 'win32',
                    'linux-xpi' => 'linux-i686',
                    'mac-xpi' => 'mac');
 
     foreach my $xpiDir (keys(%xpiDirs)) {
         my $fromDir = catfile($batch1Dir, 'stage-unsigned', $xpiDir);
-        my $toDir = catfile($batch1Dir, 'stage-unsigned',
-         $xpiDirs{$xpiDir}, 'xpi');
+        my $parentToDir = catfile($batch1Dir, 'stage-unsigned',
+         $xpiDirs{$xpiDir});
+        my $toDir = catfile($parentToDir, 'xpi');
 
         if (-e $fromDir) {
+           if (! -e $parentToDir) {
+               MkdirWithPath(dir => $parentToDir) or
+                die("Cannot create $parentToDir");
+           }
            move($fromDir, $toDir)
             or die(msg => "Cannot rename $fromDir $toDir: $!");
            $this->Log(msg => "Moved $fromDir -> $toDir");
         } else {
            $this->Log(msg => "Couldn't find $fromDir; not moving to $toDir");
         }
     }
 
--- a/tools/release/Bootstrap/Step/Tag.pm
+++ b/tools/release/Bootstrap/Step/Tag.pm
@@ -16,40 +16,47 @@ use Bootstrap::Step::Tag::Mozilla;
 use Bootstrap::Step::Tag::l10n;
 use Bootstrap::Step::Tag::Talkback;
 use Bootstrap::Config;
 
 use strict;
 
 our @ISA = qw(Bootstrap::Step);
 
+# Talkback will be appended in Execute() if it is to be used
 my @TAG_SUB_STEPS = qw( Bump
                         Mozilla
                         l10n
-                        Talkback
                       );
 
 sub Execute {
     my $this = shift;
 
     my $config = new Bootstrap::Config();
     my $productTag = $config->Get(var => 'productTag');
     my $rc = $config->Get(var => 'rc');
     my $milestone = $config->Get(var => 'milestone');
     my $tagDir = $config->Get(var => 'tagDir');
     my $mozillaCvsroot = $config->Get(var => 'mozillaCvsroot');
     my $branchTag = $config->Get(var => 'branchTag');
     my $pullDate = $config->Get(var => 'pullDate');
     my $logDir = $config->Get(sysvar => 'logDir');
+    my $useTalkback = $config->Exists(var => 'useTalkback') ?
+     $config->Get(var => 'useTalkback') : 0;
 
     my $releaseTag = $productTag . '_RELEASE';
     my $rcTag = $productTag . '_RC' . $rc;
     my $releaseTagDir = catfile($tagDir, $releaseTag);
     my $rcTagDir = catfile($tagDir, $rcTag);
 
+    # If specified, tag Talkback
+    if ($useTalkback) {
+        push(@TAG_SUB_STEPS, 'Talkback');
+    }
+
     # create the main tag directory
     if (not -d $rcTagDir) {
         MkdirWithPath(dir => $rcTagDir) 
           or die("Cannot mkdir $rcTagDir: $!");
     }
 
     # Tagging area for Mozilla
     my $cvsrootTagDir = catfile($rcTagDir, 'cvsroot');
@@ -61,26 +68,23 @@ sub Execute {
      or die("Cannot mkdir $cvsrootTagDir: $!");
 
     # Check out Mozilla from the branch you want to tag.
     # TODO this should support running without branch tag or pull date.
 
     my $geckoTag = undef;
 
     if (1 == $rc) {
-        $this->Shell(cmd => 'cvs',
-                     cmdArgs => ['-d', $mozillaCvsroot, 
-                                 'co', 
-                                 '-r', $branchTag, 
-                                 '-D', $pullDate, 
-                                 CvsCatfile('mozilla', 'client.mk'),
-                                ],
-                     dir => $cvsrootTagDir,
-                     logFile => catfile($logDir, 'tag_checkout_client_mk.log'),
-                   );
+        $this->CvsCo(cvsroot => $mozillaCvsroot,
+                     tag => $branchTag,
+                     date => $pullDate,
+                     modules => [CvsCatfile('mozilla', 'client.mk')],
+                     workDir => $cvsrootTagDir,
+                     logFile => catfile($logDir, 'tag_checkout_client_mk.log')
+        );
 
         $this->CheckLog(log => catfile($logDir, 'tag_checkout_client_mk.log'),
                        checkForOnly => '^U mozilla/client.mk');
 
         $this->Shell(cmd => 'gmake',
                      cmdArgs => ['-f', 'client.mk', 'checkout', 
                                  'MOZ_CO_PROJECT=all', 
                                  'MOZ_CO_DATE=' . $pullDate],
@@ -121,26 +125,23 @@ sub Execute {
     } else {
         # We go through some convoluted hoops here to get the _RELBRANCH
         # datespec without forcing it to be specified. Because of this,
         # there's lots of icky CVS parsing.
 
         my $rcOneTag = $productTag . '_RC1';
         my $checkoutLog = "tag_rc${rc}_checkout_client_ck.log";
 
-        $this->Shell(cmd => 'cvs',
-                     cmdArgs => ['-d', $mozillaCvsroot,
-                                 'co', 
-                                 '-r', $branchTag, 
-                                 '-D', $pullDate, 
-                                 CvsCatfile('mozilla', 'client.mk')],
-                     dir => $cvsrootTagDir,
-                     logFile => catfile($logDir, $checkoutLog),
-                   );
-
+        $this->CvsCo(cvsroot => $mozillaCvsroot,
+                     tag => $branchTag,
+                     date => $pullDate,
+                     modules => [CvsCatfile('mozilla', 'client.mk')],
+                     workDir => $cvsrootTagDir,
+                     logFile => catfile($logDir, $checkoutLog)
+        );
 
         $this->CheckLog(log => catfile($logDir, $checkoutLog),
                         checkForOnly => '^U mozilla/client.mk');
 
         # Use RunShellCommand() here because we need to grab the output,
         # and Shell() sends the output to a log.
         my $clientMkInfo = RunShellCommand(command => 'cvs',
                                            args => ['log', 
@@ -189,25 +190,22 @@ sub Execute {
         # Strip off the time...
         $relBranchDateSpec =~ s/^\s*([\d\/]+).*/$1/;
         # Strip out the /'s; now we have our datespec: 20061205
         $relBranchDateSpec =~ s/\///g;
 
         $geckoTag = $this->GenerateRelbranchName(milestone => $milestone,
          datespec => $relBranchDateSpec);
 
-        $this->Shell(cmd => 'cvs',
-                     cmdArgs => ['-d', $mozillaCvsroot,
-                                 'co',
-                                 '-r', $geckoTag,
-                                 'mozilla'],
-                     dir => $cvsrootTagDir,
-                     logFile => catfile($logDir, 'tag_checkout_client_mk.log'),
-                   );
-
+        $this->CvsCo(cvsroot => $mozillaCvsroot,
+                     tag => $geckoTag,
+                     modules => ['mozilla'],
+                     workDir => $cvsrootTagDir,
+                     logFile => catfile($logDir, 'tag_checkout_client_mk.log')
+        );
     }
 
     $config->Set(var => 'geckoBranchTag', value => $geckoTag);
 
     # Call substeps
     for (my $curStep = 0; $curStep < scalar(@TAG_SUB_STEPS); $curStep++) {
         my $stepName = $TAG_SUB_STEPS[$curStep];
         eval {
@@ -296,25 +294,34 @@ sub GenerateRelbranchName {
      (!exists($args{'milestone'}));
 
     my $config = new Bootstrap::Config();
 
     if ($config->Exists(var => 'RelbranchOverride')) {
         return $config->Get(var => 'RelbranchOverride');
     }
 
-    # Convert milestone (1.8.1.x) into "181"; we assume we should always have
-    # three digits for now (180, 181, 190, etc.)
+    # Convert milestone (1.8.1.x => 181 or 1.9b1 => 19b1) 
 
     my $geckoVersion = $args{'milestone'};
-    $geckoVersion =~ s/\.//g;
-    $geckoVersion =~ s/^(\d{3}).*$/$1/;
 
-    die "ASSERT: GenerateRelbranchName(): Gecko version should be only " .
-     "numbers by now" if ($geckoVersion !~ /^\d{3}$/);
+    # 1.9.0.10 style version numbers (for releases, generally)
+    if ($geckoVersion =~ m/(\d\.){3,4}/) {
+        $geckoVersion =~ s/\.//g;
+        $geckoVersion =~ s/^(\d{3}).*$/$1/;
+        die "ASSERT: GenerateRelbranchName(): Gecko version should be only " .
+         "numbers by now" if ($geckoVersion !~ /^\d{3}$/);
+    }
+    # 1.9b1 style version numbers (for alpha/betas, generally) 
+    elsif ($geckoVersion =~ m/\d\.\d[ab]\d+/i) {
+        $geckoVersion =~ s/\.//g;
+    }
+    else {
+        die "ASSERT: GenerateRelbranchName(): Unknown Gecko version format";
+    }
 
     my $geckoDateSpec = exists($args{'datespec'}) ? $args{'datespec'} : 
      strftime('%Y%m%d', localtime());
 
     # This assert()ion has a Y21k (among other) problem(s)...
     die "ASSERT: GenerateRelbranchName(): invalid datespec" if 
      ($geckoDateSpec !~ /^20\d{6}$/);
 
--- a/tools/release/Bootstrap/Step/Tag/Bump.pm
+++ b/tools/release/Bootstrap/Step/Tag/Bump.pm
@@ -60,28 +60,25 @@ sub Execute {
 
     # only bump milestone if it's defined in the config
     if (defined($milestone)) {
         @bumpFiles = (@bumpFiles, $milestoneTxt);
     }
 
     # Check out Mozilla from the branch you want to tag.
     # TODO this should support running without branch tag or pull date.
-    $this->Shell(
-      cmd => 'cvs',
-      cmdArgs => ['-d', $mozillaCvsroot, 
-                  'co', 
-                  '-r', $geckoBranchTag, 
-                  CvsCatfile('mozilla', 'client.mk'),
+    $this->CvsCo(
+      cvsroot => $mozillaCvsroot,
+      tag => $geckoBranchTag,
+      modules => [CvsCatfile('mozilla', 'client.mk'),
                   CvsCatfile('mozilla', $appName, 'app', 'module.ver'),
                   CvsCatfile('mozilla', $appName, 'config', 'version.txt'),
-                  CvsCatfile('mozilla', 'config', 'milestone.txt'),
-                 ],
-      dir => $cvsrootTagDir,
-      logFile => catfile($logDir, 'tag-bump_checkout.log'),
+                  CvsCatfile('mozilla', 'config', 'milestone.txt')],
+      workDir => $cvsrootTagDir,
+      logFile => catfile($logDir, 'tag-bump_checkout.log')
     );
 
     ### Perform version bump
 
     my $parentDir = catfile($cvsrootTagDir, 'mozilla');
     foreach my $fileName (@bumpFiles) {
         my $found = 0;
 
@@ -90,17 +87,19 @@ sub Execute {
         my $bumpVersion = undef;
         my $preVersion = undef;
         my %searchReplace = ();
 
         # Order or searching for these values is not preserved, so make
         # sure that the order replacement happens does not matter.
         if ($fileName eq 'client.mk') {
             %searchReplace = (
-             '^MOZ_CO_TAG\s+=\s+' . $branchTag . '$' =>
+             # MOZ_CO_TAG is commented out on some branches, make sure to
+             # accommodate that
+             '^#?MOZ_CO_TAG\s+=.+$' =>
               'MOZ_CO_TAG           = ' . $releaseTag,
              '^NSPR_CO_TAG\s+=\s+\w*' => 
               'NSPR_CO_TAG          = ' . $releaseTag,
              '^NSS_CO_TAG\s+=\s+\w*' =>
               'NSS_CO_TAG           = ' . $releaseTag,
              '^LOCALES_CO_TAG\s+=\s+' . $branchTag . '$' =>
               'LOCALES_CO_TAG       = ' . $releaseTag,
              '^LDAPCSDK_CO_TAG\s+=\s+' . $branchTag . '$' =>
@@ -137,17 +136,17 @@ sub Execute {
                 }
             }
 
             print OUTFILE $_;
         }
         close INFILE or die("Could not close $file: $!");
         close OUTFILE or die("Coule not close $file.tmp: $!");
         if (not $found) {
-            die("None of " . join(keys(%searchReplace)) . 
+            die("None of " . join(' ', keys(%searchReplace)) . 
              " found in file $file: $!");
         }
 
         if (not move("$file.tmp",
                      "$file")) {
             die("Cannot rename $file.tmp to $file: $!");
         }
     }
--- a/tools/release/Bootstrap/Step/Tag/Talkback.pm
+++ b/tools/release/Bootstrap/Step/Tag/Talkback.pm
@@ -42,22 +42,23 @@ sub Execute {
     # Create the mofo tag directory.
     my $mofoDir = catfile($releaseTagDir, 'mofo');
     if (not -d $mofoDir) {
         MkdirWithPath(dir => $mofoDir) 
           or die("Cannot mkdir $mofoDir: $!");
     }
 
     # Check out the talkback files from the branch you want to tag.
-    $this->Shell(
-      cmd => 'cvs',
-      cmdArgs => ['-d', $mofoCvsroot, 'co', '-r', $branchTag, '-D', 
-                  $pullDate, CvsCatfile('talkback', 'fullsoft')],
-      dir => catfile($releaseTagDir, 'mofo'),
-      logFile => catfile($logDir, 'tag-talkback_mofo-checkout.log'),
+    $this->CvsCo(
+      cvsroot => $mofoCvsroot,
+      tag => $branchTag,
+      date => $pullDate,
+      modules => [CvsCatfile('talkback', 'fullsoft')],
+      workDir => catfile($releaseTagDir, 'mofo'),
+      logFile => catfile($logDir, 'tag-talkback_mofo-checkout.log')
     );
 
     # Create the talkback RELEASE tag.
     $this->CvsTag(
       tagName => $releaseTag,
       coDir => catfile($releaseTagDir, 'mofo', 'talkback', 'fullsoft'),
       logFile => catfile($logDir, 
                          'tag-talkback_mofo-tag-' . $releaseTag . '.log'),
--- a/tools/release/Bootstrap/Step/Tag/l10n.pm
+++ b/tools/release/Bootstrap/Step/Tag/l10n.pm
@@ -49,40 +49,32 @@ sub Execute {
     # Note: GetLocaleInfo() has a dependency on the $releaseTag above already
     # being set; it should be by when the l10n tagging step gets run, though.
 
     my $localeInfo = $config->GetLocaleInfo();
 
     # Config::Set() for us by Step::Tag::Execute() 
     my $geckoTag = $config->Get(var => 'geckoBranchTag');
 
-    # Check out the l10n files from the branch you want to tag.
-
-    my @l10nCheckoutArgs = (1 == $rc) ?
-     # For rc1, pull by date on the branch
-     ('-r', $branchTag, '-D', $l10n_pullDate) :
-     # For rc(N > 1), pull the _RELBRANCH tag and tag that
-     ('-r', $geckoTag);
-
     for my $locale (sort(keys(%{$localeInfo}))) {
         # skip en-US; it's kept in the main repo
         next if ($locale eq 'en-US');
 
-        $this->Shell(
-            cmd => 'cvs',
-            cmdArgs => ['-d', $l10nCvsroot, 'co', @l10nCheckoutArgs, 
-                        CvsCatfile('l10n', $locale)],
-            dir => $l10nTagDir,
-            logFile => catfile($logDir, 'tag-l10n_checkout.log'),
-        );
+        # Make sure to pull from the right tag and/or date for rcN.
+        $this->CvsCo(cvsroot => $l10nCvsroot,
+                     tag => (1 == $rc) ? $branchTag : $geckoTag,
+                     date => (1 == $rc) ? $l10n_pullDate : 0,
+                     modules => [CvsCatfile('l10n', $locale)],
+                     workDir => $l10nTagDir,
+                     logFile => catfile($logDir, 'tag-l10n_checkout.log'));
     }
 
     my $cwd = getcwd();
     chdir(catfile($l10nTagDir, 'l10n')) or
-     die "chdir() to $releaseTagDir/l10n failed: $!\n";
+     die "chdir() to $l10nTagDir/l10n failed: $!\n";
     my @topLevelFiles = grep(!/^CVS$/, glob('*'));
     chdir($cwd) or die "Couldn't chdir() home: $!\n";
 
     if (1 == $rc) {
         $this->CvsTag(tagName => $geckoTag,
                       branch => 1,
                       files => \@topLevelFiles,
                       coDir => catfile($l10nTagDir, 'l10n'),
--- a/tools/release/Bootstrap/Step/TinderConfig.pm
+++ b/tools/release/Bootstrap/Step/TinderConfig.pm
@@ -35,27 +35,36 @@ sub Execute {
     if (-e $productConfigBumpDir) {
         die "ASSERT: Step::TinderConfig::Execute(): $productConfigBumpDir " .
          'already exists?';
     }
 
     MkdirWithPath(dir => $productConfigBumpDir)
       or die("Cannot mkdir $productConfigBumpDir: $!");
 
-    foreach my $branch ($branchTag . '_release', $branchTag . '_l10n_release') {
-        $this->Shell(
-          cmd => 'cvs',
-          cmdArgs => ['-d', $mozillaCvsroot, 
-                      'co', '-d', $branch,
-                      '-r', $branch,
-                      CvsCatfile('mozilla', 'tools', 'tinderbox-configs',
-                                 $product, $osname)],
-          logFile => catfile($logDir, 
-           'build_config-checkout-' . $branch . '.log'),
-          dir => $productConfigBumpDir,
+    my @branches = ();
+    # tinderbox-configs tags are different on branches vs trunk
+    # Do the right thing in both cases
+    if ($branchTag eq 'HEAD') {
+        push(@branches, ('release', 'l10n_release'));
+    }
+    else {
+        push(@branches, $branchTag . '_release');
+        push(@branches, $branchTag . '_l10n_release');
+    }
+
+    foreach my $branch (@branches) {
+        $this->CvsCo(cvsroot => $mozillaCvsroot,
+                     checkoutDir => $branch,
+                     tag => $branch,
+                     modules => [CvsCatfile('mozilla', 'tools',
+                                  'tinderbox-configs', $product, $osname)],
+                     logFile => catfile($logDir,
+                      'build_config-checkout-' . $branch . '.log'),
+                     workDir => $productConfigBumpDir
         );
   
         my @bumpConfigFiles = qw(tinder-config.pl mozconfig);
 
         foreach my $configFile (@bumpConfigFiles) {
             $config->Bump( configFile => 
              catfile($productConfigBumpDir, $branch, $configFile));
             $this->Shell(
@@ -109,19 +118,29 @@ sub Execute {
 }
 
 sub Verify {
     my $this = shift;
 
     my $config = new Bootstrap::Config();
     my $branchTag = $config->Get(var => 'branchTag');
     my $logDir = $config->Get(sysvar => 'logDir');
+    
+    my @branches = ();
+    # tinderbox-configs tags are different on branches vs trunk
+    # Do the right thing in both cases
+    if ($branchTag eq 'HEAD') {
+        push(@branches, ('release', 'l10n_release'));
+    }
+    else {
+        push(@branches, $branchTag . '_release');
+        push(@branches, $branchTag . '_l10n_release');
+    }
 
-    foreach my $branch ($branchTag . '_release', $branchTag . '_l10n_release') {
-
+    foreach my $branch (@branches) {
         $this->CheckLog(
             log => catfile($logDir, 
              'build_config-checkout-' . $branch . '.log'),
             notAllowed => 'fail',
         );
 
         $this->CheckLog(
             log => catfile($logDir, 
--- a/tools/release/Bootstrap/Step/Updates.pm
+++ b/tools/release/Bootstrap/Step/Updates.pm
@@ -33,40 +33,40 @@ sub Execute {
 
     # Create updates area.
     if (not -d $versionedUpdateDir) {
         MkdirWithPath(dir => $versionedUpdateDir) 
           or die("Cannot mkdir $versionedUpdateDir: $!");
     }
 
     # check out patcher
-    $this->Shell(
-      cmd => 'cvs',
-      cmdArgs => ['-d', $mozillaCvsroot, 'co', '-d', 'patcher', 
-                  CvsCatfile('mozilla', 'tools', 'patcher')],
-      logFile => catfile($logDir, 'updates_patcher-checkout.log'),
-      dir => $versionedUpdateDir,
+    $this->CvsCo(cvsroot => $mozillaCvsroot,
+                 checkoutDir => 'patcher',
+                 modules => [CvsCatfile('mozilla', 'tools', 'patcher')],
+                 logFile => catfile($logDir, 'updates_patcher-checkout.log'),
+                 workDir => $versionedUpdateDir
     );
-
+          
     # check out utilities
-    $this->Shell(
-      cmd => 'cvs',
-      cmdArgs => ['-d', $mozillaCvsroot, 'co', '-d', 'MozBuild', 
-                  CvsCatfile('mozilla', 'tools', 'release', 'MozBuild')],
-      logFile => catfile($logDir, 'updates_patcher-utils-checkout.log'),
-      dir => catfile($versionedUpdateDir, 'patcher'),
+    $this->CvsCo(cvsroot => $mozillaCvsroot,
+                 checkoutDir => 'MozBuild',
+                 modules => [CvsCatfile('mozilla', 'tools', 'release',
+                                        'MozBuild')],
+                 logFile => catfile($logDir,
+                                    'updates_patcher-utils-checkout.log'),
+                 workDir => catfile($versionedUpdateDir, 'patcher')
     );
-
+          
     # config lives in private repo
-    $this->Shell(
-      cmd => 'cvs',
-      cmdArgs => ['-d', $mofoCvsroot, 'co', '-d', 'config',  
-                  CvsCatfile('release', 'patcher', $patcherConfig)],
-      logFile => catfile($logDir, 'updates_patcher-config-checkout.log'),
-      dir => $versionedUpdateDir,
+    $this->CvsCo(cvsroot => $mofoCvsroot,
+                 checkoutDir => 'config',
+                 modules => [CvsCatfile('release', 'patcher', $patcherConfig)],
+                 logFile => catfile($logDir,
+                                    'updates_patcher-config-checkout.log'),
+                 workDir => $versionedUpdateDir
     );
 
     # build tools
     my $originalCvsrootEnv = $ENV{'CVSROOT'};
     $ENV{'CVSROOT'} = $mozillaCvsroot;
     $this->Shell(
       cmd => './patcher2.pl',
       cmdArgs => ['--build-tools', '--tools-revision=' . $patcherToolsRev,
@@ -134,23 +134,23 @@ sub Verify {
     my $verifyConfig = $config->Get(sysvar => 'verifyConfig');
 
     # Create verification area.
     my $verifyDirVersion = catfile($verifyDir, $product . '-' . $version);
     MkdirWithPath(dir => $verifyDirVersion) 
       or die("Could not mkdir $verifyDirVersion: $!");
 
     foreach my $dir ('updates', 'common') {
-        $this->Shell(
-          cmd => 'cvs',
-          cmdArgs => ['-d', $mozillaCvsroot, 'co', '-d', $dir,
-                      CvsCatfile('mozilla', 'testing', 'release', $dir)],
-          logFile => catfile($logDir, 
-                               'updates_verify_checkout-' . $dir . '.log'),
-          dir => $verifyDirVersion,
+        $this->CvsCo(cvsroot => $mozillaCvsroot,
+                     checkoutDir => $dir,
+                     modules => [CvsCatfile('mozilla', 'testing', 'release',
+                                            $dir)],
+                     logFile => catfile($logDir,
+                                 'updates_verify_checkout-' . $dir . '.log'),
+                     workDir => $verifyDirVersion
         );
     }
 
     $this->BumpVerifyConfig();
     
     # Customize updates.cfg to contain the channels you are interested in 
     # testing.
     
@@ -227,16 +227,23 @@ sub BumpVerifyConfig {
     my $oldRc = $config->Get(var => 'oldRc');
     my $appName = $config->Get(var => 'appName');
     my $mozillaCvsroot = $config->Get(var => 'mozillaCvsroot');
     my $verifyDir = $config->Get(var => 'verifyDir');
     my $externalAusServer = $config->Get(var => 'externalAusServer');
     my $externalStagingServer = $config->Get(var => 'externalStagingServer');
     my $verifyConfig = $config->Get(sysvar => 'verifyConfig');
     my $logDir = $config->Get(sysvar => 'logDir');
+    # We are assuming tar.bz2 to help minimize bootstrap.cfg variables in
+    # the future. tar.gz support can probably be removed once we stop
+    # building/releasing products that use it.
+    my $useTarGz = $config->Exists(var => 'useTarGz') ?
+     $config->Get(var => 'useTarGz') : 0;
+    my $linuxExtension = ($useTarGz) ? '.gz' : '.bz2';
+
 
     my $verifyDirVersion = catfile($verifyDir, $product . '-' . $version);
     my $configFile = catfile($verifyDirVersion, 'updates', $verifyConfig);
 
     # NOTE - channel is hardcoded to betatest
     my $channel = 'betatest';
 
     # grab os-specific buildID file on FTP
@@ -248,18 +255,19 @@ sub BumpVerifyConfig {
     my $releaseFile = undef;
     my $nightlyFile = undef;
     my $ftpOsname = undef;
 
     if ($osname eq 'linux') {
         $buildTarget = 'Linux_x86-gcc3';
         $platform = 'linux';
         $ftpOsname = 'linux-i686';
-        $releaseFile = $product.'-'.$oldVersion.'.tar.gz';
-        $nightlyFile = $product.'-'.$version.'.%locale%.linux-i686.tar.gz';
+        $releaseFile = $product.'-'.$oldVersion.'.tar'.$linuxExtension;
+        $nightlyFile = $product.'-'.$version.'.%locale%.linux-i686.tar'.
+         $linuxExtension;
     } elsif ($osname eq 'macosx') {
         $buildTarget = 'Darwin_Universal-gcc3';
         $platform = 'osx';
         $ftpOsname = 'mac';
         $releaseFile = ucfirst($product).' '.$oldVersion.'.dmg';
         $nightlyFile = $product.'-'.$version.'.%locale%.mac.dmg';
     } elsif ($osname eq 'win32') {
         $buildTarget = 'WINNT_x86-msvc';
--- a/tools/release/Bootstrap/Util.pm
+++ b/tools/release/Bootstrap/Util.pm
@@ -99,17 +99,18 @@ sub LoadLocaleManifest {
        die ("ASSERT: Bootstrap::Util::LoadLocaleManifest(): Can't find manifest"
         . " $manifestFile");
     }
 
     open(MANIFEST, "<$manifestFile") or return 0;
     my @manifestLines = <MANIFEST>;
     close(MANIFEST);
 
-    my @bouncerPlatforms = sort(GetBouncerPlatforms());
+    my @bouncerPlatforms = GetBouncerPlatforms();
+    @bouncerPlatforms = sort(@bouncerPlatforms);
 
     foreach my $line (@manifestLines) {   
        # We create an instance variable so if the caller munges the reference
        # to which a certain locale points, they won't screw up all the other
        # locales; previously, this was a shared array ref, which is bad.
        my @bouncerPlatformsInstance = @bouncerPlatforms;
 
        my @elements = split(/\s+/, $line);
--- a/tools/release/configs/fx-moz18-bootstrap.cfg
+++ b/tools/release/configs/fx-moz18-bootstrap.cfg
@@ -67,8 +67,11 @@ externalStagingUser     = cltbld
 externalStagingServer   = stage.mozilla.org
 # where beta updates/builds go
 ftpServer       = ftp.mozilla.org
 # where release updates/builds go
 bouncerServer   = download.mozilla.org
 # username and server to push builds
 sshUser         = cltbld
 sshServer       = build-console.build.mozilla.org
+# force 1.8 specific behavior
+useTalkback     = 1
+useTarGz        = 1
--- a/tools/release/configs/fx-moz18-staging-bootstrap.cfg
+++ b/tools/release/configs/fx-moz18-staging-bootstrap.cfg
@@ -66,8 +66,11 @@ externalStagingUser     = cltbld
 externalStagingServer   = staging-prometheus-vm.build.mozilla.org
 # where beta updates/builds go
 ftpServer       = staging-build-console.build.mozilla.org
 # where release updates/builds go
 bouncerServer   = staging-build-console.build..mozilla.org
 # username and server to push builds
 sshUser         = cltbld
 sshServer       = staging-build-console.build.mozilla.org
+# force 1.8 specific behavior
+useTalkback     = 1
+useTarGz        = 1
--- a/tools/release/configs/fx-moz180-bootstrap.cfg
+++ b/tools/release/configs/fx-moz180-bootstrap.cfg
@@ -54,9 +54,11 @@ sendmail        = /usr/lib/sendmail
 dumpLogs        = 1
 # username and server to push builds
 sshUser         = cltbld
 sshServer       = stage.mozilla.org
 # username and server to push update snippets
 ausUser           = cltbld
 ausServer         = aus2-staging.mozilla.org
 externalAusServer = aus2.mozilla.org
-
+# force 1.8 specific behavior
+useTalkback     = 1
+useTarGz        = 1
--- a/tools/release/configs/tb-moz18-bootstrap.cfg
+++ b/tools/release/configs/tb-moz18-bootstrap.cfg
@@ -61,8 +61,11 @@ externalStagingUser     = cltbld
 externalStagingServer   = stage.mozilla.org
 # where beta updates/builds go
 ftpServer       = ftp.mozilla.org
 # where release updates/builds go
 bouncerServer   = download.mozilla.org
 # username and server to push builds
 sshUser         = cltbld
 sshServer       = build-console.build.mozilla.org
+# force 1.8 specific behavior
+useTalkback     = 1
+useTarGz        = 1
--- a/tools/release/configs/tb-moz180-bootstrap.cfg
+++ b/tools/release/configs/tb-moz180-bootstrap.cfg
@@ -53,8 +53,11 @@ sendmail        = /usr/lib/sendmail
 dumpLogs        = 1
 # username and server to push builds
 sshUser         = cltbld
 sshServer       = stage.mozilla.org
 # username and server to push update snippets
 ausUser           = cltbld
 ausServer         = aus2-staging.mozilla.org
 externalAusServer = aus2.mozilla.org
+# force 1.8 specific behavior
+useTalkback     = 1
+useTarGz        = 1