MsBuild: sort your Content item file names
I have been playing a bit with MsBuild to process a set of Content items sorted by file name. Content items are the items included in the project, and their Build Action set to Content. Below some sample code on how to achive this, just paste the code in a file sorttest.msbuild, and run as msbuild.exe sorttest.msbuild.
<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="SortTest" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ><
PropertyGroup> <SortCommand>$(WinDir)\System32\sort.exe</SortCommand> <ContentItemsSortInFile>$(TEMP)\sortfileIn.tmp</ContentItemsSortInFile> <ContentItemsSortOutFile>$(TEMP)\sortfileOut.tmp</ContentItemsSortOutFile> </PropertyGroup><
ItemGroup> <Content Include="SampleNorthwind\0002_content.testdata.sql" /> <Content Include="SampleNorthwind\0001_initial.schema.sql" /> <Content Include="SampleNorthwind\0004_employee-mobilephone.schema.sql" /> <Content Include="SampleNorthwind\0003_constraints.schema.sql" /> </ItemGroup><
Target Name="SortTest"> <WriteLinesToFile File="$(ContentItemsSortInFile)" Lines="@(Content)" Overwrite="true"/> <Exec Command="$(SortCommand) $(ContentItemsSortInFile) > $(ContentItemsSortOutFile)"/> <ReadLinesFromFile File="$(ContentItemsSortOutFile)"> <Output TaskParameter="Lines" ItemName="SortedContent"/> </ReadLinesFromFile> <!-- CLEAN UP TEMPORARY FILES --> <Delete Files="$(ContentItemsSortInFile)"/> <Delete Files="$(ContentItemsSortOutFile)"/><!--</span><span style="color: rgb(0,128,0)"> DO YOUR ACTION WITH SortedContent, FOR NOW, JUST WRITE IT OUT, ',' SEPARATED </span><span style="color: rgb(0,0,255)">--> <</span><span style="color: rgb(163,21,21)">Message</span><span style="color: rgb(0,0,255)"> </span><span style="color: rgb(255,0,0)">Text</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">@(SortedContent,',')</span>"<span style="color: rgb(0,0,255)">/>
</
Target> </Project>
UPDATED:
My collegue Dion Olsthoorn came with the following solution that is smarter:
- Get the files from filesystem, is sorted by default
- Determine all files NOT in project
- Get again files from filesystem, exclude files NOT in project
- Result is a set of sorted items as included in the project (as Content items)
Nifty nifty!
Replace this target in the code above:
<Target Name="SortTest" Outputs="%(Content.RelativeDir)">
<CreateItem Include="%(Content.RelativeDir)*" Exclude="@(Content)">
<Output TaskParameter="Include" ItemName="ExcludedSortedContent"/>
</CreateItem>
<CreateItem Include="%(Content.RelativeDir)*" Exclude="@(ExcludedSortedContent)">
<Output TaskParameter="Include" ItemName="SortedContent"/>
</CreateItem>
<Message Text="@(SortedContent,',')" />
</Target>