MsBuild Copy output and remove part of path - msbuild

I have an MsBuild project which builds various solutions and then copies the output of Web Deployment Projects into a destination folder with two sub folder as follows:
The WDP output folders are copied over from the BuildFolder "Release".
DestFolder/PresentationTier/MyProject.xxx0Services_deploy/**Release**/Files...
DestFolder/MidTier/MyProject.xx1UI_deploy/**Release**/Files...
This works but I want to remove the $(Configuration) value from the output.
So the desired output folder layout is to be:
DestFolder/PresentationTier/MyProject.xxx0Services_deploy/Files...
DestFolder/MidTier/MyProject.xx1UI_deploy/Files...
Note the removal of "Release" folder
My code is below.
How can I change this to give the desired out please:
Code extract is as follows
<Target Name="CopyMidTierBuildOutput" DependsOnTargets="CopyPresentationTierBuildOutput" >
<Message Text="Copying midTier Build Output=================" />
<CreateItem Include="$(DeploymentRoot)**/MyProject.xxx0Services_deploy/$(Configuration)/**/*.*;
$(DeploymentRoot)**/MyProject.xxx1Services.Host_deploy/$(Configuration)/**/*.*;
$(DeploymentRoot)**/MyProject.xxx2.Host.IIS.csproj_deploy/$(Configuration)/**/*.*;
$(DeploymentRoot)**/MyProject.xxx3Services_deploy/$(Configuration)/**/*.*;
$(DeploymentRoot)**/Nad.xxx4_deploy/$(Configuration)/**/*.*;
$(DeploymentRoot)**/Nad.xxx5Services.Host_deploy/$(Configuration)/**/*.*;
$(DeploymentRoot)**/Nad.xxx6Services.Host_deploy/$(Configuration)/**/*.*;
$(DeploymentRoot)**/Nad.xxx7Service.Host.IIS_deploy/$(Configuration)/**/*.*;
$(DeploymentRoot)**/Nad.xxx8Services.Host_deploy/$(Configuration)/**/*.*;
$(DeploymentRoot)**/Nad.xxx9Service.Host.IIS.csproj_deploy/$(Configuration)/**/*.*;
$(DeploymentRoot)**/Nad.xxx10Services.Host_deploy/$(Configuration)/**/*.*">
<Output TaskParameter="Include" ItemName="MidTierDeploys"/>
</CreateItem>
<Copy
SourceFiles="#(MidTierDeploys)"
DestinationFolder="$(DestFolder)/MidTier/%(RecursiveDir)" ContinueOnError="false" />

You can implement expected behaviour with biltin features of MSBuild 4:
<ItemGroup>
<DeploymentProjects Include="1_deploy" />
<DeploymentProjects Include="2_deploy" />
</ItemGroup>
<Target Name="CopyMidTierBuildOutput" >
<Message Text="Copying midTier Build Output" Importance="High"/>
<ItemGroup>
<MidTierDeploys Include="$(DeploymentRoot)**\%(DeploymentProjects.Identity)\$(Configuration)\**\*.*">
<DeploymentProject>%(DeploymentProjects.Identity)</DeploymentProject>
</MidTierDeploys>
</ItemGroup>
<Msbuild Targets="CopyDeploymentItem"
Projects="$(MSBuildProjectFile)"
Properties="ItemFullPath=%(MidTierDeploys.FullPath);ItemRecursiveDir=%(MidTierDeploys.RecursiveDir);ItemDeploymentProject=%(MidTierDeploys.DeploymentProject);Configuration=$(Configuration);DestFolder=$(DestFolder)" />
</Target>
<Target Name="CopyDeploymentItem" >
<PropertyGroup>
<ItemExcludePath>$(ItemDeploymentProject)\$(Configuration)</ItemExcludePath>
<ItemDestRecursiveDirIndex>$(ItemRecursiveDir.IndexOf($(ItemExcludePath))) </ItemDestRecursiveDirIndex>
<ItemExcludePathLength>$(ItemExcludePath.Length)</ItemExcludePathLength>
<ItemSkippingCount>$([MSBuild]::Add($(ItemDestRecursiveDirIndex), $(ItemExcludePathLength)))</ItemSkippingCount>
<ItemDestRecursiveDir>$(ItemRecursiveDir.Substring($(ItemSkippingCount)))</ItemDestRecursiveDir>
</PropertyGroup>
<Copy
SourceFiles="$(ItemFullPath)"
DestinationFolder="$(DestFolder)/MidTier/$(ItemDeploymentProject)/$(ItemDestRecursiveDir)" ContinueOnError="false" />
</Target>
See Property functions for more info.

