I have subdirectories in build output but files are copied to the root destination directory without applying %RecursiveDir.
<PropertyGroup>
<slnpath>.</slnpath>
<binpath>.\ProjName\</binpath>
<destination>..\..\deploy\ProjName\Master</destination>
<PropertyGroup>
<ItemGroup>
<DefaultExclude Include="$(slnpath)\.\**\*.svn-base"/>
<DefaultExclude Include="$(slnpath)\.\**\.svn\**"/>
<DefaultExclude Include="$(slnpath)\.\**\.git\**"/>
<DefaultExclude Include="$(slnpath)\.\**\.hg\**"/>
<DefaultExclude Include="$(slnpath)\.\**\*.log"/>
<DefaultExclude Include="$(slnpath)\.\**\log\*.*" />
</ItemGroup>
<CreateItem Include="$(slnpath)\$(binpath)bin\**\*.*" Exclude="#(DefaultExclude)">
<Output ItemName="FilesToCopy" TaskParameter="Include"/>
</CreateItem>
<Copy SourceFiles="#(FilesToCopy)"
DestinationFiles="#(FilesToCopy->'$(destination)\bin\%(RecursiveDir)%(Filename)%(Extension)')" />
Why it doesn't work?
Surprisingly, copying from another source directory below in the same script works:
<CreateItem Include="$(slnpath)\DeployOverride\All\**\*.*" Exclude="#(DefaultExclude)">
<Output ItemName="FilesToCopy" TaskParameter="Include" />
</CreateItem>
<Copy SourceFiles="#(FilesToCopy)"
DestinationFiles="#(FilesToCopy->'$(destination)\bin\%(RecursiveDir)%(Filename)%(Extension)')" />
Related
I am creating a build target in .csproj file in VS 2017
<Target Name="CopyPackage" AfterTargets="Pack">
<Copy
SourceFiles="$(OutputPath)..\$(PackageId).$(PackageVersion).nupkg"
DestinationFolder="\\myshare\packageshare\"
/>
</Target>
The "PackageId" and "PackageVersion" need to be mentioned in the .csproj file to accomplish the goal.
<PackageId>My Package</PackageId>
<PackageVersion>1.0.0</PackageVersion>
But I have variables defined in .nuspec file.
Is it possible to access any variable from .nuspec file inside the .csproj?
If you already have a .nuspec file and want to query its content, you can use MSBuild's XmlPeek task:
<Target Name="PrintVersions" AfterTargets="Pack">
<XmlPeek Namespaces="<Namespace Prefix='nu' Uri='http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd'/>"
XmlInputPath="$(NuspecFile)"
Query="/nu:package/nu:metadata/nu:id/text()">
<Output TaskParameter="Result" PropertyName="MyPackageId" />
</XmlPeek>
<XmlPeek Namespaces="<Namespace Prefix='nu' Uri='http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd'/>"
XmlInputPath="$(NuspecFile)"
Query="/nu:package/nu:metadata/nu:version/text()">
<Output TaskParameter="Result" PropertyName="PackageVersion" />
</XmlPeek>
<Message Importance="high" Text="PackageId: $(PackageId)" />
<Message Importance="high" Text="PackageVersion: $(MyPackageVersion)" />
</Target>
I saw this S.O question and have a similar requirement. This is what I have in a .targets file -
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="$(TeamBuildOutDir) != '' ">
<OutputPath>$(TeamBuildOutDir)\Assemblies</OutputPath>
</PropertyGroup>
How can I output to multiple folders?
e.g.- $(TeamBuildOutDir)\Assemblies2
TIA
Thanks Nick, The copy/paste mucked it up. This is what I tried -
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="$(TeamBuildOutDir) != '' ">
<OutputPath>$(TeamBuildOutDir)\Assemblies</OutputPath>
</PropertyGroup>
<Target Name="AfterBuild">
<Copy SourceFiles="$(OutputPath)\**\*.*" DestinationFolder="$(TeamBuildOutDir)\Assemblies2" />
</Target>
</Project>
I've also tried -
<Copy SourceFiles="$(OutputPath)\***\*.*" DestinationFolder="$(TeamBuildOutDir)\Assemblies2" />
and -
<Copy SourceFiles="$(OutputPath)\***\*.*" DestinationFolder="$(TeamBuildOutDir)\" />
in case the directory not being present caused an issue but still no luck.
Updated 7/28. Tried this but doesn't work still (no errors but the files are not present in the output directory. They are present in the Assemblies folder so I know the targets file is being triggered.) -
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="$(TeamBuildOutDir) != '' ">
<OutputPath>$(TeamBuildOutDir)\Assemblies</OutputPath>
</PropertyGroup>
<Target Name="AfterBuild">
<CreateItem Include="$(OutputPath)\**\*.*">
<Output ItemName="Outfiles" TaskParameter="Include" />
</CreateItem>
<Copy SourceFiles="#(Outfiles)" DestinationFiles="#(Outfiles->'$(TeamBuildOutDir)\%(relativedir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
</Target>
</Project>
You create an AfterBuild target with a copy task the contents of $(OutputPath) to $(TeamBuildOutDir)\Assemblies2.
<Target Name="AfterBuild">
<Copy SourceFiles="$(OutputPath)\**\*.*" DestinationFolder="$(TeamBuildOutDir)\Assemblies2" />
</Target>
Edit, updating this to include a test message, and include a "DependsOnTarget" attribute to see if we can get this to occur after the build process...
<Target Name="AfterBuild" DependsOnTarget="Build">
<Message Text="**** TEST **** " Importance="high" />
<Copy SourceFiles="$(OutputPath)\**\*.*" DestinationFolder="$(TeamBuildOutDir)\Assemblies2" />
</Target>
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>
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.
Problem: an ItemGroups array isn't correctly build based on the value passed in the exclude attribute.
If you run this scrip it creates some sample file then tries to create an array called TheFiles based on the Include/Exclude attributes, problem is when the Exclude is anything other than hardcoded or a very simple property it gets it wrong.
The target DynamicExcludeList's incorrectly selects these files:
.\AFolder\test.cs;.\AFolder\test.txt
The target HardcodedExcludeList's correctly selects these files:
.\AFolder\test.txt
Any help much appreciated, this is driving me nuts.
(note its msbuild v4)
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Run">
<Target Name="Run" >
<CallTarget Targets="CreateSampleFiles" />
<CallTarget Targets="DynamicExcludeList" />
<CallTarget Targets="HardcodedExcludeList" />
</Target>
<Target Name="CreateSampleFiles" >
<MakeDir Directories="AFolder" />
<WriteLinesToFile Lines="Test" File="AFolder\test.cs" Overwrite="true" />
<WriteLinesToFile Lines="Test" File="AFolder\test.txt" Overwrite="true" />
</Target>
<Target Name="DynamicExcludeList" >
<PropertyGroup>
<CommonFileExclusion>.\DIRECTORY_NAME_TOKEN\**\*.cs</CommonFileExclusion>
<FinalExcludes>$(CommonFileExclusion.Replace('DIRECTORY_NAME_TOKEN', 'AFolder'))</FinalExcludes>
</PropertyGroup>
<Message Text="FinalExcludes: $(FinalExcludes)" />
<ItemGroup>
<TheFiles
Include=".\AFolder\**\*;"
Exclude="$(FinalExcludes)"
/>
</ItemGroup>
<Message Text="TheFiles: #(TheFiles)" />
</Target>
<Target Name="HardcodedExcludeList" >
<PropertyGroup>
<FinalExcludes>.\AFolder\**\*.cs</FinalExcludes>
</PropertyGroup>
<Message Text="FinalExcludes: $(FinalExcludes)" />
<ItemGroup>
<TheFilesWithHardcodedExcludes
Include=".\AFolder\**\*;"
Exclude="$(FinalExcludes)"
/>
</ItemGroup>
<Message Text="TheFilesWithHardcodedExcludes: #(TheFilesWithHardcodedExcludes)" />
</Target>
</Project>
This is the output, note the differences between 'TheFiles' and 'TheFilesWithHardcodedExcludes'
PS C:\SVN\TrunkDeployment\TestMsBuild> msbuild .\Test.build.xml
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.1]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 8/10/2010 2:30:42 PM.
Project "C:\SVN\TrunkDeployment\TestMsBuild\Test.build.xml" on node 1 (default targets).
DynamicExcludeList:
FinalExcludes: .\AFolder\**\*.cs
TheFiles: .\AFolder\test.cs;.\AFolder\test.txt
HardcodedExcludeList:
FinalExcludes: .\AFolder\**\*.cs
TheFilesWithHardcodedExcludes: .\AFolder\test.txt
Done Building Project "C:\SVN\TrunkDeployment\TestMsBuild\Test.build.xml" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.06
EDITS
I've updated the above script to use the CreateItem, however there is still an issue when the list of items to exclude contains more than 1 path (i.e. the value of CommonFileExclusion has changed):
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Run">
<Target Name="Run" >
<CallTarget Targets="CreateSampleFiles" />
<CallTarget Targets="DynamicExcludeList" />
<CallTarget Targets="HardcodedExcludeList" />
</Target>
<Target Name="CreateSampleFiles" >
<MakeDir Directories="AFolder" />
<WriteLinesToFile Lines="Test" File="AFolder\test.cs" Overwrite="true" />
<WriteLinesToFile Lines="Test" File="AFolder\test.txt" Overwrite="true" />
<WriteLinesToFile Lines="Test" File="AFolder\test.vb" Overwrite="true" />
</Target>
<Target Name="DynamicExcludeList" >
<PropertyGroup>
<CommonFileExclusion>.\DIRECTORY_NAME_TOKEN\**\*.cs;.\DIRECTORY_NAME_TOKEN\**\*.vb;</CommonFileExclusion>
<FinalExcludes>$(CommonFileExclusion.Replace('DIRECTORY_NAME_TOKEN', 'AFolder'))</FinalExcludes>
</PropertyGroup>
<Message Text="FinalExcludes: $(FinalExcludes)" />
<CreateItem Include=".\AFolder\**\*;"
Exclude="$(FinalExcludes)">
<Output TaskParameter="Include" ItemName="TheFiles"/>
</CreateItem>
<Message Text="TheFiles: #(TheFiles)" />
</Target>
<Target Name="HardcodedExcludeList" >
<PropertyGroup>
<FinalExcludes>.\AFolder\**\*.cs;.\AFolder\**\*.vb</FinalExcludes>
</PropertyGroup>
<Message Text="FinalExcludes: $(FinalExcludes)" />
<CreateItem Include=".\AFolder\**\*;"
Exclude="$(FinalExcludes)">
<Output TaskParameter="Include" ItemName="TheFilesWithHardcodedExcludes"/>
</CreateItem>
<Message Text="TheFilesWithHardcodedExcludes: #(TheFilesWithHardcodedExcludes)" />
</Target>
</Project>
Ok, I tried a little and I think the problem comes from the fact that you use a property which represent SCALAR value for multiple values. I would recommend batching and transforming (see http://scottlaw.knot.org/blog/?p=402 and http://msdn.microsoft.com/en-us/library/ms171476.aspx). For example the following code is working :
<Target Name="DynamicExcludeList" >
<ItemGroup>
<ExtensionsExcluded Include="cs;vb" />
</ItemGroup>
<CreateItem Include=".\AFolder\**\*"
Exclude="#(ExtensionsExcluded->'.\AFolder\**\*.%(identity)')">
<Output TaskParameter="Include" ItemName="TheFiles"/>
</CreateItem>
<Message Text="TheFiles: #(TheFiles)" />
</Target>
In target DynamicExcludeList use CreateItem task instead of ItemGroup to dynamically generate your item :
<Target Name="DynamicExcludeList" >
<PropertyGroup>
<CommonFileExclusion>.\DIRECTORY_NAME_TOKEN\**\*.cs</CommonFileExclusion>
<FinalExcludes>$(CommonFileExclusion.Replace('DIRECTORY_NAME_TOKEN', 'AFolder'))</FinalExcludes>
</PropertyGroup>
<Message Text="FinalExcludes: $(FinalExcludes)" />
<CreateItem Include=".\AFolder\**\*;"
Exclude="$(FinalExcludes)">
<Output TaskParameter="Include" ItemName="TheFiles"/>
</CreateItem>
<Message Text="TheFiles: #(TheFiles)" />
</Target>
Theoretically ItemGroup and CreateItem are equivalent but I've seen case (dynamic situation) like this one when CreateItem must be use.