use strict;
use Data::Dumper;
use File::Find;
use Cwd qw(realpath);
use English;
my @args = @ARGV;
$ENV{'LD_NO_CLASSSIC_LINKER'} = '1';
$ENV{'LD_NO_CLASSSIC_LINKER_STATIC'} = '1';
my $makefiles =
{
'makefile' => undef,
'Makefile' => undef,
};
my $find_opts =
{
'wanted' => \&find_callback,
};
my $keywords =
{
'root' => '',
'cwd' => '',
'cmd' => '',
'exit' => '',
'stdout' => [],
'stderr' => [],
};
my $max_concurrent_tests = $ENV{'LD_UNIT_TEST_CONCURRENCY'};
if (!defined $max_concurrent_tests) {
system("/bin/csh", "-c", "set n=`sysctl hw.ncpu`; exit \$n[2]");
if ($? == -1 || $? & 127) {
die("could not determine cpu count");
}
$max_concurrent_tests = $? >> 8;
}
my $keyword;
my $max_keyword_len = 0;
foreach $keyword (keys %$keywords)
{ if($max_keyword_len < length($keyword)) { $max_keyword_len = length($keyword); } }
my $delim = ':';
$max_keyword_len += length($delim) + length(' ');
my $last_keyword = '';
sub print_line
{
my ($file, $keyword, $val) = @_;
if(!exists($$keywords{$keyword}))
{
print STDERR "error: keyword $keyword not in \$keywords set\n";
exit(1);
}
my $keyword_len = 0;
if($keyword ne $last_keyword)
{
print($file "$keyword"); print($file $delim);
$keyword_len = length($keyword) + length($delim);
}
if($max_keyword_len > $keyword_len)
{
my $num_spaces = $max_keyword_len - $keyword_len;
print($file ' ' x $num_spaces);
}
print($file "$val");
if(0)
{
$last_keyword = $keyword;
}
}
my $root = '.';
$root = &realpath($root);
print_line(*STDOUT, "root", "$root\n");
my $running_test_count=0;
find($find_opts, $root);
while ( $running_test_count > 0 ) {
&reaper;
}
sub find_callback
{
if(exists($$makefiles{$_}))
{
my $makefile = $_;
my $reldir = $File::Find::dir;
$reldir =~ s|^$root/||;
my $cmd = [ "make" ];
my $arg; foreach $arg (@ARGV) { push @$cmd, $arg; }
$ENV{UNIT_TEST_NAME} = $reldir;
my $pid = fork();
if (not defined $pid) {
die "Couldn't fork"
}
elsif ($pid == 0) {
open(STDOUT, ">/tmp/unit-tests-stdout.$PID") || die("$!");
open(STDERR, ">/tmp/unit-tests-stderr.$PID") || die("$!");
exec 'make', @ARGV;
exit(-1); }
my $info;
open($info, ">/tmp/unit-tests-info.$pid") || die("$!");
&print_line($info, "cwd", "\$root/$reldir\n"); &print_line($info, "cmd", "@$cmd\n");
close($info) || die("$!");
$running_test_count++;
if ( $running_test_count == $max_concurrent_tests ) {
&reaper;
}
}
}
sub reaper {
if ( $running_test_count > 0 ) {
my $pid = wait;
if ( $pid == -1 ) {
die("no child\n");
}
my $exit = $?;
$running_test_count--;
open(INFO, "</tmp/unit-tests-info.$pid") || die("$!");
while(<INFO>)
{
print $_;
}
close(INFO) || die("$!");
unlink("/tmp/unit-tests-info.$pid");
&print_line(*STDOUT, "exit", "$exit\n");
open(OUT, "</tmp/unit-tests-stdout.$pid") || die("$!");
while(<OUT>)
{
&print_line(*STDOUT, "stdout", "$_");
}
close(OUT) || die("$!");
unlink("/tmp/unit-tests-stdout.$pid");
open(ERR, "</tmp/unit-tests-stderr.$pid") || die("$!");
while(<ERR>)
{
&print_line(*STDOUT, "stderr", "$_");
}
close(ERR) || die("$!");
unlink("/tmp/unit-tests-stderr.$pid");
}
}