Related

MSBuild incremental build error

I am facing one problem in building and copying .NET solution output to a deployment folder.
What i want to do is. Build solution and put the output into C:\TempOutput
then copy the outfiles from C:\TempOutput to another deployment folder.
at 1st attemp it creates folder in C:\TempOutput and creates output dlls and exes in this folder
also it creates folder "Exec\Debug\Bin" but does not copy files from C:\TempOutput
logs says that
Target CopyBuildFiles:
Skipping target "CopyBuildFiles" because it has no outputs.
When i run the script again this time it copies the files from C:\TempOutput to "Exec\Debug\Bin"
Am i missing something? Why it is not detecting output at 1st attempt?
following is the msbuild script
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Deploy">
<PropertyGroup>
<ProjectName>Common Projects</ProjectName>
<SolutionFilePath>..\..\Solution\Solution.sln</SolutionFilePath>
<!--Build/Rebuild-->
<BuildType>Build</BuildType>
<!--Debug -> output : local-->
<!--Release -> output : local-->
<!--ProduDbg -> output : X:\Debug-->
<!--ProduRel -> output : X:\Release-->
<BuildMode>Debug</BuildMode>
<OutputPath>..\Exec\$(BuildMode)\Bin\</OutputPath>
<ExecPath>..\..\bin\$(BuildMode)</ExecPath>
<DestinitionFolder>$(OutputPath)</DestinitionFolder>
<SubDirPath>$(ExecPath)\**</SubDirPath>
<BuildFolder>C:\TempOutputs\</BuildFolder>
</PropertyGroup>
<ItemGroup>
<File Include="
$(BuildFolder)\*.*
"
Exclude="
$(BuildFolder)\*.vshost*
"
>
</File>
</ItemGroup>
<Target Name="PreBuild">
<MakeDir Directories="$(BuildFolder)" />
<MakeDir Directories="$(DestinitionFolder)" />
</Target>
<Target Name="Compile">
<MakeDir Directories="$(BuildFolder)" />
<!-- Build does build only-->
<Message Text="*******************************************************"/>
<Message Text="-->Building $(ProjectName)"/>
<Message Text="*******************************************************"/>
<Message Text="*******************************************************"/>
<Message Text="-->Building in [$(BuildMode) | $(BuildType)] mode"/>
<Message Text="*******************************************************"/>
<MSBuild Projects="$(SolutionFilePath)" Targets="$(BuildType)" Properties="Configuration=$(BuildMode);OutDir=$(BuildFolder)"/>
</Target>
<Target Name="CopyBuildFiles"
Inputs="#(File)"
Outputs=
"#(File->'$(DestinitionFolder)%(RecursiveDir)%(Filename)%(Extension)')">
<Copy SourceFiles="#(File)"
DestinationFiles="#(File->'$(DestinitionFolder)%(RecursiveDir)%(Filename)%(Extension)')"
/>
</Target>
<Target Name="Deploy">
<CallTarget Targets="PreBuild"/>
<CallTarget Targets="Compile"/>
<Message Text="*******************************************************"/>
<Message Text="#(File)"/>
<Message Text="$(DestinitionFolder)"/>
<Message Text="*******************************************************"/>
<CallTarget Targets="CopyBuildFiles"/>
</Target>
</Project>
Try changing this bit
<Target Name="CopyBuildFiles"
Inputs="#(File)"
Outputs="#(File->'$(DestinitionFolder)%(File.RecursiveDir)%(File.Filename)%(File.Extension)')">
<Copy SourceFiles="#(File)"
DestinationFiles="#(File->'$(DestinitionFolder)%(File.RecursiveDir)%(File.Filename)%(File.Extension)')"/>
</Target>

MS Build copy a list of directories stored in Item

