This is a method for using CruiseControl with a dynamically generated config.spec that time qualifies a dyanamic clearcase view.
- Using Clearcase Labels
- Create a config.spec Template
- Install Perl
- Install the Perl Script
- Config.xml Target
- Sample Project
Using Clearcase Labels
We use "add to build" (ADD-TO-project) and "steady state" (project-SS) labels to choose which files are included in the build instead of relying on LATEST. This permits us to add files to the VOB incrementally during development, then label them when ready. As such, our config.spec uses several "element * LABEL" selectors. To prevent having files change in our dynamic view during a build, we create a config.spec that uses the "-time" qualifier for all the elements.
Create a config.spec Template
First save a copy of your config.spec to WORK_DIR as config.spec.template. This will be used by the following perl script that adds the time qualifier using CruiseControl's cctimestamp property. For example:
element * ADD-TO-SPITFIRE
element * SPITFIRE-SS
will be changed to:
element * ADD-TO-SPITFIRE -time 10-Aug-2004.16:30:00
element * SPITFIRE-SS -time 10-Aug-2004.16:30:00
Install Perl
First you will need to install the latest version of ActivePerl. I recommend letting the install set up the file association
Install the Perl Script
Now here's the perl script that should be saved in your WORK_DIR:
#!/usr/bin/perl -w
use strict;
use Getopt::Long;
use POSIX qw(strftime);
my %config;
read_cmdline_args(); # read in any cmd line args
process( %config ); # process the config.spec
exit 0; # terminate execution
##############################################################
# help message
sub help {
print <<END_HELP;
genConfigSpec.pl - Generate a dynamic config.spec for a clearcase view.
usage:
genConfigSpec.pl {--time yyyymmddhhmmss --template filename --output filename}|{--help}
where:
--time yyyymmddhhmmss The date and time to qualify all the elements
in the config.spec template with.
--template filename A config.spec to use as a template
--output filename The file to write the generate ouput to.
--help Display this message.
END_HELP
exit 0;
}
##############################################################
# Read the command line args and update the %config hash
sub read_cmdline_args {
$config{'debug-level'} = 1;
GetOptions( \%config, 'time=i', 'template=s', 'output=s', 'help' );
my $invalid = 0;
$invalid++, logError("Missing \"--time yyyymmddhhmmss\" parameter")
unless exists $config{'time'};
$invalid++, logError("Missing \"--template filename\" parameter")
unless exists $config{'template'};
$invalid++, logError("Missing \"--output filename\" parameter")
unless exists $config{'output'};
help() if exists $config{'help'} || $invalid;
return %config;
}
##############################################################
# process
sub process
{
my(%config) = @_;
my $time = formatTime($config{'time'});
logDebug("config.spec time qualified to $time");
open(IN, "<$config{'template'}") or
die "Unable to open template file: $config{'template'}: $!\n";
open(OUT, ">$config{'output'}") or
die "Unable to open output file: $config{'output'}: $!\n";
while(<IN>) {
s/^(\s*element.*)$/$1 -time $time/;
print OUT;
}
close OUT;
close IN;
}
##############################################################
# formatTime(yyyymmddhhmmss)
sub formatTime {
my $inTime = shift;
unless( $inTime =~ /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/ ) {
logError("Invalid time string: $inTime");
help();
}
return strftime("%d-%b-%Y.%H:%M:%S", $6, $5, $4, $3, ($2-1), ($1-1900));
}
##############################################################
# debug print statement
sub logDebug {
my $str = shift;
if($config{'debug-level'} > 0) {
print "$str\n";
}
}
##############################################################
# debug print statement
sub logError {
my $str = shift;
print "$str\n";
}
Config.xml Target
Here's the checkout target for the delegating Ant build.xml that dynamically generates and sets the config.spec:
<property name="view.root" value="z:\"/>
<property name="view.tag" value="my_view"/>
<property name="project.root" value="z:\project"/>
<property name="clearcase.log.dir" value="${basedir}\logs\clearcase"/>
<property name="clearcase.log" value="${basedir}\logs\clearcase\log.log"/>
<property name="config.spec.dir" value="${basedir}"/>
<property name="config.spec.filename" value="${config.spec.dir}\config.spec"/>
<property name="config.spec.template" value="${config.spec.dir}\config.spec.template"/>
<property name="perl" value="perl"/>
<property name="genConfigSpec.script" value="genConfigSpec.pl"/>
<target name="checkout" description="Update package from ClearCase">
<echo message="Cleaning ${clearcase.log.dir}"/>
<delete dir="${clearcase.log.dir}"/>
<mkdir dir="${clearcase.log.dir}"/>
<delete file="${config.spec.filename}"/>
<echo message="Generate ${config.spec.filename}"/>
<exec dir="${config.spec.dir}" executable="${perl}" failonerror="true">
<arg line="${genConfigSpec.script} -time ${cctimestamp} -template ${config.spec.template}
-output ${config.spec.filename}"/>
</exec>
<echo message="Set ${config.spec.filename}"/>
<exec dir="Z:\" executable="C:\Program Files\ClearCase\bin\cleartool.exe" failonerror="true">
<arg line="setcs -tag ${view.tag} ${config.spec.filename}"/>
</exec>
<echo message="config.spec set for view"/>
</target>
Sample Project
Now let's put it together in a sample project where:
- dynamic view tag = spitfire_view
- view share = Z:\
- project = Z:\spitfire
- java Ant build script = Z:\spitfire\java\build.xml
- working directory = D:\build\cruisecontrol
- CruiseControl config file = D:\build\cruisecontrol\config.xml
- delegating Ant build script = D:\build\cruisecontrol\build-spitfire.xml
- config.spec template file = D:\build\cruisecontrol\config.spec.template
- dynamic config.spec generating script = D:\build\cruisecontrol\genConfigSpec.pl
<crusecontrol>
<project name="jspitfire" buildafterfailed="true">
<bootstrappers>
<currentbuildstatusbootstrapper file="d:\build\cruisecontrol\logs\spitfire\buildstatus.txt"/>
</bootstrappers>
<modificationset requiremodification="true" quietperiod="600">
<clearcase branch="spitfire-dev" viewpath="Z:\spitfire" recursive="true"/>
</modificationset>
<schedule interval="3600">
<ant antscript="D:\java\apache-ant-1.6.2\bin\ant.bat"
uselogger="true"
usedebug="false"
buildfile="d:\build\cruisecontrol\build-spitfire.xml"
target="masterbuild"/>
</schedule>
<log dir="d:\build\cruisecontrol\logs\spitfire">
<merge dir="Z:\spitfire\java\reports\tests"/>
<merge dir="Z:\spitfire\java\reports\metrics"/>
</log>
<publishers>
<currentbuildstatuspublisher file="d:\build\cruisecontrol\logs\spitfire\buildstatus.txt"/>
<artifactspublisher dir="Z:\spitfire\java\reports" dest="d:\build\cruisecontrol\artifacts\spitfire"/>
<htmlemail mailhost="smtp.your.domain"
returnaddress="dev-team@your.domain"
buildresultsurl="http://build.machine:8080/cruisecontrol/buildresults/spitfire"
skipusers="true"
spamwhilebroken="true"
subjectprefix="Build:"
logdir="D:\build\cruisecontrol\logs\spitfire"
xsldir="D:\java\cruisecontrol-2.1.6\reporting\jsp\xsl"
css="D:\java\cruisecontrol-2.1.6\reporting\jsp\css\cruisecontrol.css">
<always address="admin@your.domain"/>
</htmlemail>
</publishers>
<labelincrementer defaultLabel="spitfire.1"/>
</project>
</crusecontrol>
- and the delegating ant build script:
<project name="cruisecontrol driver for spitfire" default="masterbuild" basedir="d:\build\cruisecontrol">
<property name="view.root" value="z:\"/>
<property name="project.root" value="z:\spitfire\java"/>
<property name="clearcase.log.dir" value="${basedir}\logs\clearcase"/>
<property name="clearcase.log" value="${basedir}\logs\clearcase\log.log"/>
<property name="config.spec.dir" value="${basedir}"/>
<property name="config.spec.filename" value="${config.spec.dir}\config.spec"/>
<property name="config.spec.template" value="${config.spec.dir}\config.spec.template"/>
<property name="perl" value="perl"/>
<property name="genConfigSpec.script" value="genConfigSpec.pl"/>
<target name="masterbuild" depends="checkout,build,label">
<echo message="build-spitfire Target: masterbuild"/>
</target>
<target name="checkout" description="Update package from ClearCase">
<echo message="Cleaning ${clearcase.log.dir}"/>
<delete dir="${clearcase.log.dir}"/>
<mkdir dir="${clearcase.log.dir}"/>
<delete file="${config.spec.filename}"/>
<echo message="Generate ${config.spec.filename}"/>
<exec dir="${config.spec.dir}" executable="${perl}" failonerror="true">
<arg line="${genConfigSpec.script} -time ${cctimestamp} -template ${config.spec.template}
-output ${config.spec.filename}"/>
</exec>
<echo message="Set ${config.spec.filename}"/>
<exec dir="Z:\" executable="C:\Program Files\ClearCase\bin\cleartool.exe" failonerror="true">
<arg line="setcs -tag aus_spitfire_view d:\build\cruisecontrol\config.spec"/>
</exec>
<echo message="config.spec set for view"/>
</target>
<target name="build">
<echo message="build project: ${project.root}\.build.xml Target: cleanbuild"/>
<ant dir="${project.root}" antfile="${project.root}\build.xml" target="cleanbuild"/>
</target>
<target name="label" description="Adds label to current snapshot">
<echo message="set label to @quot;${label}@quot;"/>
<fail unless="label" message="@quot;label@quot; property is not set"/>
<exec dir="${view.root}" executable="cleartool" failonerror="true">
<arg line="mklbtype -c @quot;Autobuild label@quot; ${label}"/>
</exec>
<exec dir="${view.root}" executable="cleartool" failonerror="true">
<arg line="mklabel -recurse ${label} ."/>
</exec>
</target>
</project>