Multiple fully-qualified paths in a single Task

I need to pass two sets of fully qualified file names to a task. Fully qualified paths are required because the task, (NUnit, in my case), doesn't accept relative paths for every parameter.

The only way I know to get full paths from a relative path is to first create an item group,

<ItemGroup>
<Foo Include="*.foo"/>
</ItemGroup>

and then reference it with the following syntax,%(Foo.FullPath)So far, so good.

I need another (single) fully qualified path, this time for a single file.

<ItemGroup>
<Bar Include=".\Build\bar"/>
</ItemGroup>

Now, the problem arises when trying to use fullpaths in the same task.

<Exec Command ="ECHO FIRST: %(foo.fullpath) SECOND: %(bar.fullpath)" />

The above sample will iterate over the bar files, with the foo files empty, then iterate over the foo files, with the bar files empty. Not a very useful behavior, because both are needed in EACH task iteration.

1) Is there any way to convert a relative path to a fullpath besides the %(foo.fullpath) approach?
2) Is it possible to use more than one fullpath in a task? And if so, how?
3) Is there documentation (with simple examples) on how to mimic Nant's for-each in MSBuild? (I foundhttp://forums.microsoft.com/msdn/ShowPost.aspx?PostID=6862 to be way confusing.)

Thanks

[1691 byte] By [selfcomposed] at [2007-12-16]
# 1

I'm not sure exactly what behavior you're looking for, so I'll try two possible solutions to see if either of those is what you're after:

1. You'd like to pass the set of fullpaths from foo and the set of fullpaths from bar, in one task call. This is straightforward to accomplish with a transform:

<Exec Command="ECHO FIRST: @(Foo->'%(FullPath)') SECOND: @(Bar->'%(FullPath)')" />

In this example, each item list will be transformed into another item list whose elements contain the FullPath metadata as the ItemSpec. There will only be one call/iteration because there is no batching (the reference to FullPath is inside a transform).

2. You'd like to iterate over each element foo individually, but always pass the same value of bar. You could do this with a solution halfway between your original one and the one I explain above:

<Exec Command="ECHO FIRST: %(Foo.FullPath) SECOND: @(Bar->'%(FullPath)')" />

In this example, you'll end up with one call to the Exec task for each unique value of "FullPath" on the Foo items - and each call will have the same expansion of Bar.

Below are examples of each, let us know if that doesn't solve your problem.

Thanks,
jeff
tester on msbuild

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<ItemGroup>
<Foo Include="Sources\*.cs" />
<Bar Include="Sources\*.txt" />
</ItemGroup>

<Target Name="CompileMyProject">
<Message Text="Solution 1:" />
<Exec Command="ECHO FIRST: @(Foo->'%(FullPath)') SECOND: @(Bar->'%(FullPath)')" />

<Message Text="Solution 2:" />
<Exec Command="ECHO FIRST: %(Foo.FullPath) SECOND: @(Bar->'%(FullPath)')" />
</Target>

</Project>

C:\Basic>msbuild
Microsoft (R) Build Engine Version 2.0.50730.0
[Microsoft .NET Framework, Version 2.0.50730.0]
Copyright (C) Microsoft Corporation 2005. All rights reserved.

Build started 8/4/2005 6:28:58 PM.
__
Project "C:\Basic\MyProject.csproj" (default targets):

Target CompileMyProject:
Solution 1:
ECHO FIRST: C:\Basic\Sources\a.cs;C:\Basic\Sources\b.cs;C:\Basic\Sources\c.cs;C:\Basic\Sources\d.cs SECOND: C:\Basic
\Sources\1.txt;C:\Basic\Sources\2.txt;C:\Basic\Sources\3.txt;C:\Basic\Sources\4.txt
FIRST: C:\Basic\Sources\a.cs;C:\Basic\Sources\b.cs;C:\Basic\Sources\c.cs;C:\Basic\Sources\d.cs SECOND: C:\Basic\Sour
ces\1.txt;C:\Basic\Sources\2.txt;C:\Basic\Sources\3.txt;C:\Basic\Sources\4.txt
Solution 2:
ECHO FIRST: C:\Basic\Sources\a.cs SECOND: C:\Basic\Sources\1.txt;C:\Basic\Sources\2.txt;C:\Basic\Sources\3.txt;C:\Ba
sic\Sources\4.txt
FIRST: C:\Basic\Sources\a.cs SECOND: C:\Basic\Sources\1.txt;C:\Basic\Sources\2.txt;C:\Basic\Sources\3.txt;C:\Basic\S
ources\4.txt
ECHO FIRST: C:\Basic\Sources\b.cs SECOND: C:\Basic\Sources\1.txt;C:\Basic\Sources\2.txt;C:\Basic\Sources\3.txt;C:\Ba
sic\Sources\4.txt
FIRST: C:\Basic\Sources\b.cs SECOND: C:\Basic\Sources\1.txt;C:\Basic\Sources\2.txt;C:\Basic\Sources\3.txt;C:\Basic\S
ources\4.txt
ECHO FIRST: C:\Basic\Sources\c.cs SECOND: C:\Basic\Sources\1.txt;C:\Basic\Sources\2.txt;C:\Basic\Sources\3.txt;C:\Ba
sic\Sources\4.txt
FIRST: C:\Basic\Sources\c.cs SECOND: C:\Basic\Sources\1.txt;C:\Basic\Sources\2.txt;C:\Basic\Sources\3.txt;C:\Basic\S
ources\4.txt
ECHO FIRST: C:\Basic\Sources\d.cs SECOND: C:\Basic\Sources\1.txt;C:\Basic\Sources\2.txt;C:\Basic\Sources\3.txt;C:\Ba
sic\Sources\4.txt
FIRST: C:\Basic\Sources\d.cs SECOND: C:\Basic\Sources\1.txt;C:\Basic\Sources\2.txt;C:\Basic\Sources\3.txt;C:\Basic\S
ources\4.txt