I have a text file which contains some locations of the files which I want to copy to a temp directory
---- List.txt ----
Build\Java
Build\Classes
Now, I am fetching this list into an Item
<ReadLinesFromFile File="List.txt" >
<Output TaskParameter="Lines"
ItemName="DirectoryList" />
</ReadLinesFromFile>
Now, In order to append the full path, and add some excludes, I am again storing it into another ItemGroup:
<ItemGroup>
<PackageList Include="$(BuildPath)\%(DirectoryList.Identity)\**\*.*"
Exclude="$(BuildPath)\%(DirectoryList.Identity)\**\*.pdb" />
</ItemGroup>
<Copy SourceFiles="#(PackageList)"
DestinationFiles="#(PackageList->'$(PackageTemp)\%(SourceDirectory)\%(DirInPackage)%(RecursiveDir)%(Filename)%(Extension)')" />
ISSUE:
Actual Dir -
C:\Work\Build\Java\Debug
C:\Work\Build\Java\Release
C:\Work\Build\Classes\*.class
Content in O/p
C:\temp\Debug
C:\temp\Release
C:\temp\*.class
How to make it copy the corresponding "Java" and "Classes" folder also?
You missed just a few moments in your script. First, you need to create a directory from #(PackageList). Second, in Copy Task when you set DestinationFiles you should specify subdirectory explicitly.
Take a look. That scrip does the job as you need. And it holds internal structure of all your subdirectories, specified by wildcard. For example, Java\Debug\Component1\file.ext
<Project DefaultTargets="CopyDirectories" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildPath>.</BuildPath>
<SourceDirectoryListFile>Directories.txt</SourceDirectoryListFile>
<DestinationDirectory>temp</DestinationDirectory>
</PropertyGroup>
<Target Name="ReadDirectoryList">
<ReadLinesFromFile File="$(SourceDirectoryListFile)" >
<Output TaskParameter="Lines"
ItemName="DirectoryList" />
</ReadLinesFromFile>
</Target>
<Target Name="CopyDirectories" DependsOnTargets="ReadDirectoryList"
Outputs="%(DirectoryList.Identity)">
<PropertyGroup>
<ProcessingDirectory>%(DirectoryList.Identity)</ProcessingDirectory>
</PropertyGroup>
<ItemGroup>
<PackageList Include="$(BuildPath)\$(ProcessingDirectory)\**\*.*"
Exclude="$(BuildPath)\$(ProcessingDirectory)\**\*.pdb" />
</ItemGroup>
<MakeDir Directories="$(ProcessingDirectory)" />
<Copy SourceFiles="#(PackageList)"
DestinationFiles="#(PackageList->'$(DestinationDirectory)\$(ProcessingDirectory)\%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
Arpit,
You can use a kind of reversed solution: keep in List.txt the dirs you want excluded from copy.
Based on this you can create your copyfileslist using 2 sets of dirs.
So my solution looks like this:
---- List.txt ---- dirs to be excluded ---
Demos\AccessDatabase
Demos\ActiveDirectoryMsi
Demos\JavaToolsMsi
Demos\JavaToolsMsi\Data
Demos\LocalUserGroupsMsi
Demos\MSSQLDatabase
Demos\StringToolsMsi
Demos\SystemToolsMsi
Demos\TemplateFilesMsi
Demos\UserPrivilegesMsi
Demos\WindowsServiceMsi
Common
CustomActions
Framework
Tools
Version
WixExtensions
My msbuild.proj:
<Project DefaultTargets="run" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
<Target Name="run">
<PropertyGroup>
<BuildPath>c:\tmp\msiext\msiext-1.3\trunk\src</BuildPath>
<PackageTemp>c:\tmp\</PackageTemp>
</PropertyGroup>
<ReadLinesFromFile File="List.txt" >
<Output TaskParameter="Lines"
ItemName="DirectoryList" />
</ReadLinesFromFile>
<Message Text="DirectoryList: #(DirectoryList)" />
<ItemGroup>
<PackageList Include="$(BuildPath)\%(DirectoryList.Identity)\**\*.*"
Exclude="$(BuildPath)\%(DirectoryList.Identity)\**\*.sql" />
</ItemGroup>
<!--<Message Text="PackageList: #(PackageList)" />-->
<Message Text="----------------------------------------------------------------------------" />
<CreateItem Include="$(BuildPath)\**\*.*" Exclude="#(PackageList)">
<Output TaskParameter="Include" ItemName="NeededFiles"/>
</CreateItem>
<Message Text="NeededFiles: #(NeededFiles)" />
<Message Text="----------------------------------------------------------------------------" />
<Copy SourceFiles="#(NeededFiles)" DestinationFiles="#(NeededFiles->'$(PackageTemp)\%(RecursiveDir)\%(Filename)%(Extension)')" />
</Target>
</Project>

MSBuild find value in file

