#!/usr/bin/perl -W # -*- Mode: perl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- # prototypes are your friend. sub my_die($$); sub non_fatal_error($$); sub get_date(); sub section_complete($); sub process_env_hash($); sub darwin_make_image(); sub darwin_post_build_sub(); ################################################################################ # User configuration section. # # Change these values. # ################################################################################ # Build the source? # pass -b to build $BuildSource = 0; # Make an image file? # change this to 0 if you haven't tweaked the section below! # pass -i to make image $MakeImage = 0; # upload it? # change this to 0 if you haven't tweaked the section below! # pass -u to upload $DoUpload = 0; $Debug = 0; # the top level directory $BaseDir = $ENV{'HOME'} . "/src/mozilla.org"; # the patch directory #$patchDir = "$BaseDir/conf/patches"; # uncomment this next line $remoteCvsRoot = ":pserver:anonymous\@cvs-mirror.mozilla.org:/cvsroot"; # you need to comment out this next line, it won't work for you $localCvsRoot = "/usr/local/cvsroot/mozilla"; # this is the upload command, that takes a single argument, which is # the date string we build with get_date() $UploadCommand = "~/bin/firefox-upload"; $BuildDate = get_date(); # the default program $Program = "Firefox"; # a pre build script to copy over trademarked items, relative to the modified $BaseDir # the $BaseDir that has been modified by the product is passed as an arg $PrebuildScript = "/conf/firefox-prebuild.sh"; $DoPrebuild = 1; ################################################################################ # END USER CONFIGURATION # # # # You'll still need to tweak the image creation and copy sections if you plan # # on using them, otherwise set $MakeImage and $DoUpload to 0! # ################################################################################ $cvsRoot=''; %Status = ( 'post_build_sub_complete' => 0, ); while($arg = shift(@ARGV)) { if($arg eq "-d") { # debug $Debug = 1; } elsif($arg eq "-b") { $BuildSource = 1; } elsif($arg eq "-i") { $MakeImage = 1; } elsif($arg eq "-u") { $DoUpload = 1; } elsif($arg eq '-l') { if(length($cvsRoot) == 0) { $cvsRoot = $localCvsRoot; } else { my_die(__LINE__, "You can only specify must specify one of -l or -r for local or remote cvs.") } } elsif($arg eq '-r') { if(length($cvsRoot) == 0) { $cvsRoot = $remoteCvsRoot; } else { my_die(__LINE__, "You can only specify must specify one of -l or -r for local or remote cvs.") } } elsif($arg eq '-a' || $arg eq '--all') { $BuildSource = 1; $MakeImage = 1; $DoUpload = 1; $DoPrebuild = 1; } elsif($arg eq '-p') { $Program = shift(@ARGV); } elsif($arg =~ m/^--program=/) { @progargs = split('=', $arg); $Program = pop(@progargs); } elsif($arg eq "-pb") { $PrebuildScript = shift(@ARGV); $DoPrebuild = 1; } elsif($arg =~ m/^--prebuild=/) { @pb = split('=', $arg); $PrebuildScript = pop(@pb); $DoPrebuild = 1; } elsif($arg =~ m/^--no-prebuild/ || $arg eq "-npb") { $PrebuildScript = undef; $DoPrebuild = 0; } else { my_die(__LINE__, "Unrecognized option: $arg"); } } if(length($cvsRoot) == 0) { $cvsRoot = $localCvsRoot; } # most of these are relevant to $BaseDir %Products = ( 'Firefox' => { 'base_dir' => "/firefox", 'app_dir' => "Firefox.app", 'app_bin' => "firefox-bin", 'pkg_label' => "Firefox", 'dbg_label' => "Debug-Firefox", 'mozconfig' => "/conf/mozconfig", 'dbg_mozconfig' => "/conf/mozconfig.debug", 'patch_dir' => "/conf/patches", 'debug_patch_dir'=>"/conf/debug_patches", }, 'Mozilla' => { 'base_dir' => "/mozilla", 'app_dir' => "Mozilla.app", 'app_bin' => "mozilla-bin", 'pkg_label' => "Mozilla", 'dbg_label' => "Debug-Mozilla", 'mozconfig' => "/conf/mozconfig", 'dbg_mozconfig' => "/conf/mozconfig.debug", }, ); $BaseDir = $BaseDir . $Products{$Program}{'base_dir'}; # the directory that the source gets pulled to (don't change this) $SourceDir = $BaseDir . "/mozilla"; # I suppose changing these won't hurt anything. if($Debug) { $buildLabel = "$Products{$Program}{'dbg_label'}-$BuildDate"; $mozconfig = "$BaseDir/$Products{$Program}{'dbg_mozconfig'}"; } else { $buildLabel = "$Products{$Program}{'pkg_label'}-$BuildDate"; $mozconfig = "$BaseDir/$Products{$Program}{'mozconfig'}"; } $AppDir = $Products{$Program}{'app_dir'}; #figure out the OS $host = `uname -s`; chomp($host); %OSInfo = ( 'Darwin' => { 'image_suffix' => "-mac.dmg", 'make_image_sub' => \&darwin_make_image, 'post_build_sub' => \&darwin_post_build_sub, 'env' => { 'all' => { 'set' => { 'PATH' => "/sbin:/usr/sbin:/usr/local/sbin:/sw/bin:/sw/sbin:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin:/usr/X11R6/bin:/Developer/Tools", 'DYLD_NO_FIX_PREBINDING' => 1, 'MOZ_CVS_FLAGS' => "-Q -d$cvsRoot", }, }, 'debug' => { 'unset' => { 'LD_PREBIND_ALLOW_OVERLAP' => 1, }, }, 'normal' => { 'set' => { 'LD_PREBIND_ALLOW_OVERLAP' => 1, }, }, }, }, 'Linux' => { 'image_suffix' => "i686-linux-gtk2+xft.tar", 'make_image_sub' => undef, 'post_build_sub' => undef, 'env' => { 'all' => { 'set' => { 'MOZ_CVS_FLAGS' => "-Q -d$cvsRoot", }, }, }, }, ); %envSettings = %{$OSInfo{$host}{'env'}}; # If we ever need to add environment settings for a particular product, we # just add it to %envSettings. process_env_hash(\%{$envSettings{'all'}}); if($Debug) { process_env_hash(\%{$envSettings{'debug'}}); } else { process_env_hash(\%{$envSettings{'normal'}}); } chdir($BaseDir) || my_die(__LINE__, "Can't chdir to $BaseDir: $!"); ################################################################################ # This is the section that builds the source, and is most likely what you want. if($BuildSource != 0) { # remove the link to mozilla if(-l $SourceDir) { unlink($SourceDir) || my_die(__LINE__, "Can't unlink $SourceDir: $!"); } elsif (-d $SourceDir) { if(system("rm -rf $SourceDir") != 0) { my_die(__LINE__ - 1, "Can't unlink $SourceDir: $!"); } } # checkout client.mk if(system("cvs -d$cvsRoot co mozilla/client.mk") != 0) { my_die(__LINE__ - 1, "cvs -d$cvsRoot co mozilla/client.mk failed: $?"); } # checkout the mozconfig if(system("cvs -d$cvsRoot co mozilla/browser/config/mozconfig") != 0) { my_die(__LINE__ -1, "cvs -d$cvsRoot co mozilla/browser/config/mozconfig failed: $?"); } # determine a the time and rename the source directory if(-e $SourceDir) { $newSourceDir = "$BaseDir/$buildLabel"; if(-d $newSourceDir) { # this should never happen, but just in case... rmdir($newSourceDir); } rename($SourceDir, $newSourceDir); symlink($newSourceDir, $SourceDir); } else { my_die(__LINE__, "$SourceDir doesn't exist!"); } chdir($SourceDir) || my_die(__LINE__, "Can't chdir to $SourceDir: $!"); # copy mozconfig .mozconfig if(system("cp $mozconfig .mozconfig") != 0) { my_die(__LINE__ - 1, "Can't copy $mozconfig to .mozconfig: $?"); } # pull the sources if(system("make -w -f client.mk checkout") != 0) { my_die(__LINE__ - 1, "make command failed: $?"); } # apply patches $patchDir = undef; if($Debug) { $patchDir = "$BaseDir/$Products{$Program}{'debug_patch_dir'}"; } else { $patchDir = "$BaseDir/$Products{$Program}{'patch_dir'}"; } if(defined($patchDir)) { @patches = glob("$patchDir/*.patch"); while($patch = shift(@patches)) { if(system("patch -p0 < $patch") != 0) { my_die(__LINE__ -1, "Couldn't apply patch $patch: $?"); } } } # run the prebuild script if($DoPrebuild && defined($PrebuildScript)) { if(system("$BaseDir$PrebuildScript $BaseDir") != 0) { my_die(__LINE__ -1, "Pre build script $PrebuildScript failed: $!"); } } # do the build if(system("make -w -f client.mk build") != 0) { my_die(__LINE__ - 1, "make -w -f client.mk failed: $?"); } if(defined($OSInfo{$host}{'post_build_sub'})) { &{$OSInfo{$host}{'post_build_sub'}}; } section_complete("Build"); } # $BuildSource != 0 if($MakeImage != 0) { if(defined($OSInfo{$host}{'post_build_sub'}) && $Status{'post_build_sub_complete'} == 0) { &{$OSInfo{$host}{'post_build_sub'}}; } if(defined($OSInfo{$host}{'make_image_sub'})) { &{$OSInfo{$host}{'make_image_sub'}}; } else { my_die(__LINE__, "Don't know how to make an image on platform $host"); } } if($DoUpload != 0) { # copy it over to the firewall if(system("$UploadCommand $BuildDate") != 0) { my_die(__LINE__ - 1, "Upload command failed: $?"); } section_complete("Upload"); } # BOOP! print("\007"); sub nonfatal_error($$) { my($line, $failure) = @_; format STDERR= ############################################################################# # # # # # ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~~# $0 # FAILED line ^|||: # $line # # # ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~~# $failure # # # # ############################################################################# . write(STDERR); } sub my_die($$) { my($line, $failure) = @_; nonfatal_error($line, $failure); exit(1); } sub get_date() { # get a date string for various labels @now = gmtime(); $now[5] += 1900; $now[4] += 1; for ($i = 0; $i < 8; $i++) { if($now[$i] < 10) { $now[$i] = "0" . $now[$i]; } } return("$now[5]-$now[4]-$now[3]-$now[2]"); } sub section_complete($) { my($section) = @_; print("\n\n############## $0 $section COMPLETE ##########\n\n"); } sub process_env_hash($) { my($hash) = @_; foreach $key (keys(%{$hash->{'set'}})) { $ENV{$key} = $hash->{'set'}{$key}; } foreach $key (keys(%{$hash->{'unset'}})) { delete $hash->{'unset'}{$key}; } } sub darwin_make_image() { my ($tmp) = undef; if($Debug) { $tmp = 'dbg_label'; } else { $tmp = 'pkg_label'; } my($packageLabel) = $Products{$Program}{$tmp}; if(!defined($packageLabel)) { my_die(__LINE__, "\$packagdeLabel not defined!"); } my($packageDir) = "$BaseDir/$packageLabel"; if(!defined($packageDir)) { my_die(__LINE__, "\$packagdeDir not defined!"); } my($imageFile) = "$packageDir$OSInfo{$host}{'image_suffix'}"; if(!defined($imageFile)) { my_die(__LINE__, "\$imageFile not defined!"); } my($compressedImage) = "$imageFile.gz"; my($bindir) = "$packageDir/$AppDir/Contents/MacOS"; # change base directories chdir($BaseDir) || my_die(__LINE__, "Couldn't chdir to $BaseDir: $!"); if(-e $packageDir) { if(system("rm -rf $packageDir") != 0) { my_die(__LINE__ -1, "Couldn't remove $packageDir: $?"); } } if(-e $imageFile) { unlink($imageFile) || my_die(__LINE__, "Couldn't unlink $imageFile: $!"); } # run my package and upload scripts mkdir($packageDir) || my_die(__LINE__ -1, "Couldn't make dir $packageDir: $!"); # copy over the new one if(system("rsync -aL $SourceDir/dist/$AppDir/ $packageDir/$AppDir/") != 0) { #my_die(__LINE__ - 1, "Couldn't copy the appDir to the packageDir: $?"); } # relink and strip if(system("$bindir/xpt_link $bindir/components.xpt $bindir/components/*.xpt") != 0) { my_die(__LINE__ - 1, "Couldn't run xpt_link"); } if(system("rm $bindir/components/*.xpt") != 0) { my_die(__LINE__ - 1, "Couldn't rm $bindir/components/*.xpt: $?"); } if(system("mv $bindir/components.xpt $bindir/components/") != 0) { my_die(__LINE__ - 1, "Couldn't mv $bindir/components.xpt to $bindir/components/: $?"); } # strip the executable in the dist dir, not the build chdir("$packageDir/$AppDir") || my_die(__LINE__, "Couldn't chdir to $packageDir/$AppDir/: $!"); @stripFiles = `find . -type f -perm 755 -exec file {} \\; | grep Mach-O`; foreach $file (@stripFiles) { $file =~ s/: Mach-O.*//; $file =~ s/ /\\ /g; if(system("strip -x $file") != 0) { my_die(__LINE__ - 1, "Couldn't strip file $file: $?"); } } chdir("$packageDir/$AppDir/Contents/MacOS") || my_die(__LINE__, "Couldn't chdir to $bindir: $!"); @trash = qw(asdecode bloaturls.txt mangle mozilla-config nsinstall regExport res/samples res/throbber xpcshell xpidl xpt_dump xpt_link chrome/chromelist.txt); foreach $file (@trash) { if(system("rm -rf $file") != 0) { nonfatal_error(__LINE__ - 1, "Couldn't unlink file $file\n"); } } chdir($BaseDir) || my_die(__LINE__, "Couldn't chdir to $BaseDir: $!"); # size up the directory, and add a little extra $imageSize = `/usr/bin/du -s $packageDir | /usr/bin/cut -f1`; $imageSize += $imageSize * 0.05; if(system("hdiutil create -ov -sectors $imageSize -fs HFS+ -volname $packageLabel $imageFile") != 0) { my_die(__LINE__ -1, "Couldn't create image file $packageLabel: $?"); } if(system("hdiutil mount $imageFile") != 0) { my_die(__LINE__ - 1, "Couldn't mount image $imageFile: $?"); } if(system("rsync -a $packageDir/ /Volumes/$packageLabel/") != 0) { my_die(__LINE__ - 1, "Couldn't copy $packageDir: $?"); } chdir("$BaseDir") || my_die(__LINE__, "Couldn't chdir to $BaseDir: $!"); #nonfatal_error(__LINE__, "Unmounting /Volumes/$packageLabel/"); if(system("hdiutil unmount /Volumes/$packageLabel/") != 0) { my_die(__LINE__ - 1, "Couldn't unmount $packageLabel: $?"); } #nonfatal_error(__LINE__, "Done unmounting /Volumes/$packageLabel/"); if(-e $compressedImage) { unlink($compressedImage) || my_die(__LINE__, "Can't unlink $compressedImage: $!"); } # create the compressed image if(system("gzip --best $imageFile") != 0) { my_die(__LINE__ - 1, "Couldn't compress image file $imageFile: $?"); } section_complete("Make Image"); } # $MakeImage != 0 sub darwin_post_build_sub() { my $cmd = $Products{$Program}{'app_bin'}; if(!defined($cmd)) { my_die(__LINE__ -1, "app_bin command not defined!"); } # register the components if(!chdir("$SourceDir/dist/$AppDir/Contents/MacOS")) { nonfatal_error(__LINE__ - 1, "Can't chdir to $SourceDir/dist/$AppDir/Contents/MacOS: $!"); return; } $ENV{'DYLD_LIBRARY_PATH'} = `pwd`; if(system("./$Products{$Program}{'app_bin'} -register") != 0) { nonfatal_error(__LINE__ -1, "./$Products{$Program}{'app_bin'} -register returned $?\n"); } chdir($SourceDir) || my_die(__LINE__, "Can't chdir to $SourceDir: $!"); $Status{'post_build_sub_complete'} = 1; }