How does the cb:eval preprocessor work in CruiseControl.net - cruisecontrol.net

I want to calculate a value in my ccnet.config file. So I tried this:
<cb:eval prio="$(BasePriority)+$(Priority)" />
<project name="test" queue="test" queuePriority="$(prio)">
...
But this gave me an error that eval needs to have the "expr" attribute. How do I name the output of the eval so I can reference it?

I found an example in another question on stack overflow. Here is how its done:
<cb:define name="prio">
<cb:eval expr="$(BasePriority)+$(Priority)" />
</cb:define>
<project name="test" queue="test" queuePriority="$(prio)">

Related

Overriding project properties with a custom task

Our C++ project uses MSBuild to build on Windows and GNU make on *nix. I'm trying to recreate the functionality of the following single line of GNU make in MSBuild:
GENN_PATH:=$(abspath $(dir $(shell which genn-buildmodel.sh))../userproject/include)
Essentially setting a variable to a path relative to an executable in the path. However, this is proving to be a battle to implement in MSBuild...
The following are the (hopefully) pertinent sections from my vcxproj. For testing purposes I am first setting the variable I want to override to something obvious:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<PropertyGroup Label="Configuration">
...
<GeNNUserProject>UNDEFINED</GeNNUserProject>
</PropertyGroup>
Then, in my ClCompile item definitions, I am adding the value of this property to the additional include directories
<ItemDefinitionGroup>
<ClCompile>
...
<AdditionalIncludeDirectories>include;$(GeNNUserProject)</AdditionalIncludeDirectories>
</ClCompile>
...
</ItemDefinitionGroup>
In order to find this path, I'm using the where command and redirecting it's output to a property. Then, from this, I'm finding the include directory and printing it out - this works!
<Target Name="FindUserProjects">
<Exec Command="where genn-buildmodel.bat" ConsoleToMsBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="GeNNBuildModelPath" />
</Exec>
<PropertyGroup>
<GeNNUserProject>$([System.IO.Path]::GetFullPath($([System.IO.Path]::GetDirectoryName($(GeNNBuildModelPath)))\..\userproject\include))</GeNNUserProject>
</PropertyGroup>
<Message Text="MAGIC GENN-FINDING! $(GeNNBuildModelPath) -> $(GeNNUserProject)"/>
</Target>
I've tried a variety of ways of making this a dependency of ClCompile including setting the Target as BeforeTargets="PrepareForBuild" and the following:
<PropertyGroup>
<BeforeClCompileTargets>
FindUserProjects;
$(BeforeClCompileTargets);
</BeforeClCompileTargets>
</PropertyGroup>
</Project>
Whatever I do, my custom target runs but the property is not being overriden. Google suggests that if properties are overriden in depencies they should be visible from targets and from digging into Microsoft.CPP*.targets this is what setting BeforeClCompileTargets is doing.
The problem here was not that the target wasn't setting the property, it's that the AdditionalIncludeDirectories item metadata was being set from the original value. The solution is to set this directly from the target instead:
<ItemGroup>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$([System.IO.Path]::GetFullPath($([System.IO.Path]::GetDirectoryName($(GeNNBuildModelPath)))\..\userproject\include))</AdditionalIncludeDirectories>
</ClCompile>
</ItemGroup>

msbuild+wix : how to get heatdirectory to use defineconstants's variable?