So I run my task with ccnet and my task creates files. What is the best way to read the file and identify if there is a certain value in it from msbuild??
It's depend on your file.
Plain text with multiple lines
If the file is like that :
Building XXX
...
BUILD SUCCESSFUL
Total time: 38 seconds
Buildfile: file.
You could use ReadLinesFromFile to read the file and CreateProperty with a Condition to check the value.
<PropertyGroup>
<ValueToCheck>BUILD SUCCESSFUL</ValueToCheck>
</PropertyGroup>
<Target Name="CheckValue">
<ReadLinesFromFile File="#(MyTextFile)" >
<Output TaskParameter="Lines" ItemName="Value"/>
</ReadLinesFromFile>
<CreateProperty Value="true"
Condition="'%(Value.Identity)' == '$(ValueToCheck)'">
<Output TaskParameter="Value" PropertyName="ValueIsPresent" />
</CreateProperty>
</Target>
Xml file
If the file is in Xml, you could use XmlPeek (MSBuild 4) or XmlRead from MSBuild Community Task.
How to use XmlPeek?
How to use XmlRead?
Here's what I did in MSBuild 4. It's a crude but native grep for MSBuild, with no pattern matching. This MSBuild project will look for files (FILES_TO_FIND) in a folder (SOURCE_FOLDER) that contain a string (STRING_TO_FIND).
After parsing the files, it prints a list of files that do not contain the string (FILES_THAT_DONT_MATCH), and a list of files that did (FILES_THAT_MATCH).
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0" DefaultTargets="Main">
<!-- Works as-is in MSBuild 4.0.30319.1 -->
<PropertyGroup>
<SOURCE_FOLDER>C:\MyCode</SOURCE_FOLDER>
<FILES_TO_SEARCH>*.sln</FILES_TO_SEARCH>
<STRING_TO_FIND>vcxproj</STRING_TO_FIND>
</PropertyGroup>
<ItemGroup>
<FILES_TO_SEARCH Include="$(SOURCE_FOLDER)\**\$(FILES_TO_SEARCH)"/>
</ItemGroup>
<Target Name="Main" DependsOnTargets="CheckForValue">
<Message Text="$(FILES_TO_SEARCH) files without '$(STRING_TO_FIND)':"
Importance="high"/>
<Message Text=" - %(FILES_THAT_DONT_MATCH.Identity)"/>
<Message Text=" "/>
<Message Text="$(FILES_TO_SEARCH) files with '$(STRING_TO_FIND)':"
Importance="high"/>
<Message Text=" - %(FILES_THAT_MATCH.Identity)"/>
</Target>
<Target Name="CheckForValue" Outputs="%(FILES_TO_SEARCH.Identity)">
<ReadLinesFromFile File="%(FILES_TO_SEARCH.Identity)" >
<Output TaskParameter="Lines" ItemName="LinesFromReadFile"/>
</ReadLinesFromFile>
<PropertyGroup>
<FileContent>#(LinesFromReadFile)</FileContent>
</PropertyGroup>
<ItemGroup>
<FILES_THAT_MATCH Include="%(FILES_TO_SEARCH.Identity)"
Condition="$(FileContent.Contains ('$(STRING_TO_FIND)'))"/>
<FILES_THAT_DONT_MATCH Include="%(FILES_TO_SEARCH.Identity)"
Condition="!$(FileContent.Contains ('$(STRING_TO_FIND)'))"/>
</ItemGroup>
</Target>
</Project>

MSBuild Copy task not copying files the first time round

I created a build.proj file which consists of a task to copy files that will be generated after the build is complete. The problem is that these files are not copied the first time round and I have to run msbuild again on the build.proj so that the files can be copied. Please can anyone tell me whats wrong with the following build.proj file:
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<SourcePath Condition="'$(SourcePath)' == ''">$(MSBuildProjectDirectory)</SourcePath>
<BuildDir>$(SourcePath)\build</BuildDir>
</PropertyGroup>
<ItemGroup>
<Projects
Include="$(SourcePath)\src\myApp\application.csproj">
</Projects>
</ItemGroup>
<Target Name="Build">
<Message text = "Building project" />
<MSBuild
Projects="#(Projects)"
Properties="Configuration=$(Configuration)" />
</Target>
<ItemGroup>
<OutputFiles Include ="$(MSBuildProjectDirectory)\**\**\bin\Debug\*.*"/>
</ItemGroup>
<Target Name="CopyToBuildFolder">
<Message text = "Copying build items" />
<Copy SourceFiles="#(OutputFiles)" DestinationFolder="$(BuildDir)"/>
</Target>
<Target Name="All"
DependsOnTargets="Build; CopyToBuildFolder"/>
</Project>
The itemgroups are evaluated when the script is parsed. At that time your files aren't there yet. To be able to find the files you'll have to fill the itemgroup from within a target.
<!-- SQL Scripts which are needed for deployment -->
<Target Name="BeforeCopySqlScripts">
<CreateItem Include="$(SolutionRoot)\04\**\Databases\**\*.sql">
<Output ItemName="CopySqlScript" TaskParameter="Include"/>
</CreateItem>
</Target>
This example creates the ItemGroup named "CopySqlScript" using the expression in the Include attribute.
Edit:
Now I can read your script: add the CreateItem tag within your CopyToBuildFolder target

