--- /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;
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="build.xsl"?>
+<!-- <!DOCTYPE BUILD SYSTEM "ebs.dtd"> -->
+<!DOCTYPE Build [
+ <!ELEMENT Product (Commands)>
+ <!ATTLIST Product name CDATA #REQUIRED>
+ <!ELEMENT Commands (Execute+ | SetEnv*)>
+ <!ELEMENT Execute EMPTY>
+ <!ATTLIST Execute ID CDATA #REQUIRED>
+ <!ATTLIST Execute Stage CDATA #REQUIRED>
+ <!ATTLIST Execute Component CDATA #REQUIRED>
+ <!ATTLIST Execute Cwd CDATA #REQUIRED>
+ <!ATTLIST Execute CommandLine CDATA #REQUIRED>
+ <!ELEMENT SetEnv EMPTY>
+ <!ATTLIST SetEnv Order ID #REQUIRED>
+ <!ATTLIST SetEnv Name CDATA #REQUIRED>
+ <!ATTLIST SetEnv Value CDATA #REQUIRED>
+]>
+<Product name="zip">
+ <Commands>
+ <SetEnv Order="1" Name="PATH" Value="\\epoc32\\gcc\\bin;\\epoc32\\tools;%PATH%"/>
+EOT
+
+ my $order = 2;
+ foreach my $setenv (@{$self->{env}})
+ {
+ print EBSSCRIPT
+ "<SetEnv Order=\"$order\" Name=\"$setenv->{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
+ "<Execute ID=\"$id\" Stage=\"$stage_id\" Component=\"$component\" Cwd=\"$cwd\" CommandLine=\"$cmdline\"\/>\n";
+ $id++;
+ }
+ $stage_id++;
+ }
+ print EBSSCRIPT <<EOT;
+ </Commands>
+</Product>
+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<BuildJob|scripts::BuildJob> is a wrapper to call this module from the command line.
+
+=cut