Given a list of directories:
<ItemGroup>
<Dirs Include="Foo\Dir1" />
<Dirs Include="Foo\Dir2" />
</ItemGroup>
How can I get a list of all subdirectories.
Transforming this list with "$(Identity)\**"
does not match anything and transforming with "$(Identity)\**\*"
and then with RelativeDir
yields only directories that contain files.
Currently I have to resort to C#:
<UsingTask TaskName="GetSubdirectories" TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<Directories ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<SubDirectories ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs"><![CDATA[
var result = new List<ITaskItem>();
foreach (var dirItem in Directories) {
foreach (var dir in Directory.GetDirectories(dirItem.ItemSpec, "*", SearchOption.AllDirectories)) {
if (dir.Contains(@"\.svn\") || dir.EndsWith(@"\.svn")) continue;
result.Add(new TaskItem(dir));
}
}
SubDirectories = result.ToArray();
]]></Code>
</Task>
</UsingTask>
<GetSubdirectories Directories="@(Dirs)">
<Output TaskParameter="SubDirectories" ItemName="SubDirs" />
</GetSubdirectories>
But I would like to know if there is an easier way.
Excerpted from the book "MSBuild Trickery":
<Import Project="EnableAllPropertyFunctions.tasks" />
<Target Name="GetSubdirectories">
<ItemGroup>
<Dirs Include="$([System.IO.Directory]::
EnumerateDirectories(
`.\Foo`,
`*`,
System.IO.SearchOption.AllDirectories))"
/>
</ItemGroup>
<Message Text="%(Dirs.Identity)" />
</Target>
You'll need to first enable the extended property function set by ensuring that the environment variable MSBuildEnableAllPropertyFunctions is set to the value 1 (that is what the imported .tasks file accomplishes, with an inline task).
Once @(Dirs) is set up, you can filter it with the Remove attribute to get rid of the Subversion folders.
<CreateItem Include="$(OutputFolder)\*\*.*">
<Output TaskParameter="Include" ItemName="FilesInSubFolders" />
</CreateItem>
<RemoveDuplicates Inputs="@(FilesInSubFolders->'%(RelativeDir)')">
<Output TaskParameter="Filtered" ItemName="SubDirs"/>
</RemoveDuplicates>
<Message Text="@(SubDirs)"/>
This will put all the immediate subfolder paths into @(SubDirs). If you change Include="$(OutputFolder)\*\*.*"
to Include="$(OutputFolder)\**\*.*"
, it'll include all subfolders recursively.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With