views:

2703

answers:

4

How can I get MSBuild to evaluate and print in a <Message /> task an absolute path given a relative path?

Property Group

<Source_Dir>..\..\..\Public\Server\</Source_Dir>
<Program_Dir>c:\Program Files (x86)\Program\</Program_Dir>

Task

<Message Importance="low" Text="Copying '$(Source_Dir.FullPath)' to '$(Program_Dir)'" />

Output

Copying '' to 'c:\Program Files (x86)\Program\'

+2  A: 

Wayne is correct that well-known metadata does not apply to properties - only to items. Using properties such as "MSBuildProjectDirectory" will work, but I'm not aware of a built in way to resolve the full path.

Another option is to write a simple, custom task that will take a relative path and spit out the fully-resolved path. It would look something like this:

public class ResolveRelativePath : Task
{
    [Required]
    public string RelativePath { get; set; }

    [Output]
    public string FullPath { get; private set; }

    public override bool Execute()
    {
     try
     {
      DirectoryInfo dirInfo = new DirectoryInfo(RelativePath);
      FullPath = dirInfo.FullName;
     }
     catch (Exception ex)
     {
      Log.LogErrorFromException(ex);
     }
     return !Log.HasLoggedErrors;
    }
}

And your MSBuild lines would look something like:

<PropertyGroup>
    <TaskAssembly>D:\BuildTasks\Build.Tasks.dll</TaskAssembly>
    <Source_Dir>..\..\..\Public\Server\</Source_Dir>
    <Program_Dir>c:\Program Files (x86)\Program\</Program_Dir>
</PropertyGroup>
<UsingTask AssemblyFile="$(TaskAssembly)" TaskName="ResolveRelativePath" />

<Target Name="Default">
    <ResolveRelativePath RelativePath="$(Source_Dir)">
    <Output TaskParameter="FullPath" PropertyName="_FullPath" />
    </ResolveRelativePath>
    <Message Importance="low" Text="Copying '$(_FullPath)' to '$(Program_Dir)'" />
</Target>
muloh
Dude, I have learnt more about how to build an MS Task from that piece of code above, then I ever have in the MSBuild documentation.Thank you! :-)
evilhomer
+2  A: 

You are trying to access an item metadata property through a property, which isn't possible. What you want to do is something like this:

<PropertyGroup>
  <Program_Dir>c:\Program Files (x86)\Program\</Program_Dir>
</PropertyGroup>
<ItemGroup>
   <Source_Dir Include="..\Desktop"/>
</ItemGroup>     
<Target Name="BuildAll">
   <Message Text="Copying '%(Source_Dir.FullPath)' to '$(Program_Dir)'" />
</Target>

Which will generate output as:

 Copying 'C:\Users\sdorman\Desktop' to 'c:\Program Files (x86)\Program\'

(The script was run from my Documents folder, so ..\Desktop is the correct relative path to get to my desktop.)

In your case, replace the "..\Desktop" with "......\Public\Server" in the Source_Dir item and you should be all set.

Scott Dorman
+1  A: 

If you need to convert Properties to Items you have two options. With msbuild 2, you can use the CreateItem task

  <Target Name='Build'>
    <CreateItem Include='$(Source_Dir)'>
      <Output ItemName='SRCDIR' TaskParameter='Include' />
    </CreateItem>

and with MSBuild 3.5 you can have ItemGroups inside of a Task

  <Target Name='Build'>
    <ItemGroup>
      <SRCDIR2 Include='$(Source_Dir)' />
    </ItemGroup>
    <Message Text="%(SRCDIR2.FullPath)" />
    <Message Text="%(SRCDIR.FullPath)" />
  </Target>
Scott Weinstein
+8  A: 

In MSBuild 3.5, you can use the ConvertToAbsolutePath task:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
         DefaultTargets="Test"
         ToolsVersion="3.5">
  <PropertyGroup>
    <Source_Dir>..\..\..\Public\Server\</Source_Dir>
    <Program_Dir>c:\Program Files (x86)\Program\</Program_Dir>
  </PropertyGroup>

  <Target Name="Test">
    <ConvertToAbsolutePath Paths="$(Source_Dir)">
      <Output TaskParameter="AbsolutePaths" PropertyName="Source_Dir_Abs"/>
    </ConvertToAbsolutePath>
    <Message Text='Copying "$(Source_Dir_Abs)" to "$(Program_Dir)".' />
  </Target>
</Project>

Relevant output:

Project "P:\software\perforce1\main\XxxxxxXxxx\Xxxxx.proj" on node 0 (default targets).
  Copying "P:\software\Public\Server\" to "c:\Program Files (x86)\Program\".

A little long-winded if you ask me, but it works. Any suggestions on how to make this shorter are welcome!

romkyns