How to assign exec's output to a property in NAnt - cruisecontrol.net

My aim is to fill property with output of command "git describe".
I have a property:
<property name="build.version" value = ""/>
And I want to fill it with output of the following command: git describe
I tried:
<exec program='${git.executable}' outputproperty='build.version'>
<arg value='describe' />
</exec>
but unlike the Ant, NAnt doesn't support outputproperty :( only output (to file).

You're right. You have resultproperty attribute to hold the exit code and output attribute to redirect the output.
Why don't you redirect the output and load the file afterwards via loadfile task:
<target name="foo">
<property
name="git.output.file"
value="C:\foo.txt" />
<exec program="${git.executable}" output="${git.output.file}">
<arg value="describe" />
</exec>
<loadfile
file="${git.output.file}"
property="git.output" />
</target>

Using trim, you can get rid of the carriage return character at the end. For instance, in the example above, add a line at the end to trim the string
<target name="foo">
<property
name="git.output.file"
value="C:\foo.txt" />
<exec program="${git.executable}" output="${git.output.file}">
<arg value="describe" />
</exec>
<loadfile
file="${git.output.file}"
property="git.output" />
<property name="git.ouput.trimmed" value="${string::trim(git.output)}" />
</target>

Related

ImageMagick identify.exe returns nothing in parallel Apache Ant project

I use Apache Ant project to gather some information about textures. Here you can see a test project that does only reading without any further actions. This is a minimal set that reproduces one nasty bug. I have found that sometimes ImageMagick's identify.exe does not return anything – I've added a code that forces build to fail if so. If I run this project multiple times I will get unstable behavior. Sometimes project build successfully, sometimes it fails with several fail-messages. Developers of ImageMagick say that their tools are thread safe. But if identify.exe is not the case then what can be? I really need help of someone with advance knowledge about Apache Ant and ImageMagick.
<project default="default">
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
<property name="image_magick_path" location="c:\Program Files\ImageMagick-6.8.9-Q8\"/>
<property name="images_path" location="path\to\folder\with\png\images"/>
<target name="default">
<for param="item" parallel="true">
<path>
<fileset dir="${images_path}">
<patternset id="pattern_images">
<include name="**\*.png"/>
<include name="**\*.jpg"/>
<include name="**\*.gif"/>
<include name="**\*.bmp"/>
</patternset>
</fileset>
</path>
<sequential>
<local name="image_width"/>
<tex_width file="#{item}" property="image_width"/>
<local name="image_height"/>
<tex_width file="#{item}" property="image_height"/>
<if>
<or>
<equals arg1="${image_width}" arg2=""/>
<equals arg1="${image_height}" arg2=""/>
</or>
<then>
<fail message="Got nothing. But why? Image: #{item}"/>
</then>
</if>
</sequential>
</for>
</target>
<macrodef name="tex_width">
<attribute name="file"/>
<attribute name="property"/>
<sequential>
<exec executable="${image_magick_path}\identify.exe" outputproperty="#{property}">
<arg value="-format"/>
<arg value="%w"/>
<arg value="#{file}"/>
</exec>
</sequential>
</macrodef>
<macrodef name="tex_height">
<attribute name="file"/>
<attribute name="property"/>
<sequential>
<exec executable="${image_magick_path}\identify.exe" outputproperty="#{property}">
<arg value="-format"/>
<arg value="%h"/>
<arg value="#{file}"/>
</exec>
</sequential>
</macrodef>
</project>
Ok, I will write here how I managed to solve my problem. I hope it will help someone someday.
First thing I found is that PHP method 'getimagesize' is much faster so I decided to switch to it thus killing the main problem. I wrote following macrodef to get both image width and height:
<macrodef name="getimagesize">
<attribute name="file"/>
<attribute name="propertywidth"/>
<attribute name="propertyheight"/>
<sequential>
<local name="output"/>
<exec executable="php" outputproperty="output">
<arg value="-r"/>
<arg value=
""$size=getimagesize('#{file}');
echo($size[0].' '.$size[1]);""
/>
</exec>
<propertyregex
property="#{propertywidth}"
input="${output}"
regexp="(\d*) (\d*)"
replace="\1"
/>
<propertyregex
property="#{propertyheight}"
input="${output}"
regexp="(\d*) (\d*)"
replace="\2"
/>
</sequential>
</macrodef>
Unfortunately this macrodef has abosutely same bug. Sometimes during parallel run some exec-tasks returned nothing in output. I was very upset so I decided to write another macrodef which I use now and finally it works fine. What I did was avoid reading anything from exec-task's 'stdout' and use tempfile-task instead. Here's final macrodef:
<macrodef name="getimagesize">
<attribute name="file"/>
<attribute name="propertywidth"/>
<attribute name="propertyheight"/>
<sequential>
<local name="file_dirname"/>
<dirname property="file_dirname" file="#{file}"/>
<local name="file_temp"/>
<tempfile property="file_temp" destdir="${file_dirname}" createfile="true"/>
<exec executable="php">
<arg value="-r"/>
<arg value=""$size=getimagesize('#{file}');
file_put_contents('${file_temp}', $size[0].' '.$size[1]);""/>
</exec>
<local name="file_temp_content"/>
<loadfile property="file_temp_content" srcfile="${file_temp}"/>
<delete file="${file_temp}"/>
<propertyregex
property="#{propertywidth}"
input="${file_temp_content}"
regexp="(\d*) (\d*)"
replace="\1"
/>
<propertyregex
property="#{propertyheight}"
input="${file_temp_content}"
regexp="(\d*) (\d*)"
replace="\2"
/>
</sequential>
</macrodef>