hello everybody : my first post !
i am trying to get a wixproj using heatdirectory to take its source directory using visualstudio's "Define Constants" feature, in which i define a constant SourceBinaries=c:\someproject\bin\release.
The purpose is to use the same wixproj/setup for several projects and automate the whole with TFS-Build...
however, the Directory Tag never gets the SourceBinaries's value.
here's the xml code :
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
blah..
<OutputName>ProjectSetup</OutputName>
blah..
</PropertyGroup>
<PropertyGroup>
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<DefineConstants>SourceBinaries=c:\someproject\bin\release\</DefineConstants>
</PropertyGroup>
<ItemGroup>
blah..
</ItemGroup>
<Import Project="$(WixTargetsPath)" />
<Target Name="BeforeBuild">
<HeatDirectory NoLogo="$(HarvestDirectoryNoLogo)"
Directory="$(SourceBinaries)"
PreprocessorVariable="var.SourceBinaries"
SuppressAllWarnings="$(HarvestDirectorySuppressAllWarnings)"
SuppressSpecificWarnings="$(HarvestDirectorySuppressSpecificWarnings)"
ToolPath="$(WixToolPath)"
TreatWarningsAsErrors="$(HarvestDirectoryTreatWarningsAsErrors)"
TreatSpecificWarningsAsErrors="$(HarvestDirectoryTreatSpecificWarningsAsErrors)"
VerboseOutput="$(HarvestDirectoryVerboseOutput)"
AutogenerateGuids="$(HarvestDirectoryAutogenerateGuids)"
GenerateGuidsNow="$(HarvestDirectoryGenerateGuidsNow)"
OutputFile="ProductFiles.wxs"
SuppressFragments="$(HarvestDirectorySuppressFragments)"
SuppressUniqueIds="$(HarvestDirectorySuppressUniqueIds)"
Transforms="Transforms.xsl"
ComponentGroupName="ProductFiles"
DirectoryRefId="INSTALLLOCATION"
KeepEmptyDirectories="false"
SuppressCom="%(HarvestDirectory.SuppressCom)"
SuppressRootDirectory="true"
SuppressRegistry="%(HarvestDirectory.SuppressRegistry)">
</HeatDirectory>
blah..
</Target>
<Target Name="AfterBuild">
blah..
</Target>
</Project>
whatever i tried lead me to "Error The "HeatDirectory" task was not given a value for the required parameter "Directory".
can somebody help me resolving this ?
thanks in advance...
Didier
I think your main source of confusion is that the variables defined in the <DefineConstants> element only work for the .wxs files, but they will not work in the .wixproj file itself.
To fix this you could do something like:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
blah..
<OutputName>ProjectSetup</OutputName>
blah..
</PropertyGroup>
<PropertyGroup>
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<SourceBinaries>c:\someproject\bin\release</SourceBinaries>
<DefineConstants>SourceBinaries=$(SourceBinaries)</DefineConstants>
</PropertyGroup>
<ItemGroup>
blah..
</ItemGroup>
<Import Project="$(WixTargetsPath)" />
<Target Name="BeforeBuild">
<HeatDirectory NoLogo="$(HarvestDirectoryNoLogo)"
Directory="$(SourceBinaries)"
PreprocessorVariable="var.SourceBinaries"
SuppressAllWarnings="$(HarvestDirectorySuppressAllWarnings)"
SuppressSpecificWarnings="$(HarvestDirectorySuppressSpecificWarnings)"
ToolPath="$(WixToolPath)"
TreatWarningsAsErrors="$(HarvestDirectoryTreatWarningsAsErrors)"
TreatSpecificWarningsAsErrors="$(HarvestDirectoryTreatSpecificWarningsAsErrors)"
VerboseOutput="$(HarvestDirectoryVerboseOutput)"
AutogenerateGuids="$(HarvestDirectoryAutogenerateGuids)"
GenerateGuidsNow="$(HarvestDirectoryGenerateGuidsNow)"
OutputFile="ProductFiles.wxs"
SuppressFragments="$(HarvestDirectorySuppressFragments)"
SuppressUniqueIds="$(HarvestDirectorySuppressUniqueIds)"
Transforms="Transforms.xsl"
ComponentGroupName="ProductFiles"
DirectoryRefId="INSTALLLOCATION"
KeepEmptyDirectories="false"
SuppressCom="%(HarvestDirectory.SuppressCom)"
SuppressRootDirectory="true"
SuppressRegistry="%(HarvestDirectory.SuppressRegistry)">
</HeatDirectory>
blah..
</Target>
<Target Name="AfterBuild">
blah..
</Target>
</Project>
Above, we're creating a new <SourceBinaries> element with the path to the directory. This custom element can then be used as a variable in the rest of the .wixproj file. We then use this value to populate the SourceBinaries constant that is used in the .wxs files.
In conclusion, in the <HeatDirectory> element:
the Directory attribute gets its value from <SourceBinaries>
The PreProcessorVariable attribute gets its value from <DefineConstants> (or other variables available to .wxs files like project references)
You could use the HarvestDirectory target as described here http://wixtoolset.org/documentation/manual/v3/msbuild/target_reference/harvestdirectory.html.

CruiseControl.NET use project name in project config

