diff -r 044383f39525 -r be27ed110b50 buildframework/helium/tools/common/packages/BuildJob.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buildframework/helium/tools/common/packages/BuildJob.pm Wed Oct 28 14:39:48 2009 +0000 @@ -0,0 +1,294 @@ +# +# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of the License "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# +#!perl -w +# ============================================================================== +# %name: BuildJob.pm % +# Part of: Juno Build Tools +# Requires: Symbian OS build tools +# +# %derived_by: hasegawa % +# %version: to1r1103#4.1.2 % +# %date_modified: Thu Oct 5 15:41:26 2006 % +# +# See POD text at the end of this file for usage and other details. +# ============================================================================== + +package BuildJob; +use strict; +use warnings; +use Win32::Job; +use Config; +use Exporter; + +our @ISA = qw(Exporter); +our @EXPORT_OK = qw(EBS_PORT EBS_DIR EBS_CLIENT EBS_SERVER); + +our $EPOCROOT = $ENV{EPOCROOT} || "\\"; +our $BUILD_DRIVE = $ENV{BUILD_DRIVE}; + +my @EBS_PATHS = ("epoc32\\tools\\build", "src\\common\\generic\\tools\\build"); + +$BuildJob::EBS_PORT = 1973; +$BuildJob::EBS_DIR = ""; +$BuildJob::EBS_CLIENT = "buildclient.pl"; +$BuildJob::EBS_SERVER = "buildserver.pl"; + +sub find_ebs +{ + return 1 if -d "$BuildJob::EBS_DIR\\$BuildJob::EBS_CLIENT"; + foreach (map("${BuildJob::BUILD_DRIVE}${BuildJob::EPOCROOT}$_", @EBS_PATHS)) + { + $BuildJob::EBS_DIR = $_ and return 1 if -f "$_\\$BuildJob::EBS_CLIENT"; + } + return 0; +} + +sub run +{ + my $data_source = shift; + return 0 unless ($data_source and -e $data_source); + + # finding free port. + my $offset = 0; + my $trials = 10; + $BuildJob::EBS_PORT = $BuildJob::EBS_PORT + int(rand(1000)); + for(;$offset < $trials; $offset++) { + if (!is_buildjob_running($BuildJob::EBS_PORT + $offset)) { + $BuildJob::EBS_PORT = $BuildJob::EBS_PORT + $offset; + last; + } + } + warn("Can't start build job, is one already running?\n") and return 0 if ($offset > $trials); + print "Using port: $BuildJob::EBS_PORT\n"; + + my $log_file = shift; + $log_file = "build.log" unless $log_file; + my $num_clients = shift; + + # default number of clients is the number of processors + $num_clients = $ENV{NUMBER_OF_PROCESSORS} unless ($num_clients); + + # if we can't find the number of processors, just run one client + $num_clients = 1 unless ($num_clients); + + find_ebs() + or die("Can't find EBS scripts; looked in: " + . join(",", map("${BuildJob::EPOCROOT}$_", @EBS_PATHS))); + + my $job = Win32::Job->new(); + for (my $i = 0; $i < $num_clients; $i++) + { + $job->spawn( + $Config{perlpath}, + "perl $BuildJob::EBS_DIR\\$BuildJob::EBS_CLIENT -d localhost:$BuildJob::EBS_PORT -w 2 -c EBS_CLIENT$i", + {new_console => 1, window_attr => 'minimized'}); + } + my $server_pid = $job->spawn($Config{perlpath}, + "perl $BuildJob::EBS_DIR\\$BuildJob::EBS_SERVER -d $data_source -p $BuildJob::EBS_PORT -l $log_file" + ); + + my $job_failure = 0; + { + # kill the job if we receive a sigint + local $SIG{INT} = sub {$job->kill();}; + + # start job with no timeout (a null watchdog run every 60s) + # and complete when the first process terminates + $job_failure = !$job->watch(sub {return 0}, 60, 0); + } + + my $job_status = $job->status(); + $job_failure ||= ($job_status->{$server_pid}{exitcode} != 0); + + if ($job_failure) + { + print(STDERR "Abnormal job termination:\nProcess\tExit Code\n"); + foreach my $pid (keys %$job_status) + { + print( STDERR (($pid == $server_pid) ? "server" : "client") . "\t" + . $job_status->{$pid}{exitcode} + . "\n"); + } + } + return !$job_failure; +} + +sub is_buildjob_running +{ + my $port = shift; + use IO::Socket::INET; + + # try to open a socket on the build server port + my $sock = + IO::Socket::INET->new(LocalAddr => '127.0.0.1', + LocalPort => $port, + Proto => 'tcp', + Timeout => 2); + + # failure means the server is probably running already + my $is_port_available = !defined $sock; + $sock->close() if $sock; + return $is_port_available; +} + +sub new +{ + my $invocant = shift; + my $name = shift; + my $class = ref($invocant) || $invocant; + my $self = {name => $name, stages => [], env => []}; + bless($self, $class); + $self->new_stage(); + return $self; +} + +sub set +{ + my $self = shift; + my $var = shift; + my $value = shift; + + push(@{$self->{env}}, + {name => $var, + value => $value}); +} + +sub add +{ + my $self = shift; + push(@{$self->{stages}->[0]}, shift); +} + +sub new_stage +{ + my $self = shift; + unshift(@{$self->{stages}}, []); +} + +sub go +{ + my $self = shift; + my $logfile = shift; + my $scriptfile = $self->{name} . ".xml"; + + open(EBSSCRIPT, ">$scriptfile") or die("Can't open $scriptfile: $!"); + print EBSSCRIPT < + + + + + + + + + + + + + + + +]> + + + +EOT + + my $order = 2; + foreach my $setenv (@{$self->{env}}) + { + print EBSSCRIPT + "{name}\" Value=\"$setenv->{value}\"/>\n"; + $order++; + } + + my $id = 1; + my $stage_id = 1; + foreach my $stage (reverse @{$self->{stages}}) + { + foreach my $cmd (@{$stage}) + { + my $cmdline; + $cmdline = $cmd->{commandline} if exists $cmd->{commandline}; + die("Undefined command line") unless $cmdline; + my $cwd = "\\"; + $cwd = $cmd->{cwd} if exists $cmd->{cwd}; + my $component = $id; + $component = $cmd->{component} if exists $cmd->{component}; + + print EBSSCRIPT + "\n"; + $id++; + } + $stage_id++; + } + print EBSSCRIPT < + +EOT + close(EBSSCRIPT); + + my $status = run($scriptfile, $logfile); + unlink($scriptfile); + return $status; +} + +1; + +__END__ + +=head1 NAME + +BuildJob - Run BuildServer and BuildClients + +=head1 SYNOPSIS + + use BuildJob; + + BuildJob::run($data_source, $num_clients, $log_file); + +=head1 DESCRIPTION + +BuildJob runs a number of BuildClients and the BuildServer with the +specified data source and log file. If undefined, the number of +clients defaults to the number of processors on the system and the log +file name defaults to "build.log" in the current working directory. + +Any errors are communicated by a nonzero return code. + +BuildJob uses port 1973 for communications and looks for the build +client and server scripts "buildclient.pl" and "buildserver.pl" in +"\src\common\generic\tools\build". Change these defaults by setting +the following variables prior to calling "run": + + $EBS_PORT = 1973; + $EBS_DIR = "\\src\\common\\generic\\tools\\build"; + $EBS_CLIENT = "buildclient.pl"; + $EBS_SERVER = "buildserver.pl"; + +This module uses Win32::Job to start and stop the clients and server. + +If a BuildJob attempts to run on a system that is already running one +on the same EBS_PORT, the job will not be run and the original job +will continue unaffected. + +=head1 SEE ALSO + +L is a wrapper to call this module from the command line. + +=cut