Conditional Include on Items in an Item Group

I want to copy files over to a server but before i do this i would like to include the latest msi file that i generate.
I noticed that the ItemGroup and Item have a Condition attribute but i do not know how to utilize this to include the latest file.
So far this is my setup:
<Target Name="AfterBuild">
<ItemGroup>
<Installers Include="\\SERVERNAME\BuildOutput\ProductStream\**\Installers\Customer\Installer.msi"/>
</ItemGroup>
<Message Text="FirstItem: %(Installers.Filename)" />
<Message Text="FirstItem: %(Installers.FullPath)" />
The output of this are two files:
e.g
\\Servername\BuildOutput\ProductStream\Installers\ProductStreamV2.1.1202.1402\Installer.msi
\\Servername\BuildOutput\ProductStream\Installers\ProductStreamV2.1.1405.1301\Installer.msi
I want to include the 2.1.1405.1301 build in the Item as this is the latest one.
I would appreciate if someone would assist me because i cannot find how to go about doing this from the MSDN blogs.
Thanks,
You could use a custom task for this purpose. It allows you to filter items any way you want. Here I used regular expressions to select the latest installer:
<Target Name="AfterBuild">
<ItemGroup>
<Installers Include="**\Installer.msi"/>
</ItemGroup>
<SelectLatestInstaller Installers="#(Installers)">
<Output TaskParameter="LatestInstaller" ItemName="LatestInstaller" />
</SelectLatestInstaller>
<Message Text="%(LatestInstaller.FullPath)" />
</Target>
<UsingTask TaskName="SelectLatestInstaller"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<Installers ParameterType="System.String[]" Required="true" />
<LatestInstaller ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Reference Include="System.Linq" />
<Using Namespace="System" />
<Using Namespace="System.Linq" />
<Using Namespace="System.Text.RegularExpressions" />
<Code Type="Fragment" Language="cs">
<![CDATA[
LatestInstaller = Installers
.OrderByDescending(f => Regex.Match(f, #"\\ProductStreamV(?<version>(\d+.){0,3}\d+)\\").Groups["version"].Value)
.FirstOrDefault();
]]>
</Code>
</Task>
</UsingTask>

Not able to see the FxCop Report embeded in the Email using CruiseControl.Net

I have installed Cruise Control 1.5 on my machine and trying to configure the automated build. Everything is working fine. Application is building, i receive an email but I don't see the FXCop result embedded in the Build Email. What am i missing?
ccnet.config file
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<project name="SampleProject">
<webURL>http://localhost/ccnet</webURL>
<workingDirectory>E:\\NewProject\\DevBuilds</workingDirectory>
<artifactDirectory>E:\\NewProject\\DevBuilds\Artifacts</artifactDirectory>
<modificationDelaySeconds>600</modificationDelaySeconds>
<category>Dev Build</category>
<sourcecontrol type="svn">
<trunkUrl>https://mycompany.com/svn/trunk/MyApplication</trunkUrl>
<workingDirectory>E:\\NewProject\\DevBuilds\SourceCode</workingDirectory>
<autoGetSource>false</autoGetSource>
<executable>C:\Program Files\Subversion\bin\svn.exe</executable>
<username>username</username>
<password>password</password>
</sourcecontrol>
<initialState>Started</initialState>
<startupMode>UseInitialState</startupMode>
<triggers>
<intervalTrigger seconds="3600" buildCondition="IfModificationExists" />
</triggers>
<state type="state" directory="E:\\NewProject\\DevBuilds" />
<labeller type="iterationlabeller">
<prefix>1.0</prefix>
<duration>1</duration>
<releaseStartDate>2012/04/11</releaseStartDate>
<separator>.</separator>
</labeller>
<tasks>
<nant>
<executable>E:\NewProject\Installables\nant\bin\nant.exe</executable>
<baseDirectory>E:\\NewProject\\Build Files</baseDirectory>
<buildFile>Build.xml</buildFile>
<targetList>
<target>Run</target>
</targetList>
<buildTimeoutSeconds>5000</buildTimeoutSeconds>
</nant>
</tasks>
<publishers>
<merge>
<files>
<file>E:\NewProject\DevBuilds\FxCopOutput\FxCop-results.xml</file>
</files>
</merge>
<xmllogger logDir="E:\\NewProject\\DevBuilds\Artifacts\\buildlogs" />
<email from="Checkins#symphonysv.com" mailhost="smtp.gmail.com" includeDetails="true" useSSL="false">
<users>
<user name="dev1" group="buildmaster" address="myname#gmail.com"/>
</users>
<groups>
<group name="buildmaster">
<notifications>
<notificationType>Always</notificationType>
</notifications>
</group>
</groups>
</email>
</publishers>
</project>
</cruisecontrol>
Build.xml
<?xml version="1.0"?>
<project name="Test" default="Run" basedir=".">
<property name="BuildNumber" value="1.0.0.0"/>
<property name="SourceControlURL" value="https://mycompany.com/svn/trunk/MyApplication/"/>
<property name="BuildFile" value=".\Build.xml"/>
<property name="TagBuild" value="false"/>
<property name="BuildType" value="Release"/>
<property name="BuildTargetDir" value="E:\NewProject\DevBuilds\Executables"/>
<property name="BuildWorkDir" value="E:\NewProject\DevBuilds\SourceCode"/>
<property name="MSBUILD" value="C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319"/>
<property name="FxCopOutPutDirectory" value="E:\NewProject\DevBuilds\FxCopOutput" />
<property name="FxCopInputDirectory" value="E:\NewProject\DevBuilds" />
<target name="Run" description="Starting ThinkPets Build">
<call target="GetLatestCode"/>
<call target="BuildCode"/>
<call target="BuildASPWebSite"/>
<call target="runFxCop"/>
</target>
<target name="GetLatestCode">
<echo message="Updating Code From SVN to ${BuildWorkDir}"/>
<exec program="svn.exe">
<arg line="checkout ${SourceControlURL} ${BuildWorkDir} -q"/>
</exec>
</target>
<target name="BuildCode">
<echo message="Building VS10 Projects Web" />
<exec program="${MSBUILD}\msbuild.exe" failonerror="true">
<arg line=" "${BuildWorkDir}\Application.sln" /t:Rebuild /p:Configuration=Release /V:q"/>
</exec>
</target>
<target name="BuildASPWebSite">
<echo message="Building ASP Web Site" />
<exec program="${MSBUILD}\aspnet_compiler.exe" failonerror="true">
<arg line=" -v / -p "${BuildWorkDir}\MyDir" -f -c "${BuildTargetDir}" "/>
</exec>
</target>
<target name="runFxCop" depends="BuildCode">
<exec program="C:\Program Files\Microsoft FxCop 1.36\FxCopCmd.exe" failonerror="false">
<arg line="/p:${FxCopInputDirectory}\SampleProject.FxCop /o:${FxCopOutPutDirectory}\FxCop-results.xml"/>
</exec>
</target>
</project>
There are a few points you missed:
You need to add <includeDetails>true</includeDetails> to your e-mail publisher block. This will give you HTML e-mails.
In order to transform your XML build results into HTML you need to add an <xslFiles> section to your e-mail publisher block. The elements of this block point to XSL transformation files in [CCNET_INSTALL_DIR]\server\xsl.
So for including the FxCop summary just as appears in CCNET webdasboard this is your e-mail publisher block:
<email from="Checkins#symphonysv.com" mailhost="smtp.gmail.com" includeDetails="true" useSSL="false">
<users>
<user name="dev1" group="buildmaster" address="myname#gmail.com"/>
</users>
<groups>
<group name="buildmaster">
<notifications>
<notificationType>Always</notificationType>
</notifications>
</group>
</groups>
<includeDetails>true</includeDetails>
<xslFiles>
<file>xsl\fxcop-summary_1_36.xsl</file>
</xslFiles>
</email>
Thanks Chairman for your valuable time. I think my mistake was that I did not host the "ccnet" application on my machine which resulted in not able to find the xsls for the publishers. When I used the same settings and config file on the Server machine with "ccnet" application hosted, I was able to see the FxCop summary in the email. Please correct my understanding if wrong.

Building a WSP File on the Build Machine

On my development machine I installed VSeWSS 1.3 and configured the local IIS 6 so that I can build my SharePoint project and deploy the generated WSP file to the local machine. The WSP file is generated by the Packaging step, which I can successfully install on other machines.
Now I have to migrate my project to our build machine which currently does not have SharePoint installed and is not configured for VSeWSS (no VSeWSS web service endpoint). Is there a way to automate the building of the WSP file without the need to configure IIS on the build machine for use with SharePoint and VSeWSS?
Some of the books describe the manual step of using MakeCab.exe and defining a DDF file, but I don't see any DDF file generated by VSeWSS (is it maybe generated in a TEMP folder which I could use to configure my automated build process?).
I just faced the same problem. I opted for another tool for developing the whole solution: I found WSPBuilder much cleaner and less intrusive. It also can be used from the Command line, which is great for Build files.
I modified some Nant scripts created by Bil Simser in order to compile and deploy the project and move the code from VSeWSS to WSPBuilder. It works like a charm either on my machine or on the build machine.
You can find WSPBuilder on http://www.Codeplex.com, and these targets need nantContrib (on www.tigris.org) to work.
Here are some of the targets I'm using:
<target name="build" depends="compile">
<copy todir="${build.dir}\12\">
<fileset basedir="${sharepoint.dir}\12">
<include name="**/*"/>
</fileset>
</copy>
<copy
file="${sharepoint.dir}\solutionid.txt"
tofile="${build.dir}\solutionid.txt"
/>
<call target="buildsolutionfile" />
</target>
<target name="buildsolutionfile">
<exec program="${wspbuilder.exe}" workingdir="${build.dir}">
<arg value="-BuildDDF"/>
<arg value="${debug}"/>
<arg value="-Cleanup"/>
<arg value="false"/>
<arg value="-FolderDestination"/>
<arg value="${build.dir}"/>
<arg value="-Outputpath"/>
<arg value="${build.dir}"/>
<arg value="-TraceLevel"/>
<arg value="verbose"/>
</exec>
<copy
file="${build.dir}\${package.file}"
tofile="${solution.dir}\${package.file}"/>
</target>
<target name="addsolution">
<exec program="${stsadm.exe}" verbose="${verbose}">
<arg value="-o" />
<arg value="addsolution" />
<arg value="-filename" />
<arg value="${solution.dir}\${package.file}" />
</exec>
<call target="spwait" />
</target>
<target name="spwait" description="Waits for the timer job to complete.">
<exec program="${stsadm.exe}" verbose="${verbose}">
<arg value="-o" />
<arg value="execadmsvcjobs" />
</exec>
</target>
<target name="app.pool.reset" description="Resets Sharepoint's application pool.">
<iisapppool action="Restart" pool="${apppool}" server="${server}" />
</target>
<target name="deploysolution" depends="addsolution">
<exec program="${stsadm.exe}" workingdir="${build.dir}" verbose="${verbose}">
<arg value="-o" />
<arg value="deploysolution" />
<arg value="-name" />
<arg value="${package.file}" />
<arg value="-immediate" />
<arg value="-allowgacdeployment" />
<arg value="-allcontenturls" />
<arg value="-force" />
</exec>
<call target="spwait" />
<call target="app.pool.reset" />
</target>

NAnt Web Application Deployment

Good day.
I'm trying to deploy a web application using NAnt. It is current zipped using the NAnt ZIP task.
I can try calling MSDeploy from NAnt but I don't think MSDeploy was written for such deployments.
I can also try using NAnt task.
Does anybody have suggestions as to what approach can save me the most time?
Using the aspnet compiler is the simplest way and gets you access to all cl arguments which is not available on nant tasks. Not sure why it's so.
Here's what I do
<property name="aspnetcomplier" value="C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe" />
<target name="deploy">
<mkdir dir="${output.dir}" />
<exec program="${aspnetcomplier}">
<arg value="-v" />
<arg value="/trunk" />
<arg value="-p" />
<arg value="${source.dir}\Root" />
<arg value="-f" />
<arg value="${output.dir}" />
</exec>
</target
Nothing complicated.Works like a charm.
P.S. Dont forget to do a iisreset /stop and /start
<target name="stop.iis" >
<servicecontroller action="Stop" service="w3svc" timeout="10000" verbose="true" />
</target>
<target name="start.iis" >
<servicecontroller action="Start" service="w3svc" timeout="10000" verbose="true" />
</target>

Resources