Is there any way to use the project name in the project config in CruiseControl.NET ?
I tried ${project.name} based on other posts which doesn't work.
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<cb:define BuildArtifactsMainDir="D:\CCNet\BuildArtifacts\"/>
<project name="MyProject">
<artifactDirectory>$(BuildArtifactsMainDir)${project.name}</artifactDirectory>
<tasks>
<exec>
<executable>C:\Windows\System32\robocopy.exe</executable>
<buildArgs>D:\${project.name} F:\${project.name}</buildArgs>
<buildTimeoutSeconds>600</buildTimeoutSeconds>
<successExitCodes>0,1,3,4,8,16</successExitCodes>
</exec>
</tasks>
I don't think there's a parameter for project name. You can use scopes instead.
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<cb:define BuildArtifactsMainDir="D:\CCNet\BuildArtifacts\"/>
<cb:scope ProjectName="MyProject">
<project name="$(ProjectName)">
<artifactDirectory>$(BuildArtifactsMainDir)$(ProjectName)</artifactDirectory>
...
</project>
</cb:scope>

How can I set define multiple parameters in CCNet?

I am working in CCNet version 1.4, and I am having difficulty getting the parameters I want defined in a clean manner. In my example, I want 6 total projects as (3 solutions in 2 branches). I defined a generic project that could incorporate all 6 possibilities based on choice of 8 variables. When it's a trunk project, 4 of the variables should be one thing. When it's a branch project, the 4 variables should be another thing. The other 4 variables are dependent on which solution I want to build.
In my attempt below, I put the 4 trunk variables in one define block and the 4 release variables in another block. I also have a define block for each of the solutions.
<cb:define name="ProductBuildProject">
<project name="$(ProjectName)" queue="Common">
<category>Main Builds</category>
<sourcecontrol type="multi">
<sourceControls>
<cb:svn-sourcebuild-checkout BranchPath="$(BranchPath)" MainSourcePath="$(MainSourcePath)" />
</sourceControls>
</sourcecontrol>
<modificationDelaySeconds>10</modificationDelaySeconds>
<labeller type="defaultlabeller">
<prefix><cb:LabelPrefix/></prefix>
<incrementOnFailure>true</incrementOnFailure>
</labeller>
<triggers>
<intervalTrigger name="continuous" seconds="900" buildCondition="IfModificationExists"/>
</triggers>
<tasks>
<nant>
<executable>&nant-path;</executable>
<baseDirectory><cb:LocalKeywordLabPath/>\<cb:MainSourcePath/></baseDirectory>
<buildArgs>-v -D:deployServer=<cb:DeployServer/></buildArgs>
<buildFile><cb:BuildFileName/></buildFile>
<targetList>
<target><cb:BuildTargetName/></target>
</targetList>
<buildTimeoutSeconds>600</buildTimeoutSeconds>
</nant>
</tasks>
<publishers>
<merge>
<files>
<file><cb:LocalKeywordLabPath/>\<cb:MainSourcePath/>\<cb:UnitTestOutputPath/></file>
</files>
</merge>
&publishers-common-block;
</publishers>
<externalLinks/>
</project>
</cb:define>
<cb:define name="TrunkBuildParameters">
<cb:define name="LocalKeywordLabPath"><cb:keywordlab-trunk-local/></cb:define>
<cb:define name="BranchPath"><cb:trunk-path/></cb:define>
<cb:define name="LabelPrefix">1.1.0.</cb:define>
<cb:define name="DeployServer">smwtlkwlab01n</cb:define>
</cb:define>
<cb:define name="ReleaseBranchBuildParameters">
<cb:define name="LocalKeywordLabPath"><cb:keywordlab-release-local/></cb:define>
<cb:define name="BranchPath"><cb:releaseBranch-path/></cb:define>
<cb:define name="LabelPrefix">1.1.100.</cb:define>
<cb:define name="DeployServer">smwdvkwlab03n</cb:define>
</cb:define>
<cb:define name="KeywordLabWebParameters">
<cb:define name="MainSourcePath">Source\Presentation</cb:define>
<cb:define name="BuildFileName">KeywordLab.Web.build</cb:define>
<cb:define name="BuildTargetName">automated-with-webdeploy</cb:define>
<cb:define name="UnitTestOutputPath">KeywordLab.Web.UnitTest\bin\Release\KeywordLab.Web.UnitTest.trx</cb:define>
</cb:define>
<cb:define name="KeywordLabWebMvcParameters">
<cb:define name="MainSourcePath">Source\UI</cb:define>
<cb:define name="BuildFileName">KeywordLab.Web.Mvc.build</cb:define>
<cb:define name="BuildTargetName">automated-with-webdeploy</cb:define>
<cb:define name="UnitTestOutputPath">KeywordLab.Web.Mvc.Tests\bin\Release\KeywordLab.Web.Mvc.Tests.trx</cb:define>
</cb:define>
<cb:define name="KeywordLabServiceParameters">
<cb:define name="MainSourcePath">Source\Service</cb:define>
<cb:define name="BuildFileName">KeywordLab.build</cb:define>
<cb:define name="BuildTargetName">automated</cb:define>
<cb:define name="UnitTestOutputPath">KeywordLab.UnitTest\bin\Release\KeywordLab.UnitTest.trx</cb:define>
</cb:define>
Finally, I try to define the 6 projects each by referencing the define block for the trunk or release build and the correct define block for the solution.
<!--KeywordLab Web-->
<cb:ProductBuildProject>
<cb:define name="ProjectName">KeywordLab Web (1N)</cb:define>
<cb:TrunkBuildParameters/>
<cb:KeywordLabWebParameters/>
</cb:ProductBuildProject>
<!--KeywordLab Web Mvc-->
<cb:ProductBuildProject>
<cb:define name="ProjectName">KeywordLab Web Mvc (1N)</cb:define>
<cb:TrunkBuildParameters/>
<cb:KeywordLabWebMvcParameters/>
</cb:ProductBuildProject>
<!--KeywordLab Service-->
<cb:ProductBuildProject>
<cb:define name="ProjectName">KeywordLab Service (1N)</cb:define>
<cb:TrunkBuildParameters/>
<cb:KeywordLabServiceParameters/>
</cb:ProductBuildProject>
<!--KeywordLab Web-->
<cb:ProductBuildProject>
<cb:define name="ProjectName">Release Branch (3N) - KeywordLab Web</cb:define>
<cb:ReleaseBranchBuildParameters/>
<cb:KeywordLabWebParameters/>
</cb:ProductBuildProject>
<!--KeywordLab Web Mvc-->
<cb:ProductBuildProject>
<cb:define name="ProjectName">Release Branch (3N) - KeywordLab Web Mvc</cb:define>
<cb:ReleaseBranchBuildParameters/>
<cb:KeywordLabWebMvcParameters/>
</cb:ProductBuildProject>
<!--KeywordLab Service-->
<cb:ProductBuildProject>
<cb:define name="ProjectName">Release Branch (3N) - KeywordLab Service</cb:define>
<cb:ReleaseBranchBuildParameters/>
<cb:KeywordLabServiceParameters/>
</cb:ProductBuildProject>
This isn't working and I'm hoping that someone can point out what I'm doing wrong. When I try to load this config, the error I receive is:
[CCNet Server:ERROR] INTERNAL ERROR: Reference to unknown symbol LabelPrefix
As you can see in TrunkBuildParameters and ReleaseBranchBuildParameters, I define LabelPrefix in both, and all 6 projects reference one or the other of these define blocks. I then try to reference this in the block of the project. This is apparently not a valid way of defining a variable for use by projects. Could someone please tell me what I'm doing wrong or perhaps a better way to do this at all?
I'd suggest using the Validator supplied with cruisecontrol to see what the final parsed config file is, to check if you've missed anything.
Having said that, what I usually do is the other way around. I define commonly used config blocks and then write out the project config with only a few lines. Perhaps you'll consider that clean enough?