Updating Assembly information with MSBuild failing

All
i am trying to automatically update the assembly information of a project using AssemblyInfo task, before build however the target appears to do nothing (no failure/error) just no update/creation
Below is the build.proj file I am using (obviously some contents altered)
Can anyone help?
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\AssemblyInfoTask\Microsoft.VersionNumber.targets"/>
<PropertyGroup>
<Major>1</Major>
<Minor>0</Minor>
<Build>0</Build>
<Revision>0</Revision>
</PropertyGroup>
<PropertyGroup>
<BuildDir>C:\svn\Infrastructure</BuildDir>
</PropertyGroup>
<ItemGroup>
<SolutionsToBuild Include="Infrastructure.sln"/>
</ItemGroup>
<Target Name="Build" DependsOnTargets="ChangeDataAccessAssemblyInfo">
<RemoveDir Directories="$(BuildDir)\Builds" Condition="Exists('$(BuildDir)\Builds')" />
<MSBuild Projects="#(SolutionsToBuild)" Properties="Configuration=Debug" Targets="Rebuild" />
</Target>
<ItemGroup>
<TestAssemblies Include="Build\Logging\Logging.UnitTests.dll" />
</ItemGroup>
<!--<UsingTask TaskName="NUnit" AssemblyFile="$(teamcity_dotnet_nunitlauncher_msbuild_task)" />
<Target Name="Test" DependsOnTargets="Build">
<NUnit NUnitVersion="NUnit-2.4.6" Assemblies="#(TestAssemblies)" />
</Target>-->
<Target Name="ChangeDataAccessAssemblyInfo" >
<Message Text="Writing ChangeDataAccessAssemblyInfo file for 1"/>
<Message Text="Will update $(BuildDir)\DataAccess\My Project\AssemblyInfo.vb" />
<AssemblyInfo CodeLanguage="VB"
OutputFile="$(BuildDir)\DataAccess\My Project\AssemblyInfo_new.vb"
AssemblyTitle="Data Access Layer"
AssemblyDescription="Message1"
AssemblyCompany="http://somewebiste"
AssemblyProduct="the project"
AssemblyCopyright="Copyright notice"
ComVisible="true"
CLSCompliant="true"
Guid="hjhjhkoi-9898989"
AssemblyVersion="$(Major).$(Minor).1.1"
AssemblyFileVersion="$(Major).$(Minor).5.7"
Condition="$(Revision) != '0' "
ContinueOnError="false" />
<Message Text="Updated Assembly File Info"
ContinueOnError="false"/>
</Target>
</Project>
I think you are missing the specification of the AssemblyInfoFiles attribute on your AssemblyInfo task. Here's how it looks on a project I'm working on...
<Target Name="AfterGet">
<Message Text="In After Get"/>
<CreateItem Include="$(SolutionRoot)\Source\SomeProject\My Project\AssemblyInfo.vb">
<Output ItemName="AssemblyInfoFiles" TaskParameter="Include"/>
</CreateItem>
<Attrib Files="#(AssemblyInfoFiles)"
ReadOnly="false"/>
<AssemblyInfo AssemblyInfoFiles="#(AssemblyInfoFiles)"
AssemblyDescription="$(LabelName)">
</AssemblyInfo>
</Target>
What we're doing is first using to create a property that contains the name of the file we'll be updating. We have to do this via createItem because when we start the build the file doesn't exist (and that is when MSBuild evaluates the and definitions in your build file.
We then take the readonly bit off the file.
Finally we invoke the AssemblyInfo task passing it the file(s) to update and a custom assembly name that we want to give it (in this case we put the TFS build label into the Assembly Description field so that we can easily tell which team build the assembly came from.