Build succeeded.
0 Warning(s)
0 Error(s)

Time Elapsed 00:00:00.37

C:\Basic>

JefferyCallahan at 2007-9-9 > top of Msdn Tech,Visual Studio,Visual Studio MSBuild...
# 2

Thank you, that helped a lot.

Here is a little example I developed for the most common cases.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<ItemGroup>
<A Include="*.cs" />
<B Include="*.txt" />
</ItemGroup>

<Target Name="List, Batching and Transform Examples">

<Message Text="Environment variable: $(TEMP)"/>
<Message Text =" "/>


<Message Text="Iterate for each item (for-each): %(A.Identity)"/>
<Message Text =" "/>
<Message Text="Iterate for each item, single transform: %(A.fullpath)"/>
<Message Text =" "/>
<Message Text="Iterate for each item, multiple transforms: %(A.rootdir)%(directory)%(filename)%(extension)"/>
<Message Text =" "/>
<Message Text="Iterate task for each A, pass whole B list each time: %(A.Identity) @(B)"/>
<Message Text =" "/>
<Message Text="Iterate Cartesian product of A and B (for each A, for each B):Not possible. Write/use a task which accepts lists as

parameters"/>
<Message Text =" "/>

<Message Text="Default List: @(A)"/>
<Message Text =" "/>
<Message Text="List with Identity transform (same as above): @(A->'%(Identity)')"/>
<Message Text =" "/>
<Message Text="List with custom separator: @(A,'!')"/>
<Message Text =" "/>
<Message Text="Multiple lists (all passed to single task): @(A) @(B)"/>
<Message Text =" "/>
<Message Text="List with transform applied to each item: @(A->'%(FullPath)')"/>
<Message Text =" "/>
<Message Text="List with transform and arbitrary text: @(A->'%(filename).XYZ')"/>
<Message Text =" "/>
<Message Text="List with multiple transforms: @(A->'%(rootdir)%(directory)%(filename)%(extension)')"/>
<Message Text =" "/>


</Target>

</Project>

And the output is:

Target Simple Batching and Transform Examples:
Environment variable: C:\DOCUME~1\myself\LOCALS~1\Temp

Iterate for each item (for-each): bar.cs
Iterate for each item (for-each): foo.cs

Iterate for each item, single transform: C:\Temp\bar.cs
Iterate for each item, single transform: C:\Temp\foo.cs

Iterate for each item, multiple transforms: C:\Temp\bar.cs
Iterate for each item, multiple transforms: C:\Temp\foo.cs

Iterate task for each A, pass whole B list each time: bar.cs t.txt;x.txt;y.txt
Iterate task for each A, pass whole B list each time: foo.cs t.txt;x.txt;y.txt

Iterate Cartesian product of A and B (for each A, for each B):Not possible. Write/use a task which accepts lists as parameters

Default List: bar.cs;foo.cs

List with Identity transform (same as above): bar.cs;foo.cs

List with custom separator: bar.cs!foo.cs

Multiple lists (all passed to single task): bar.cs;foo.cs t.txt;x.txt;y.txt

List with transform applied to each item: C:\Temp\bar.cs;C:\Temp\foo.cs

List with transform and arbitrary text: bar.XYZ;foo.XYZ

List with multiple transforms: C:\Temp\bar.cs;C:\Temp\foo.cs

selfcomposed at 2007-9-9 > top of Msdn Tech,Visual Studio,Visual Studio MSBuild...

Visual Studio

Site Classified