MSBuild: Permanently Change PropertyGroup Property of a Project

I was hoping to find a way to set a value in my csproj file during my build to a value. Is there a task in MSBuild that I can use to set a property permanently to a value? In the example below, can I set CustomValue = Yes permanently?
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
.....
<CustomValue>XXXX</CustomValue
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids></ProjectTypeGuids>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
You can use the XmlPoke task to do that. It seems a little odd to be altering projects this way though. Alternatively, you can set up a tiny import file,
<!-- in your main project file, right below the PropertyGroup -->
<Import
Condition="Exists('Custom.props')"
Project="Custom.props"
/>
Then dynamically create this property file, as,
<?xml version="1.0" encoding="utf-8"?>
<Project
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0">
<PropertyGroup>
<CustomValue>True</CustomValue>
</PropertyGroup>
</Project>
You can either use XmlPoke on just this .props file, or use WriteLinesToFile to create the entire file. This secondary file wouldn't need to be checked into source control, the condition on the import makes the project functional when the file doesn't exist.
The XmlPoke task would look like this,
<XmlPoke
XmlInputPath="./Custom.props"
Namespaces="<Namespace Prefix='x'
Uri='http://schemas.microsoft.com/developer/msbuild/2003'/>"
Query="//x:PropertyGroup/x:CustomValue/#Value"
Value="True"
/>

Resources