Condition using File::Exists not working

1.8k views Asked by At

I currently create my first MSBuild-script.

I've a tag "Folders" that findes all Directories in a given root path:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
  <Target Name="Build">
    <PropertyGroup>
      <RootFolder>tmp</RootFolder>
    </PropertyGroup>
    <ItemGroup>
      <Folders Include="$([System.IO.Directory]::GetDirectories(&quot;$(RootFolder)&quot;))"/>
    </ItemGroup>
    <Message Text="@(Folders -> '%(FullPath)\Bin\Debug\%(Filename)%(Extension).dll', ';')"/>
  </Target>
</Project>

That works perfect. My problem is that I only need directories where the specified file exists. I tried a condition like that

Condition="$([System.IO.File]::Exists(&quot;%(FullPath)\\Bin\\Debug\\%(Filename)%(Extension).dll&quot;))"

for the folder tag.

This script runs without any error but my list is empty. Why?

Are there any other solutions to check for a file?

I used this solution because it uses C# and I'm a C#-developer.

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
  <Target Name="Build">
    <PropertyGroup>
      <RootFolders>tmp</RootFolders>
    </PropertyGroup>
    <GetFiles rootFolders="$(RootFolders)">
      <Output PropertyName="Files" TaskParameter="Files" />
    </GetFiles>
    <Message Text="$(Files)" />
  </Target>

  <UsingTask
      TaskName="GetFiles"
      TaskFactory="CodeTaskFactory"
      AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
      <ParameterGroup>
        <rootFolders ParameterType="System.String" Required="true" />
        <files ParameterType="System.String" Output="true" />
      </ParameterGroup>
      <Task>
          <Using Namespace="System" />
          <Using Namespace="System.IO" />
          <Using Namespace="System.Linq" />
          <Code Type="Fragment" Language="cs">
              <![CDATA[               
                  Func<string, string> BuildFilePath = path => path + @"\Bin\Debug\" + Path.GetFileName(path) + ".dll";
                  var dirs = Directory.GetDirectories(rootFolders).Where(x => File.Exists(BuildFilePath(x)));
                  files = string.Join("\n", dirs.Select(BuildFilePath));
              ]]>
          </Code>
      </Task>
  </UsingTask>
</Project>
1

There are 1 answers

1
Isantipov On BEST ANSWER

AFAIK, the thing is Condition is executed and checked for the whole declaration of Items (i.e. <Folders ..> tag).

I think, you need to loop through the collection (e.g. using target/task batching) and check the file to exist in every single folder folder in the collection. Then if the file exists - include it in the new <FoldersFiletered> items collection.

NB: I don't have time to test the code now, but this is the idea roughly:

<Target Name="FilterFolders"
    Inputs="@(Folders)"
    Outputs="%(FullPath)">
    <ItemGroup>
    <FoldersFiltered Include="@(Folders->'%(FullPath)')"
        Condition="$([System.IO.File]::Exists(&quot;@(Folders->'%(FullPath)'\\Bin\\Debug\\YourFile.dll&quot;))" />
    </ItemGroup>
</Target>