Trying to create an MSBuild task that outputs my code to a folder. All is working except the Regular Expression. My code:
<Target Name="AfterBuild">
<GetAssemblyIdentity AssemblyFiles="$(OutDir)$(TargetFileName)">
<Output TaskParameter="Assemblies" ItemName="TheVersion" />
</GetAssemblyIdentity>
<PropertyGroup>
<Pattern>(\d+)\.(\d+)\.(\d+)</Pattern>
<In>%(TheVersion.Version)</In>
<OutVersion>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern)))</OutVersion>
</PropertyGroup>
<ItemGroup>
<OutputFiles Include="$(OutDir)*" Exclude="*.tmp" />
<SolnFiles Include="$(SolutionDir)INDIVIDUAL.txt;$(SolutionDir)LICENSE.txt;$(SolutionDir)README.md" />
</ItemGroup>
<Copy SourceFiles="#(OutputFiles)" DestinationFolder="$(SolutionDir)dache-%(OutVersion)\Tests" SkipUnchangedFiles="true" />
<Copy SourceFiles="#(SolnFiles)" DestinationFolder="$(SolutionDir)dache-%(OutVersion)\" SkipUnchangedFiles="true" />
</Target>
When I run this, I get this error:
The item "D:\Dache\INDIVIDUAL.txt" in item list "SolnFiles" does not define a value for metadata "OutVersion". In order to use this metadata, either qualify it by specifying %(SolnFiles.OutVersion), or ensure that all items in this list define a value for this metadata.
When I try %(SolnFiles.OutVersion) it comes up blank. I'm doing something dumb here, what is it?
Took me a few to figure it out. PropertyGroup variables are referenced as $(Var) while ItemGroup output variables are #() and GetAssemblyIdentity is %() - so I changed:
<Copy SourceFiles="#(OutputFiles)" DestinationFolder="$(SolutionDir)dache-%(OutVersion)\Tests" SkipUnchangedFiles="true" />
<Copy SourceFiles="#(SolnFiles)" DestinationFolder="$(SolutionDir)dache-%(OutVersion)\" SkipUnchangedFiles="true" />
to this:
<Copy SourceFiles="#(OutputFiles)" DestinationFolder="$(SolutionDir)dache-$(OutVersion)\Tests" SkipUnchangedFiles="true" />
<Copy SourceFiles="#(SolnFiles)" DestinationFolder="$(SolutionDir)dache-$(OutVersion)\" SkipUnchangedFiles="true" />
and it worked.
Related
I have defined targets in ant for our games, e.g. clean, build-ios, build-android, deploy-ios, deploy-android, etc. Now I would like to define a new set of targets that represent our games, say game1, game2, game3.
My goal is to be able to launch ant with a set of target games and a set of target tasks so that for each selected game, each selected task is executed.
Example pseudo code: Foreach [game1, game3]: clean, build-ios, deploy-ios
How can I achieve this with ant? A requirement would be to define which games and which tasks are selected through targets, not to write them in a file that is altered manually.
The subant task is useful for situations where you have multiple subprojects that share similar structures.
In your main build.xml, define a target that rubs the desired build target on your game subdirectories, along with all of the generalized build targets.
<target name="deploy-all">
<subant target="deploy">
<dirset dir="." includes="game-*" />
</subant>
<echo message="All games deployed." />
</target>
<target name="deploy" depends="deploy-ios,deploy-android">
<echo message="${ant.project.name} build complete." />
</target>
<target name="clean">
<echo message="Cleaning ${ant.project.name}" />
</target>
<target name="build-ios" depends="clean">
<echo message="Building iOS ${ant.project.name}" />
</target>
<target name="build-android" depends="clean">
<echo message="Building Android ${ant.project.name}" />
</target>
<target name="deploy-ios" depends="build-ios">
<echo message="Deploying iOS ${ant.project.name}" />
</target>
<target name="deploy-android" depends="build-android">
<echo message="Deploying Android ${ant.project.name}" />
</target>
Then, in the game-* subdirectories, create a simple build.xml that links back to the common one.
game-1/build.xml:
<project name="game-1" default="build">
<import file="../build.xml" />
<echo message="=== Building Game 1 ===" />
</project>
game-2/build.xml:
<project name="game-2" default="build">
<import file="../build.xml" />
<echo message="=== Building Game 2 ===" />
</project>
Edit: If your build needs to include/exclude certain subprojects based on the user's input or a pre-defined property, you can modify the subant task's nested resource collection to accommodate for this.
<property name="game.includes" value="game-*" />
<property name="game.excludes" value="" />
<subant target="deploy">
<dirset dir="." includes="${game.includes}" excludes="${game.excludes}" />
</subant>
The user can then run a command that optionally passes values for game.includes and/or game.excludes. If these properties are not specified, the values defined above by the property task will be used as defaults.
I use a build file to build and test my project.
I have a Compile-Target which has this line "Targets = "Rebuild". Do I really need this line? Using Visual Studio I know that I can clean a Solution and build it again, or I can just rebuild the solution.
In my msbuild-file I delete my main folder BuildArtifacts before creating him again. I used this Tutorial and I don't know why he uses Target=Rebuild?
This is my build file:
<Project ToolsVersion="4.0" DefaultTargets="RunUnitTests" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Falls Eigenschaften nicht gesetzt -> Release & Any CPU als default-->
<PropertyGroup>
<!-- ... -->
</PropertyGroup>
<ItemGroup>
<!-- ... -->
</ItemGroup>
<!-- All the stuff go into my main folder -->
<Target Name="Init" DependsOnTargets="Clean">
<MakeDir Directories="#(BuildArtifacts)" />
</Target>
<!-- delete my main folder -->
<Target Name="Clean">
<RemoveDir Directories="#(BuildArtifactsDir)" />
</Target>
<!-- delete NUnit-Files -->
<Target Name="CleanAfter">
<RemoveDir Directories="#(NunitDir)" />
</Target>
<Target Name="Compile" DependsOnTargets="Init">
<MSBuild Projects="#(SolutionFile)"
Targets="Rebuild"
Properties="OutDir=%(BuildArtifactsDir.FullPath);
Configuration=$(Configuration);
Platform=$(BuildPlatform)" />
</Target>
<Target Name="RunUnitTests" DependsOnTargets="Compile">
<Exec Command='"#(NUnitConsole)" "#(UnitTestsDLL)" --result=console-test.xml --work=BuildArtifacts' />
<CallTarget Targets="CleanAfter" />
</Target>
</Project>
This depends on your own needs: do you need the whole solution to be rebuilt or not? Arguably, on a build server, you want to do a complete clean/rebuild after every commit to make sure the codebase is sane. Removing just the output directory (I assume that is what the Clean starget does) doesn't necessarily remove all object files as well since they typically go into the intermediate directory which might not be the same as the output directory.
I want to execute a target before project builds.
I have define the following in the .vcxproj file.
<Target Name="BeforeBuild">
<Message Text="BeforeBuilds" />
<CallTarget Targets="myTarget" />
</Target>
<Import Project="..\GetCat.targets" />
<Target Name="DefaultBeforeTarget" BeforeTargets="Default">
<CallTarget Targets="myTarget" />
</Target>
<Target Name="myTarget" Inputs="$(TargetPath)" Outputs="$(TargetDir)$(TargetName).tlb" DependsOnTargets="GetCat">
<Message Text="Calling myTarget" />
<Exec Command="mkdri HelloW" />
</Target>
The myTarget <Message> is not getting called.
How to fix this?
I'm using MSBuild extension pack to replace lines in .proj files.
I'm replacing multiple lines with multiple lines. The lines it's outputting still have a semi colon at the end even when I do a transform.
<ItemGroup>
<TestFile Include="regextest.xml" />
<MyLines Include ="%3CItemGroup%3E%0A"/>
<MyLines Include ="%09%3CReference Include=%22Stuff%22%3E%0A" />
<MyLines Include ="%09%09%3CHintPath%3E..\..\packages\secret.dll%3C/HintPath%3E%0A" />
<MyLines Include ="%09%09%3CPrivate%3ETrue%3C/Private%3E%0A" />
<MyLines Include ="%09%3C/Reference%3E%0A" />
<MyLines Include ="%3C/ItemGroup%3E%0A" />
</ItemGroup>
<Target Name="Default">
<MSBuild.ExtensionPack.FileSystem.File TaskAction="Replace"
TextEncoding="ASCII"
RegexPattern="%3CProjectReference"
RegexOptionList="IgnoreCase"
Replacement="#(MyLines->'%(Identity)')"
Files="#(TestFile)" />
</Target>
And this is the output:
<ItemGroup>
; <Reference Include="Stuff">
; <HintPath>..\..\packages\secret.dll</HintPath>
; <Private>True</Private>
; </Reference>
;</ItemGroup>
Doing it without the transform still has them there too.
One easy way to handle multi-line replacement strings is to form them in a CDATA block inside of a property instead of a collection of single-line items (this is where the semicolons come from). In this case, you could create the multi-line replacement string as a property and then assign its value to an item, then pass the item to the Replace task action:
<PropertyGroup>
<MyMultiLine>
<![CDATA[
%3CItemGroup%3E
%3CReference Include="Stuff"%3E
%3CHintPath%3E..\..\packages\secret.dll%3C/HintPath%3E
%3CPrivate>True%3C/Private%3E
%3C/Reference%3E
%3C/ItemGroup%3E
]]>
</MyMultiLine>
</PropertyGroup>
<ItemGroup>
<TestFile Include="regextest.xml" />
<MyMultiLineItem Include="$(MyMultiLine)" />
</ItemGroup>
<Target Name="Default">
<MSBuild.ExtensionPack.FileSystem.File TaskAction="Replace"
TextEncoding="ASCII"
RegexPattern="%3CProjectReference"
RegexOptionList="IgnoreCase"
Replacement="#(MyMultiLineItem ->'%(Identity)')"
Files="#(TestFile)" />
</Target>
I have an NAnt task "ship" to package my current .sql scripts into a build, then name the build with an incrementing int {######} and copy it to a build folder.
I have another NAnt task which executes those build scripts.
They must execute in order, but in my last attempt, they were not. Can I "force" NAnt to work alphabetically?
FAIL:
<fileset basedir="source\tsql\builds\" id="buildfiles">
<include name="*.sql.template.sql" />
<exclude name="*.sql" />
<exclude name="*asSentTo*" />
</fileset>
<foreach item="File" property"filename">
<in refid="buildfiles">
<echo message="${filename}" />
</in>
</foreach>
PASS:
<foreach item="File" property="filename" in="source\tsql\builds">
<do>
<if test="${string::ends-with(filename,'.sql.template.sql')}">
<echo message="${filename}" />
</if>
</do>
</foreach>
To satisfy my curiosity I tried to reproduce the problem with this script:
<?xml version="1.0"?>
<project name="foreach.test" default="foreach.alpha">
<target name="foreach.alpha">
<foreach item="File" in="C:\foo" property="filename">
<do>
<echo message="${filename}" />
</do>
</foreach>
</target>
</project>
The filenames are printed out in alphabetical order. So conventional use of foreach already seems to be the solution to the problem.
Here is how you do it with a fileset
<fileset id="mySet">
<include name="*.sql" />
</fileset>
<copy>
<fileset refid="mySet" />
</copy>
<foreach item="File" property="filename">
<in>
<items refid="mySet" />
</in>
<do>
<echo message="Copied files: ${filename} to directory: ${Folder}." />
</do>
</foreach>