Как я могу заставить MSBUILD оценить и напечатать полный путь, если указан относительный путь? - PullRequest
54 голосов
/ 07 октября 2008

Как я могу заставить MSBuild оценить и напечатать в задаче <Message /> абсолютный путь с заданным относительным путем?

Группа недвижимости

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

Задача

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

выход

Копирование '' в 'c: \ Program Files (x86) \ Program \'

Ответы [ 5 ]

91 голосов
/ 09 августа 2009

В MSBuild 4.0 самый простой способ заключается в следующем:

$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)\your\path'))

Этот метод работает, даже если скрипт <Import> переведен в другой скрипт; путь относительно файла, содержащего вышеуказанный код.

(объединено с ответом Аарона , а также последней частью ответом Саида )


В MSBuild 3.5 вы можете использовать задачу ConvertToAbsolutePath :

<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>

Соответствующий вывод:

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

Немного скучно, если вы спросите меня, но это работает. Это будет относительно «исходного» файла проекта, поэтому, если поместить его в файл, который получает <Import> ed, это не будет относительно этого файла.


В MSBuild 2.0 есть подход, который не разрешает "..". Однако он ведет себя как абсолютный путь:

<PropertyGroup>
    <Source_Dir_Abs>$(MSBuildProjectDirectory)\$(Source_Dir)</Source_Dir_Abs>
</PropertyGroup>

Зарезервированное свойство $ (MSBuildProjectDirectory) всегда является каталогом скрипта, содержащего эту ссылку.

Это также будет относительно «исходного» файла проекта, поэтому, если поместить его в файл, который получает <Import> ed, это не будет относительно этого файла.

31 голосов
/ 04 февраля 2011

Добавлена ​​MSBuild 4.0 Функции свойств , которые позволяют вызывать статические функции в некоторых системных библиотеках .net. Очень хорошая вещь о свойствах функций в том, что они будут оценивать вне цели.

Чтобы оценить полный путь, вы можете использовать System.IO.Path.GetFullPath при определении свойства следующим образом:

<PropertyGroup>
  <Source_Dir>$([System.IO.Path]::GetFullPath('..\..\..\Public\Server\'))</Source_Dir>
</PropertyGroup>

Синтаксис немного уродливый, но очень мощный.

6 голосов
/ 07 октября 2008

Уэйн прав, что известные метаданные не применяются к свойствам - только к элементам. Использование таких свойств, как «MSBuildProjectDirectory», будет работать, но я не знаю встроенного способа разрешения полного пути.

Другой вариант - написать простую пользовательскую задачу, которая будет принимать относительный путь и выводить полностью разрешенный путь. Это будет выглядеть примерно так:

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;
    }
}

И ваши строки MSBuild будут выглядеть примерно так:

<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>
5 голосов
/ 07 октября 2008

Вы пытаетесь получить доступ к свойству метаданных элемента через свойство, которое невозможно. То, что вы хотите сделать, это что-то вроде этого:

<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>

Который будет генерировать вывод как:

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

(Сценарий был запущен из папки «Мои документы», поэтому .. \ Desktop - правильный относительный путь для доступа к моему рабочему столу.)

В вашем случае замените ".. \ Рабочий стол" на "...... \ Public \ Server" в элементе Source_Dir, и все должно быть готово.

4 голосов
/ 07 октября 2008

Если вам нужно преобразовать свойства в элементы, у вас есть два варианта. В msbuild 2 вы можете использовать задачу CreateItem

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

, а в MSBuild 3.5 вы можете создавать группы элементов внутри задачи

  <Target Name='Build'>
    <ItemGroup>
      <SRCDIR2 Include='$(Source_Dir)' />
    </ItemGroup>
    <Message Text="%(SRCDIR2.FullPath)" />
    <Message Text="%(SRCDIR.FullPath)" />
  </Target>
...