-1

I have a Target which I want to run once if none of the files in my ItemGroup exist.

<ItemGroup>
    <Foo Include="a.txt;b.txt;c.txt" />
</ItemGroup>
<Target Name="Bar" Condition="?">

My question is what is what to put in the '?'.

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • http://msdn.microsoft.com/en-us/library/7szfhaft.aspx seems pretty straight forward. From the doc, I'd guess `"Exists('a.txt') And Exists('b.txt') And Exists('c.txt')"`. Though trying to do this stuff is what turned me off to the whole msbuild system in general. – IdeaHat Nov 11 '14 at 14:59
  • @MadScienceDreams So the goal of the question would be to interpolate each element of `Foo`. In my actual code I don't know the list of files contained by `Foo` at design time. – Jonathan Mee Nov 11 '14 at 15:07
  • 1
    Why the anonymous downvote? It seems like a perfectly good "how can I get MSBuild to do something that would be so simple in a real programming language" question. If there's some technicality, state what in the comment so we can all learn. – JDługosz Nov 11 '14 at 15:33

1 Answers1

1

You can use another Target to go through the file list (what Targets are good at!) and leave a result in a Property. Make a wrapper Target that is dependent on the tester Target and on Bar. Bar has a condition that uses the mechanism set by the first target.

Note that the global property set within a task is not seen until that task has finished, so the idiom is to wrap the thing producing the result and the thing consuming the result as dependents of an empty task.

I think you need to also make the tester a dependency of Bar as well, to make sure it gets the order correct.

Something like this:

<Target Name="TestLoop" Outputs="%(Foo.Identity)">
    <PropertyGroup>
        <Tested Condition="Exists(%(Foo.Identity))">Present</Tested>
    </PropertyGroup>
</Target>

After TestLoop is triggered, the Property Tested will be set to "Present" if and only if at least one of the files is present. That is, it codes a looping logical OR.

Now if you use this as a dependency:

<Target Name="Wrapper" DependsOnTargets="TestLoop;Bar" />

then you can have Bar look at the state left by TestLoop. Assuming they are executed in the correct order, not in parallel! To ensure that, also make TestLoop a prerequisite for Bar, and the build engine will determine the needed sequence and know not to try doing Bar until after TestLoop is done.

Oh, and Wrapper is the target to ask for. As described above, if you ask for Bar directly it will not see the property update (I think). So you might name them to make the Wrapper the exposed Bar, and your Bar an internal Bar_helper.

JDługosz
  • 5,592
  • 3
  • 24
  • 45
  • Nice, this solves what I'm looking for, but I don't know how to setup the dependency. – Jonathan Mee Nov 11 '14 at 15:22
  • I'm running Visual Studio 2010, I'm not allowed to use global properties apparently. MSBuild error: "error MSB4066: The attribute "Name" in element is unrecognized." I tried switching that line to `Present` and that seems to work. – Jonathan Mee Nov 11 '14 at 15:54
  • So it initially didn't work for me cause I didn't do what you suggested and create a `Wrapper` target that depended on both. Can you explain to me why the wrapper target is significant and why I can't just do: `` – Jonathan Mee Nov 11 '14 at 16:06
  • @JonathanMee yes, I typed the syntaxbwrong on the property (fixwd in edit). – JDługosz Nov 11 '14 at 23:36
  • I must be reading with all thumbs, I could have sworn you typed: "yes, I typed the syntax wrong on the property (fixed in edit)." – Jonathan Mee Nov 11 '14 at 23:45
  • Anyway as far as doing this without a wrapper, that's not possible? – Jonathan Mee Nov 11 '14 at 23:48
  • @JonathanMee in that case, the Condition is checked *first*. In general, I knew to use a wrapper because changed properties are not visible until (I don't recall the rule from memory). IAC, it skips dependencies of tasks that are not performed, so you can see the problem here. Since the ordering and parallelism is determined ahead of time, it must actually be testing the condition and pruning just before it would do any skippable dependencies. That is the driving requirement for the publishing rule of properties set by other tasks. – JDługosz Nov 11 '14 at 23:50
  • Possible? Maybe there are other ways, including writing custom task. Lots of stuff in the supplied .targets files works this way, somgo with it. Name the wrapper as the publicly named target and the details are internal. Look at MS's files for examples :) (sorry I wrote Task for Target in the previous long comment) – JDługosz Nov 11 '14 at 23:54