This reduces the build scripts code duplication. A side-effect is that the status lines now all start with the 'Task:' prefix.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- testbot/bin/build/Build.pl | 89 +------- testbot/bin/build/Reconfig.pl | 113 +--------- testbot/bin/build/WineReconfig.pl | 247 ++------------------ testbot/bin/build/WineTest.pl | 111 +-------- testbot/lib/Build/Utils.pm | 363 ++++++++++++++++++++++++++++++ 5 files changed, 409 insertions(+), 514 deletions(-) create mode 100644 testbot/lib/Build/Utils.pm
diff --git a/testbot/bin/build/Build.pl b/testbot/bin/build/Build.pl index e1133aaee..7f94c8595 100755 --- a/testbot/bin/build/Build.pl +++ b/testbot/bin/build/Build.pl @@ -43,98 +43,23 @@ sub BEGIN } $::BuildEnv = 1; } -my $Name0 = $0; -$Name0 =~ s+^.*/++; -
+use Build::Utils; use WineTestBot::Config; -use WineTestBot::PatchUtils; use WineTestBot::Utils;
-# -# Logging and error handling helpers -# - -sub InfoMsg(@) -{ - print @_; -} - -sub LogMsg(@) -{ - print "Build: ", @_; -} - -sub Error(@) -{ - print STDERR "$Name0:error: ", @_; -} - - # # Build helpers #
-my $ncpus; -sub CountCPUs() -{ - if (open(my $fh, "<", "/proc/cpuinfo")) - { - # Linux - map { $ncpus++ if (/^processor/); } <$fh>; - close($fh); - } - $ncpus ||= 1; -} - -sub ApplyPatch($) -{ - my ($PatchFile) = @_; - - InfoMsg "Applying patch\n"; - system("cd '$DataDir/wine' && ". - "echo wine:HEAD=`git rev-parse HEAD` && ". - "set -x && ". - "git apply --verbose ". ShQuote($PatchFile) ." && ". - "git add -A"); - if ($? != 0) - { - LogMsg "Patch failed to apply\n"; - return undef; - } - - my $Impacts = GetPatchImpact($PatchFile, "nounits"); - if ($Impacts->{MakeMakefiles}) - { - InfoMsg "\nRunning make_makefiles\n"; - system("cd '$DataDir/wine' && set -x && ./tools/make_makefiles"); - if ($? != 0) - { - LogMsg "make_makefiles failed\n"; - return undef; - } - } - - if ($Impacts->{Autoconf} && !$Impacts->{HasConfigure}) - { - InfoMsg "\nRunning autoconf\n"; - system("cd '$DataDir/wine' && set -x && autoconf"); - if ($? != 0) - { - LogMsg "Autoconf failed\n"; - return undef; - } - } - - return $Impacts; -}
sub BuildNative() { InfoMsg "\nRebuilding native tools\n"; + my $CPUCount = GetCPUCount(); system("cd '$DataDir/build-native' && set -x && ". - "time make -j$ncpus __tooldeps__"); + "time make -j$CPUCount __tooldeps__"); if ($? != 0) { LogMsg "Rebuild of native tools failed\n"; @@ -160,8 +85,9 @@ sub BuildTestExecutables($$$) }
InfoMsg "\nBuilding the $Bits-bit test executable(s)\n"; + my $CPUCount = GetCPUCount(); system("cd '$DataDir/build-mingw$Bits' && set -x && ". - "time make -j$ncpus ". join(" ", sort @BuildDirs)); + "time make -j$CPUCount ". join(" ", sort @BuildDirs)); if ($? != 0) { LogMsg "Rebuild of $Bits-bit crossbuild failed\n"; @@ -262,6 +188,7 @@ if (!defined $Usage) } if (defined $Usage) { + my $Name0 = GetToolName(); if ($Usage) { Error "try '$Name0 --help' for more information\n"; @@ -292,9 +219,7 @@ if ($DataDir =~ /'/) # Run the builds #
-CountCPUs(); - -my $Impacts = ApplyPatch($PatchFile); +my $Impacts = ApplyPatch("wine", $PatchFile);
if (!$Impacts or ($Impacts->{WineBuild} and !BuildNative()) or diff --git a/testbot/bin/build/Reconfig.pl b/testbot/bin/build/Reconfig.pl index 4aada3242..36748d66e 100755 --- a/testbot/bin/build/Reconfig.pl +++ b/testbot/bin/build/Reconfig.pl @@ -39,112 +39,15 @@ sub BEGIN } $::BuildEnv = 1; } -my $Name0 = $0; -$Name0 =~ s+^.*/++; -
+use Build::Utils; use WineTestBot::Config; -use WineTestBot::PatchUtils; - - -# -# Logging and error handling helpers -# - -sub InfoMsg(@) -{ - print @_; -} - -sub LogMsg(@) -{ - print "Reconfig: ", @_; -} - -sub Error(@) -{ - print STDERR "$Name0:error: ", @_; -}
# # Build helpers #
-my $ncpus; -sub CountCPUs() -{ - if (open(my $fh, "<", "/proc/cpuinfo")) - { - # Linux - map { $ncpus++ if (/^processor/); } <$fh>; - close($fh); - } - $ncpus ||= 1; -} - -sub BuildTestAgentd() -{ - # If testagentd already exists it's likely already running - # so don't rebuild it. - if (! -x "$BinDir/build/testagentd") - { - InfoMsg "\nBuilding the native testagentd\n"; - system("cd '$::RootDir/src/testagentd' && set -x && ". - "time make -j$ncpus build"); - if ($? != 0) - { - LogMsg "Build testagentd failed\n"; - return !1; - } - } - - InfoMsg "\nRebuilding the Windows TestAgentd\n"; - system("cd '$::RootDir/src/testagentd' && set -x && ". - "time make -j$ncpus iso"); - if ($? != 0) - { - LogMsg "Build winetestbot.iso failed\n"; - return !1; - } - - return 1; -} - -sub BuildTestLauncher() -{ - InfoMsg "\nRebuilding TestLauncher\n"; - system("cd '$::RootDir/src/TestLauncher' && set -x && ". - "time make -j$ncpus"); - if ($? != 0) - { - LogMsg "Build TestLauncher failed\n"; - return !1; - } - - return 1; -} - -sub GitPull() -{ - InfoMsg "\nUpdating the Wine source\n"; - system("cd '$DataDir/wine' && git pull"); - if ($? != 0) - { - LogMsg "Git pull failed\n"; - return !1; - } - - my $ErrMessage = UpdateWineData("$DataDir/wine"); - if ($ErrMessage) - { - LogMsg "$ErrMessage\n"; - return !1; - } - - return 1; -} - sub BuildNative($) { my ($NoRm) = @_; @@ -153,10 +56,11 @@ sub BuildNative($)
# Rebuild from scratch to make sure cruft will not accumulate InfoMsg "\nRebuilding native tools\n"; + my $CPUCount = GetCPUCount(); system("cd '$DataDir/build-native' && set -x && ". ($NoRm ? "" : "rm -rf * && ") . "time ../wine/configure --enable-win64 --without-x --without-freetype --disable-winetest && ". - "time make -j$ncpus __tooldeps__"); + "time make -j$CPUCount __tooldeps__");
if ($? != 0) { @@ -176,11 +80,12 @@ sub BuildCross($$$)
# Rebuild from scratch to make sure cruft will not accumulate InfoMsg "\nRebuilding the $Bits-bit test executables\n"; + my $CPUCount = GetCPUCount(); my $Host = ($Bits == 64 ? "x86_64-w64-mingw32" : "i686-w64-mingw32"); system("cd '$DataDir/build-mingw$Bits' && set -x && ". ($NoRm ? "" : "rm -rf * && ") . "time ../wine/configure --host=$Host --with-wine-tools=../build-native --without-x --without-freetype --disable-winetest && ". - "time make -j$ncpus buildtests"); + "time make -j$CPUCount buildtests"); if ($? != 0) { LogMsg "Build cross ($Bits bits) failed\n"; @@ -271,6 +176,7 @@ if (!defined $Usage) } if (defined $Usage) { + my $Name0 = GetToolName(); if ($Usage) { Error "try '$Name0 --help' for more information\n"; @@ -308,10 +214,9 @@ if (! -d "$DataDir/staging" and ! mkdir "$DataDir/staging") # Run the builds #
-CountCPUs(); - -exit(1) if (!BuildTestAgentd() or !BuildTestLauncher()); -exit(1) if ($OptUpdate and !GitPull()); +exit(1) if (!BuildNativeTestAgentd() or !BuildWindowsTestAgentd()); +exit(1) if (!BuildTestLauncher()); +exit(1) if ($OptUpdate and !GitPull("wine")); exit(1) if ($OptBuild and !UpdateWineBuilds($Targets, $OptNoRm));
LogMsg "ok\n"; diff --git a/testbot/bin/build/WineReconfig.pl b/testbot/bin/build/WineReconfig.pl index 77722734c..b30ddd190 100755 --- a/testbot/bin/build/WineReconfig.pl +++ b/testbot/bin/build/WineReconfig.pl @@ -36,92 +36,15 @@ sub BEGIN } $::BuildEnv = 1; } -my $Name0 = $0; -$Name0 =~ s+^.*/++; - - -use Digest::SHA; -use File::Path;
+use Build::Utils; use WineTestBot::Config; -use WineTestBot::PatchUtils; - - -# -# Logging and error handling helpers -# - -sub InfoMsg(@) -{ - print @_; -} - -sub LogMsg(@) -{ - print "Reconfig: ", @_; -} - -sub Error(@) -{ - print STDERR "$Name0:error: ", @_; -}
# # Build helpers #
-my $ncpus; -sub CountCPUs() -{ - if (open(my $fh, "<", "/proc/cpuinfo")) - { - # Linux - map { $ncpus++ if (/^processor/); } <$fh>; - close($fh); - } - $ncpus ||= 1; -} - -sub BuildTestAgentd() -{ - # If testagentd already exists it's likely already running - # so don't rebuild it. - if (! -x "$BinDir/build/testagentd") - { - InfoMsg "\nBuilding the native testagentd\n"; - system("cd '$::RootDir/src/testagentd' && set -x && ". - "time make -j$ncpus build"); - if ($? != 0) - { - LogMsg "Build testagentd failed\n"; - return !1; - } - } - - return 1; -} - -sub GitPull() -{ - InfoMsg "\nUpdating the Wine source\n"; - system("cd '$DataDir/wine' && git pull"); - if ($? != 0) - { - LogMsg "Git pull failed\n"; - return !1; - } - - my $ErrMessage = UpdateWineData("$DataDir/wine"); - if ($ErrMessage) - { - LogMsg "$ErrMessage\n"; - return !1; - } - - return 1; -} - sub BuildWine($$$$) { my ($Targets, $NoRm, $Build, $Extras) = @_; @@ -132,10 +55,11 @@ sub BuildWine($$$$) # If $NoRm is not set, rebuild from scratch to make sure cruft will not # accumulate InfoMsg "\nRebuilding the $Build Wine\n"; + my $CPUCount = GetCPUCount(); system("cd '$DataDir/build-$Build' && set -x && ". ($NoRm ? "" : "rm -rf * && ") . "time ../wine/configure $Extras && ". - "time make -j$ncpus"); + "time make -j$CPUCount"); if ($? != 0) { LogMsg "The $Build build failed\n"; @@ -159,160 +83,30 @@ sub UpdateWineBuilds($$) # WinePrefix helpers #
-sub VerifyAddOn($$) -{ - my ($AddOn, $Arch) = @_; - - my $Sha256 = Digest::SHA->new(256); - eval { $Sha256->addfile("$DataDir/$AddOn->{name}/$AddOn->{filename}") }; - return "$@" if ($@); - - my $Checksum = $Sha256->hexdigest(); - return undef if ($Checksum eq $AddOn->{$Arch}); - return "Bad checksum for '$AddOn->{filename}'"; -} - -sub UpdateAddOn($$$) +sub UpdateWinePrefixes($) { - my ($AddOn, $Name, $Arch) = @_; + my ($Targets) = @_;
- if (!defined $AddOn) - { - LogMsg "Could not get information on the $Name addon\n"; - return 0; - } - if (!$AddOn->{version}) - { - LogMsg "Could not get the $Name version\n"; - return 0; - } - if (!$AddOn->{$Arch}) + # Set up brand new WinePrefixes ready for use for testing. + # This way we do it once instead of doing it for every test, thus saving + # time. Note that this requires using a different wineprefix for each build. + foreach my $Build ("win32", "wow64", "wow32") { - LogMsg "Could not get the $Name $Arch checksum\n"; - return 0; - } - - $AddOn->{filename} = "wine". ($Name eq "gecko" ? "_" : "-") . - "$Name-$AddOn->{version}". - ($Arch eq "" ? "" : "-$Arch") .".msi"; - return 1 if (!VerifyAddOn($AddOn, $Arch)); + next if (!$Targets->{$Build});
- InfoMsg "Downloading $AddOn->{filename}\n"; - mkdir "$DataDir/$Name"; - - my $Url="http://dl.winehq.org/wine/wine-$Name/$AddOn-%3E%7Bversion%7D/$AddOn-%3E%7Bfi..."; - for (1..3) - { - system("cd '$DataDir/$Name' && set -x && ". - "wget --no-verbose -O- '$Url' >'$AddOn->{filename}'"); - last if ($? == 0); - } - my $ErrMessage = VerifyAddOn($AddOn, $Arch); - return 1 if (!defined $ErrMessage); - LogMsg "$ErrMessage\n"; - return 0; -} - -sub UpdateAddOns() -{ - my %AddOns; - if (open(my $fh, "<", "$DataDir/wine/dlls/appwiz.cpl/addons.c")) - { - my $Arch = ""; - while (my $Line= <$fh>) + # Wait for the wineprefix creation to complete so it is really done + # before the snapshot gets updated. + SetupWineEnvironment($Build); + my $ErrMessage = CreateWinePrefix($Build, "wait"); + if (defined $ErrMessage) { - if ($Line =~ /^\s*#\s*define\s+ARCH_STRING\s+"([^"]+)"/) - { - $Arch = $1; - } - elsif ($Line =~ /^\s*#\s*define\s*(GECKO|MONO)_VERSION\s*"([^"]+)"/) - { - my ($AddOn, $Version) = ($1, $2); - $AddOn =~ tr/A-Z/a-z/; - $AddOns{$AddOn}->{name} = $AddOn; - $AddOns{$AddOn}->{version} = $Version; - } - elsif ($Line =~ /^\s*#\s*define\s*(GECKO|MONO)_SHA\s*"([^"]+)"/) - { - my ($AddOn, $Checksum) = ($1, $2); - $AddOn =~ tr/A-Z/a-z/; - $AddOns{$AddOn}->{$Arch} = $Checksum; - $Arch = ""; - } + LogMsg "$ErrMessage\n"; + return 0; } - close($fh); - } - else - { - LogMsg "Could not open 'wine/dlls/appwiz.cpl/addons.c': $!\n"; - return 0; - } - - return UpdateAddOn($AddOns{gecko}, "gecko", "x86") && - UpdateAddOn($AddOns{gecko}, "gecko", "x86_64") && - UpdateAddOn($AddOns{mono}, "mono", ""); -} - -# See also WineTest.pl -sub SetupWineEnvironment($) -{ - my ($Build) = @_; - - $ENV{WINEPREFIX} = "$DataDir/wineprefix-$Build"; - $ENV{DISPLAY} ||= ":0.0"; -} - -# See also WineTest.pl -sub RunWine($$$) -{ - my ($Build, $Cmd, $CmdArgs) = @_; - - my $Magic = `cd '$DataDir/build-$Build' && file $Cmd`; - my $Wine = ($Magic =~ /ELF 64/ ? "./wine64" : "./wine"); - return system("cd '$DataDir/build-$Build' && set -x && ". - "time $Wine $Cmd $CmdArgs"); -} - -# Setup a brand new WinePrefix ready for use for testing. -# This way we do it once instead of doing it for every test, thus saving -# time. Note that this requires using a different wineprefix for each build. -sub NewWinePrefix($$) -{ - my ($Targets, $Build) = @_; - - return 1 if (!$Targets->{$Build}); - - InfoMsg "\nRecreating the $Build wineprefix\n"; - SetupWineEnvironment($Build); - rmtree($ENV{WINEPREFIX}); - - # Crash dialogs cause delays so disable them - if (RunWine($Build, "./programs/reg/reg.exe.so", "ADD HKCU\\Software\\Wine\\WineDbg /v ShowCrashDialog /t REG_DWORD /d 0")) - { - LogMsg "Failed to disable the $Build build crash dialogs: $!\n"; - return 0; } - - # Ensure the WinePrefix has been fully created before updating the snapshot - system("cd '$DataDir/build-$Build' && ./server/wineserver -w"); - return 1; }
-sub UpdateWinePrefixes($) -{ - my ($Targets) = @_; - - return NewWinePrefix($Targets, "win32") && - # The wow32 and wow64 wineprefixes: - # - Are essentially identical. - # - Must be created after both WoW builds have been updated. - # - Make it possible to run the wow32 and wow64 tests in separate - # prefixes, thus ensuring they don't interfere with each other. - NewWinePrefix($Targets, "wow64") && - NewWinePrefix($Targets, "wow32"); -} -
# # Setup and command line processing @@ -393,6 +187,7 @@ if (!defined $Usage) } if (defined $Usage) { + my $Name0 = GetToolName(); if ($Usage) { Error "try '$Name0 --help' for more information\n"; @@ -436,10 +231,8 @@ if ($DataDir =~ /'/) # Run the builds and/or tests #
-CountCPUs(); - -exit(1) if (!BuildTestAgentd()); -exit(1) if ($OptUpdate and !GitPull()); +exit(1) if (!BuildNativeTestAgentd()); +exit(1) if ($OptUpdate and !GitPull("wine")); exit(1) if ($OptAddOns and !UpdateAddOns()); exit(1) if ($OptBuild and !UpdateWineBuilds($Targets, $OptNoRm)); exit(1) if ($OptWinePrefix and !UpdateWinePrefixes($Targets)); diff --git a/testbot/bin/build/WineTest.pl b/testbot/bin/build/WineTest.pl index b29440e21..9c264b485 100755 --- a/testbot/bin/build/WineTest.pl +++ b/testbot/bin/build/WineTest.pl @@ -40,93 +40,16 @@ sub BEGIN } $::BuildEnv = 1; } -my $Name0 = $0; -$Name0 =~ s+^.*/++; -
+use Build::Utils; use WineTestBot::Config; -use WineTestBot::PatchUtils; use WineTestBot::Utils;
-# -# Logging and error handling helpers -# - -sub InfoMsg(@) -{ - print @_; -} - -sub LogMsg(@) -{ - print "Task: ", @_; -} - -sub Error(@) -{ - print STDERR "$Name0:error: ", @_; -} - - # # Build helpers #
-my $ncpus; -sub CountCPUs() -{ - if (open(my $fh, "<", "/proc/cpuinfo")) - { - # Linux - map { $ncpus++ if (/^processor/); } <$fh>; - close($fh); - } - $ncpus ||= 1; -} - -sub ApplyPatch($) -{ - my ($PatchFile) = @_; - - InfoMsg "Applying patch\n"; - system("cd '$DataDir/wine' && ". - "echo wine:HEAD=`git rev-parse HEAD` && ". - "set -x && ". - "git apply --verbose ". ShQuote($PatchFile) ." && ". - "git add -A"); - if ($? != 0) - { - LogMsg "Patch failed to apply\n"; - return undef; - } - - my $Impacts = GetPatchImpact($PatchFile, "nounits"); - if ($Impacts->{MakeMakefiles}) - { - InfoMsg "\nRunning make_makefiles\n"; - system("cd '$DataDir/wine' && set -x && ./tools/make_makefiles"); - if ($? != 0) - { - LogMsg "make_makefiles failed\n"; - return undef; - } - } - - if ($Impacts->{Autoconf} && !$Impacts->{HasConfigure}) - { - InfoMsg "\nRunning autoconf\n"; - system("cd '$DataDir/wine' && set -x && autoconf"); - if ($? != 0) - { - LogMsg "Autoconf failed\n"; - return undef; - } - } - - return $Impacts; -} - sub BuildWine($$) { my ($Targets, $Build) = @_; @@ -134,8 +57,9 @@ sub BuildWine($$) return 1 if (!$Targets->{$Build});
InfoMsg "\nRebuilding the $Build Wine\n"; + my $CPUCount = GetCPUCount(); system("cd '$DataDir/build-$Build' && set -x && ". - "time make -j$ncpus"); + "time make -j$CPUCount"); if ($? != 0) { LogMsg "The $Build build failed\n"; @@ -150,25 +74,6 @@ sub BuildWine($$) # Test helpers #
-# See also WineReconfig.pl -sub SetupWineEnvironment($) -{ - my ($Build) = @_; - - $ENV{WINEPREFIX} = "$DataDir/wineprefix-$Build"; - $ENV{DISPLAY} ||= ":0.0"; -} - -# See also WineReconfig.pl -sub RunWine($$$) -{ - my ($Build, $Cmd, $CmdArgs) = @_; - - my $Magic = `cd '$DataDir/build-$Build' && file $Cmd`; - my $Wine = ($Magic =~ /ELF 64/ ? "./wine64" : "./wine"); - return system("cd '$DataDir/build-$Build' && set -x && ". - "time $Wine $Cmd $CmdArgs"); -}
sub DailyWineTest($$$$$) { @@ -330,6 +235,12 @@ if (!defined $Usage) } if (defined $Usage) { + my $Name0 = GetToolName(); + if ($Usage) + { + Error "try '$Name0 --help' for more information\n"; + exit $Usage; + } print "Usage: $Name0 [--help] --testpatch TARGETS PATCH\n"; print "or $Name0 [--help] --winetest [--no-submit] TARGETS BASETAG ARGS\n"; print "\n"; @@ -365,11 +276,9 @@ if ($DataDir =~ /'/) # Clean up old reports map { unlink("$_.report") } keys %AllTargets;
-CountCPUs(); - if ($Action eq "testpatch") { - my $Impacts = ApplyPatch($FileName); + my $Impacts = ApplyPatch("wine", $FileName); exit(1) if (!$Impacts or !BuildWine($Targets, "win32") or !BuildWine($Targets, "wow64") or diff --git a/testbot/lib/Build/Utils.pm b/testbot/lib/Build/Utils.pm new file mode 100644 index 000000000..038c188f2 --- /dev/null +++ b/testbot/lib/Build/Utils.pm @@ -0,0 +1,363 @@ +# -*- Mode: Perl; perl-indent-level: 2; indent-tabs-mode: nil -*- +# Copyright 2018 Francois Gouget +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +use strict; + +package Build::Utils; + +=head1 NAME + +Build::Utils - Utility functions for the build scripts + +=cut + +use Exporter 'import'; +our @EXPORT = qw(GetToolName InfoMsg LogMsg Error + GitPull ApplyPatch + GetCPUCount BuildNativeTestAgentd BuildWindowsTestAgentd + BuildTestLauncher UpdateAddOns + SetupWineEnvironment RunWine CreateWinePrefix); + +use Digest::SHA; +use File::Path; + +use WineTestBot::Config; +use WineTestBot::PatchUtils; +use WineTestBot::Utils; + + +# +# Logging and error handling +# + +my $Name0 = $0; +$Name0 =~ s+^.*/++; + +sub GetToolName() +{ + return $Name0; +} + +sub InfoMsg(@) +{ + print @_; +} + +sub LogMsg(@) +{ + print "Task: ", @_; +} + +sub Error(@) +{ + print STDERR "$Name0:error: ", @_; +} + + +# +# Repository updates +# + +sub GitPull($) +{ + my ($Dir) = @_; + + InfoMsg "\nUpdating the $Dir source\n"; + system("cd '$DataDir/$Dir' && git pull"); + if ($? != 0) + { + LogMsg "Git pull failed\n"; + return !1; + } + + if ($Dir eq "wine") + { + my $ErrMessage = UpdateWineData("$DataDir/$Dir"); + if ($ErrMessage) + { + LogMsg "$ErrMessage\n"; + return !1; + } + } + + return 1; +} + +sub ApplyPatch($$) +{ + my ($Dir, $PatchFile) = @_; + + InfoMsg "Applying patch\n"; + system("cd '$DataDir/$Dir' && ". + "echo $Dir:HEAD=`git rev-parse HEAD` && ". + "set -x && ". + "git apply --verbose ". ShQuote($PatchFile) ." && ". + "git add -A"); + if ($? != 0) + { + LogMsg "Patch failed to apply\n"; + return undef; + } + + my $Impacts = GetPatchImpact($PatchFile, "nounits"); + if ($Impacts->{MakeMakefiles}) + { + InfoMsg "\nRunning make_makefiles\n"; + system("cd '$DataDir/$Dir' && set -x && ./tools/make_makefiles"); + if ($? != 0) + { + LogMsg "make_makefiles failed\n"; + return undef; + } + } + + if ($Impacts->{Autoconf} && !$Impacts->{HasConfigure}) + { + InfoMsg "\nRunning autoconf\n"; + system("cd '$DataDir/$Dir' && set -x && autoconf"); + if ($? != 0) + { + LogMsg "Autoconf failed\n"; + return undef; + } + } + + return $Impacts; +} + + +# +# Build helpers +# + +my $_CPUCount; + +sub GetCPUCount() +{ + if (!defined $_CPUCount) + { + if (open(my $Fh, "<", "/proc/cpuinfo")) + { + # Linux + map { $_CPUCount++ if (/^processor/); } <$Fh>; + close($Fh); + } + $_CPUCount ||= 1; + } + return $_CPUCount; +} + +sub BuildNativeTestAgentd() +{ + # If testagentd already exists it's likely already running + # so don't rebuild it. + return 1 if (-x "$BinDir/build/testagentd"); + + InfoMsg "\nBuilding the native testagentd\n"; + my $CPUCount = GetCPUCount(); + system("cd '$::RootDir/src/testagentd' && set -x && ". + "time make -j$CPUCount build"); + if ($? != 0) + { + LogMsg "Build testagentd failed\n"; + return !1; + } + + return 1; +} + +sub BuildWindowsTestAgentd() +{ + InfoMsg "\nRebuilding the Windows TestAgentd\n"; + my $CPUCount = GetCPUCount(); + system("cd '$::RootDir/src/testagentd' && set -x && ". + "time make -j$CPUCount iso"); + if ($? != 0) + { + LogMsg "Build winetestbot.iso failed\n"; + return !1; + } + + return 1; +} + +sub BuildTestLauncher() +{ + InfoMsg "\nRebuilding TestLauncher\n"; + my $CPUCount = GetCPUCount(); + system("cd '$::RootDir/src/TestLauncher' && set -x && ". + "time make -j$CPUCount"); + if ($? != 0) + { + LogMsg "Build TestLauncher failed\n"; + return !1; + } + + return 1; +} + + +# +# Wine addons updates +# + +sub _VerifyAddOn($$) +{ + my ($AddOn, $Arch) = @_; + + my $Sha256 = Digest::SHA->new(256); + eval { $Sha256->addfile("$DataDir/$AddOn->{name}/$AddOn->{filename}") }; + return "$@" if ($@); + + my $Checksum = $Sha256->hexdigest(); + return undef if ($Checksum eq $AddOn->{$Arch}); + return "Bad checksum for '$AddOn->{filename}'"; +} + +sub _UpdateAddOn($$$) +{ + my ($AddOn, $Name, $Arch) = @_; + + if (!defined $AddOn) + { + LogMsg "Could not get information on the $Name addon\n"; + return 0; + } + if (!$AddOn->{version}) + { + LogMsg "Could not get the $Name version\n"; + return 0; + } + if (!$AddOn->{$Arch}) + { + LogMsg "Could not get the $Name $Arch checksum\n"; + return 0; + } + + $AddOn->{filename} = "wine". ($Name eq "gecko" ? "_" : "-") . + "$Name-$AddOn->{version}". + ($Arch eq "" ? "" : "-$Arch") .".msi"; + return 1 if (!_VerifyAddOn($AddOn, $Arch)); + + InfoMsg "Downloading $AddOn->{filename}\n"; + mkdir "$DataDir/$Name"; + + my $Url="http://dl.winehq.org/wine/wine-$Name/$AddOn-%3E%7Bversion%7D/$AddOn-%3E%7Bfi..."; + for (1..3) + { + system("cd '$DataDir/$Name' && set -x && ". + "wget --no-verbose -O- '$Url' >'$AddOn->{filename}'"); + last if ($? == 0); + } + my $ErrMessage = _VerifyAddOn($AddOn, $Arch); + return 1 if (!defined $ErrMessage); + LogMsg "$ErrMessage\n"; + return 0; +} + +sub UpdateAddOns() +{ + my %AddOns; + if (open(my $fh, "<", "$DataDir/wine/dlls/appwiz.cpl/addons.c")) + { + my $Arch = ""; + while (my $Line= <$fh>) + { + if ($Line =~ /^\s*#\s*define\s+ARCH_STRING\s+"([^"]+)"/) + { + $Arch = $1; + } + elsif ($Line =~ /^\s*#\s*define\s*(GECKO|MONO)_VERSION\s*"([^"]+)"/) + { + my ($AddOn, $Version) = ($1, $2); + $AddOn =~ tr/A-Z/a-z/; + $AddOns{$AddOn}->{name} = $AddOn; + $AddOns{$AddOn}->{version} = $Version; + } + elsif ($Line =~ /^\s*#\s*define\s*(GECKO|MONO)_SHA\s*"([^"]+)"/) + { + my ($AddOn, $Checksum) = ($1, $2); + $AddOn =~ tr/A-Z/a-z/; + $AddOns{$AddOn}->{$Arch} = $Checksum; + $Arch = ""; + } + } + close($fh); + } + else + { + LogMsg "Could not open 'wine/dlls/appwiz.cpl/addons.c': $!\n"; + return 0; + } + + return _UpdateAddOn($AddOns{gecko}, "gecko", "x86") && + _UpdateAddOn($AddOns{gecko}, "gecko", "x86_64") && + _UpdateAddOn($AddOns{mono}, "mono", ""); +} + + +# +# Wine helpers +# + +sub SetupWineEnvironment($) +{ + my ($Build) = @_; + + $ENV{WINEPREFIX} = "$DataDir/wineprefix-$Build"; + $ENV{DISPLAY} ||= ":0.0"; +} + +sub RunWine($$$) +{ + my ($Build, $Cmd, $CmdArgs) = @_; + + my $Magic = `cd '$DataDir/build-$Build' && file $Cmd`; + my $Wine = ($Magic =~ /ELF 64/ ? "./wine64" : "./wine"); + return system("cd '$DataDir/build-$Build' && set -x && ". + "time $Wine $Cmd $CmdArgs"); +} + + +# +# WinePrefix helpers +# + +sub CreateWinePrefix($$) +{ + my ($Build, $Wait) = @_; + + return "$WINEPREFIX is not set!" if (!$ENV{WINEPREFIX}); + rmtree($ENV{WINEPREFIX}); + + # Crash dialogs cause delays so disable them + if (RunWine($Build, "./programs/reg/reg.exe.so", "ADD HKCU\\Software\\Wine\\WineDbg /v ShowCrashDialog /t REG_DWORD /d 0")) + { + return "Failed to disable the $Build build crash dialogs: $!"; + } + + if ($Wait) + { + # Ensure the WinePrefix has been fully created and the registry files + # saved before returning. + system("cd '$DataDir/build-$Build' && ./server/wineserver -w"); + } + + return undef; +} + +1;