#!/usr/bin/perl -w no warnings 'portable'; require 5.6.0; use strict; use Cwd; use File::Copy; use File::Path; use Getopt::Long; use POSIX qw(strftime); # this is the build script for the SlimServer. # It currently builds a versioned directory containing: # A "server" containing the Perl server code and firmware # A tarred and gzip'd copy of this directory # A zipped copy of this directory # A RedHat RPM # A Mac OS X preference pane and SLIMP3 firmware updater application # A standalone Windows application shell, server executable, firmware updater, and installer # Requires: # command-line zip tool # Macintosh Developer Tools (on MacOS systems only) # cygwin (including cygwin perl), ActiveState PerlDev, Windows Dev Studio .NET (windows) # rpm (if you've got it) my $snapshot = 0; my $date; my $version; my $title; my $title_perlscripts; my $distdir; my $sourcecopy; my $TOPDIR; my $checkout; my $source; my $update; my $branch = 'trunk'; my $humantitle; my $pwd; # set these to the explicit path of your windows perl installation my $perldir = "/c/Perl"; my $perldirwin = "C:\\Perl"; my %osToBuildMap = ( 'MSWin32' => \&buildWin32Installer, 'cygwin' => \&buildWin32Installer, 'darwin' => \&buildOSXInstaller, 'linux' => \&buildRPM, 'solaris' => \&buildSysVPkg, ); sub main { if (!GetOptions( 'version=s' => \$version, 'snapshot' => \$snapshot, 'checkout' => \$checkout, 'update' => \$update, 'branch=s' => \$branch, )) { showUsage(); exit(1); }; my $arg = pop(@ARGV); $pwd = cwd(); my $branchname = ''; if ($snapshot) { $version = $date = strftime('%Y-%m-%d', localtime()); if ($branch ne 'trunk') { $branchname = $branch; $branchname =~ s/^BRANCH_//; } $checkout = 1; $update = 0; } else { if (!defined($version)) { print "Version? --> "; chomp($version = ); } $version =~ s/[^0-9A-Za-z_.-]//g; $title = "SlimServer_v$version"; } if ($branchname) { $title = "SlimServer_" . $branchname . "_v$version"; $humantitle = "SlimServer $branchname $version"; } else { $title = "SlimServer_v$version"; $humantitle = "SlimServer $version"; } print "Okay, this is $humantitle\n"; print "Please don't forget to tag it in Subversion!\n"; $distdir = $title; if (-d $distdir) { print "Deleting original release dir: $distdir\n"; rmtree($distdir); } mkpath($distdir) or die "Problem: couldn't make $distdir!"; print "Made $distdir\n"; if ($checkout) { print "Checking out a copy of the source from Subversion on branch $branch...\n"; my $options = '--quiet --force --non-interactive'; if ($branch eq 'trunk') { system "svn export $options http://svn.slimdevices.com/repos/slim/$branch release"; } else { system "svn export $options http://svn.slimdevices.com/repos/slim/branches/$branch release"; } $source = './release'; } else { if ($update) { print "Updating from Subversion...\n"; system "svn update"; } $source = '.'; } $sourcecopy = "$distdir/$title"; print "Making copy of server source...\n"; system "cp -R $source/server $sourcecopy"; die "Problem: export of server files failed" unless (-d $sourcecopy); chmod 0755, "$sourcecopy/slimserver.pl"; print "Copying firmware files...\n"; mkpath("$sourcecopy/slimp3"); copy("$source/slimp3/updater/MAIN.HEX", "$sourcecopy/slimp3"); copy("$source/slimp3/updater/update_firmware.pl", "$sourcecopy/slimp3"); chmod 0755, "$sourcecopy/slimp3/update_firmware.pl"; die "Problem: copy of slimp3 firmware files failed" unless (-d "$sourcecopy/slimp3"); rmsvn($sourcecopy); # Don't bother with the tarball on Win32 or OSX if ($^O eq 'linux' || $^O eq 'solaris') { # make the tar file print "Making the tarball $title...\n"; # not everyone has GNUtar :( system "cd $distdir; tar --exclude MSWin32-x86-multi-thread -cf $title.tar $title; gzip -9 $title.tar"; print "tarball done...\n"; # make the tar file without the CPAN/arch dir - bug #755 print "Making the tarball $title.no-cpan-arch...\n"; # not everyone has GNUtar :( system "cd $distdir; tar --exclude arch --exclude Bin -cf $title.no-cpan-arch.tar $title; gzip -9 $title.no-cpan-arch.tar"; print "tarball done...\n"; } # run the build method for the OS. { no strict 'refs'; $osToBuildMap{$^O}(); } if ($snapshot) { # save away the snapshot image `mv $distdir ..`; } if ($checkout) { print "Deleting exported copy...\n"; rmtree($source); } } # make the OSX application sub buildOSXInstaller { print "Building MacOSX Project...\n"; # Remove files we won't ever use. removeDirectoriesNotMatching("$source/server/Bin", $^O); removeDirectoriesNotMatching("$source/server/CPAN/arch/5.6", $^O); removeDirectoriesNotMatching("$source/server/CPAN/arch/5.8", $^O); `cc $source/platforms/osx/openUp.c -o $source/platforms/osx/openUp`; my $osxdir = "$distdir/$humantitle"; mkpath("$osxdir/Install Files"); mkpath("$osxdir/Utilities"); `cd "$source/platforms/osx/Preference Pane"; rm -rf build; xcodebuild clean; xcodebuild -target "SlimServer" -buildstyle Deployment`; print "Copying Preference Pane...\n"; `ditto "$source/platforms/osx/Preference Pane/build/SlimServer.prefPane" "$osxdir/Install Files/SlimServer.prefPane"`; print "Copying MacOSX Installer...\n"; `ditto "$source/platforms/osx/Preference Pane/build/SlimServer Installer.app" "$osxdir/SlimServer Installer.app"`; print "Copying MacOSX SLIMP3 Firmware Updater...\n"; `ditto "$source/platforms/osx/Preference Pane/build/SLIMP3 Firmware Updater.app" "$osxdir/Utilities/SLIMP3 Firmware Updater.app"`; `cp -R "$source/platforms/osx/Getting Started.html" "$osxdir/Getting Started.html"`; `cat "$source/server/Changelog.html">> "$osxdir/Getting Started.html"`; `cp -R "$source/server/license.txt" "$osxdir/License.txt"`; rmsvn($osxdir); `hdiutil unmount "/Volumes/$humantitle"`; print "Building MacOSX DMG image...\n"; `hdiutil create -fs HFS+ -volname "$humantitle" -size 100m "$distdir/SlimServer.dmg"`; print "Mounting MacOSX DMG image...\n"; `hdiutil mount "$distdir/SlimServer.dmg"`; print "Copying MacOSX files...\n"; `ditto -rsrc -V "$osxdir" "/Volumes/$humantitle"`; print "Making auto open\n"; `$source/platforms/osx/openUp "/Volumes/$humantitle"`; print "Unmounting MacOSX DMG image...\n"; `hdiutil unmount "/Volumes/$humantitle"`; print "Converting MacOSX DMG image...\n"; `hdiutil convert -format UDZO "$distdir/SlimServer.dmg" -o "$distdir/$title.dmg"`; print "Removing old MacOSX DMG image...\n"; unlink("$distdir/SlimServer.dmg"); return 1; } sub buildWin32Installer { print "Building Windows directory...\n"; my $winserverdir = "build"; if (-d $winserverdir) { print "Deleting original win build dir: $winserverdir\n"; rmtree($winserverdir); } mkpath($winserverdir); # We don't need unixy bits. removeDirectoriesNotMatching("$source/server/Bin", 'MSWin32'); removeDirectoriesNotMatching("$source/server/CPAN/arch/5.8", 'MSWin32'); `cp -R $source/server "$winserverdir/server"`; `cp "$source/platforms/win32/Getting Started.html" "$winserverdir"`; `cp "$source/server/CHANGELOG.html" "$winserverdir/Release Notes.html"`; `cp -R "$source/server/license.txt" "$winserverdir/License.txt"`; print "Building Windows executable...\n"; print `devenv "$source/platforms/win32/SlimServer.sln" /rebuild Release`; `cp $source/platforms/win32/Release/SlimServer.exe "$winserverdir/SlimServer.exe"`; `cp $source/platforms/win32/psapi.dll "$winserverdir/psapi.dll"`; rmsvn($winserverdir); print "Building perlsvc executable for server...\n"; my $libpaths = join(';', "$perldir/lib", qw( . CPAN CPAN/arch/5.8/MSWin32-x86-multi-thread CPAN/arch/5.8/MSWin32-x86-multi-thread/auto )); print `cd $source/server; perlsvc --verbose --add Compress::Zlib --force slimserver.pl --lib ".;CPAN;CPAN/arch/5.8/MSWin32-x86-multi-thread"; cd ..`; move("$source/server/slimserver.exe", "$winserverdir/server/slim.exe"); print "Building perlapp executable for SLIMP3 upgrader...\n"; print `cd $source/slimp3/updater; perlapp --force update_firmware.pl; cd ..`; mkpath("$winserverdir/firmware"); move("$source/slimp3/updater/update_firmware.exe", "$winserverdir/firmware/SLIMP3 Updater.exe"); print "Copying firmware...\n"; copy("$source/slimp3/updater/MAIN.HEX", "$winserverdir/firmware/MAIN.HEX"); print "Making installer...\n"; copy("$source/platforms/win32/installer/SlimServer.iss", "$winserverdir"); copy("$source/platforms/win32/installer/slim.bmp", "$winserverdir"); print `"c:/Program Files/Inno Setup 4/ISCC.exe" "$winserverdir/SlimServer.iss"`; unlink("$winserverdir/SlimServer.iss"); unlink("$winserverdir/slim.bmp"); move($winserverdir, "$distdir/SlimServer for Windows"); $winserverdir = "$distdir/SlimServer for Windows"; move("$winserverdir/Output/SlimSetup.exe", "$distdir/SlimServer_v$version.exe"); rmtree("$winserverdir/Output"); # make the zip file, if we can system("which zip >/dev/null 2>&1"); # > 0 indicates failure...freaking shell if ($? >> 8) { print "zip not installed, skipping zipping...\n"; } else { # make the zip file print "Making the zip file...\n"; $title_perlscripts = $title . "_perlscripts"; `cd $distdir; zip -r $title.ZIP "SlimServer for Windows"`; `cd $distdir; zip -r $title_perlscripts.ZIP "$distdir"`; } } sub buildSysVPkg { print "Building Solaris package...\n"; system("which pkgmk >/dev/null 2>&1"); # > 0 indicates failure...freaking shell print "result " . $? . "\n"; if ($? >> 8) { print "pkgmk not detected on this system. Not making a Solaris package"; return; } removeDirectoriesNotMatching("$source/server/Bin", '(solaris|sunos)'); removeDirectoriesNotMatching("$source/server/CPAN/arch/5.6", '(solaris|sunos)'); removeDirectoriesNotMatching("$source/server/CPAN/arch/5.8", '(solaris|sunos)'); print "Making package...\n"; # setup the file structure for the package `$source/platforms/solaris/makeit.sh $distdir`; # someone make me pretty my $arch = `uname -p`; chomp($arch); $arch = $arch.`echo .`; chomp($arch); $arch = $arch.`uname -m`; #my $arch = `uname -p`; chomp($arch); open (READ, "$source/platforms/solaris/pkginfo.build") || die "Can't open pkginfo file to read: $!\n"; open (WRITE, ">$distdir/pkg/pkginfo") || die "Can't open pkginfo file to write: $!\n"; while () { s/_VERSION_/$version/; s/_SOURCE_/$title.tar.gz/; s/_TOPDIR_/$pwd\/$distdir\/rpm/; s/_SOURCEFILE_/$distdir/; s/_ARCH_/$arch/; print WRITE $_; } close WRITE; close READ; # TODO:Put in some logic to use either SUNWpl5u /usr/bin/perl # on Sol9 or SMCperl /usr/local/bin/perl on Sol8-7-6 # Do it `cd $distdir/pkg; pkgmk -r . -d ..`; `pkgtrans -s $pwd/$distdir $pwd/$distdir/$title.pkg Slim`; `gzip $distdir/$title.pkg`; rmtree("$distdir/Slim"); rmtree("$distdir/pkg"); } sub buildRPM { print "Building Linux RPM...\n"; # this must be a unix system # make the RPM if appropriate my $rpmversion = $version; $rpmversion =~ s/-/_/g; system("which rpmbuild >/dev/null 2>&1"); # > 0 indicates failure...freaking shell print "result " . $? . "\n"; if ($? >> 8) { print "rpmbuild not detected on this system. Not making an RPM"; return; } # remove bits that don't need to be in the RPM my $match = qr/(?:darwin|MSWin32|freebsd|openbsd|ppc-linux|powerpc-hardhat-linux|netbsd)/i; removeDirectoriesMatching("$source/server/Bin", $match); removeDirectoriesMatching("$source/server/CPAN/arch/5.6", $match); removeDirectoriesMatching("$source/server/CPAN/arch/5.8", $match); print "Making version $rpmversion RPM in $distdir..\n"; # make a destination dir for the RPM for my $path (qw(SPECS SOURCES BUILD RPMS SRPMS)) { mkpath("$distdir/rpm/$path"); } copy("$source/platforms/redhat/slimserver.config", "$distdir/rpm/SOURCES"); copy("$source/platforms/redhat/slimserver.init", "$distdir/rpm/SOURCES"); open (READ, "$source/platforms/redhat/slimserver.spec.build") || die "Can't open spec file to read: $!\n"; open (WRITE, ">$distdir/rpm/SPECS/slimserver.spec") || die "Can't open spec file to write: $!\n"; while () { s/_VERSION_/$rpmversion/; s/_SOURCE_/$title.tar.gz/; s/_TOPDIR_/$pwd\/$distdir\/rpm/; s/_SOURCEFILE_/$distdir/; print WRITE $_; } close WRITE; close READ; copy("$distdir/$title.tar.gz", "$distdir/rpm/SOURCES"); # Do it `rpmbuild -bb --define='_topdir $pwd/$distdir/rpm' $distdir/rpm/SPECS/slimserver.spec`; `cp $distdir/rpm/RPMS/noarch/slimserver-$rpmversion-*.noarch.rpm $distdir`; rmtree("$distdir/rpm"); } sub showUsage { print "makerelease.pl [--checkout] [--update] [--snapshot] [--version VERSION]\n"; } sub rmsvn { my $root = shift; print "Removing .svn directories from $root...\n"; system "find '$root' -name .svn -print0 | xargs -0 rm -r" || die; } sub removeDirectoriesMatching { _removeDirectories(@_); } sub removeDirectoriesNotMatching { _removeDirectories(@_, 'not'); } sub _removeDirectories { my $path = shift; my $match = shift; my $type = shift; # Remove files we won't ever use. opendir(DIR, $path) or die "Couldn't open directory: [$path] : $!\n"; while (my $dir = readdir(DIR)) { next if $dir =~ /\./; if ($type eq 'not') { next if $dir =~ /$match/; } else { next if $dir !~ /$match/; } print "Removing $path/$dir\n"; rmtree("$path/$dir"); } close DIR; } main(); __END__