Как я могу заставить 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)'" />
Выход
Copying '' to 'c:\Program Files (x86)\Program\'
Я думаю, что вы правы, кто-нибудь знает способ перейти от Property к полному / абсолютному пути?
Вы могли бы "вроде" попасть туда, используя $ (ProjectDir) $ (Source_Dir), но у вас были бы лишние '..'





Уэйн прав в том, что хорошо известные метаданные не относятся к свойствам - только к элементам. Использование таких свойств, как «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>
Чувак, я узнал больше о том, как создать задачу MS из этого фрагмента кода выше, чем когда-либо в документации MSBuild. Спасибо! :-)
Вы пытаетесь получить доступ к свойству метаданных элемента через свойство, что невозможно. Вы хотите сделать что-то вроде этого:
<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\'
(Сценарий был запущен из моей папки Documents, поэтому .. \ Desktop - это правильный относительный путь для доступа к моему рабочему столу.)
В вашем случае замените ".. \ Desktop" на "...... \ Public \ Server" в элементе Source_Dir, и все будет готово.
+1 Это прекрасно работает, и я (как и другие) приземлился здесь в поисках способа канонизировать ItemGroup (в значительной степени предполагая, что пакет и копирование в новую ItemGroup были необходимы) - синтаксис, который вы показываете, делает это без этой путаницы. IOW я забыл про FullPathХорошо известные метаданные
Если вам нужно преобразовать свойства в элементы, у вас есть два варианта. С msbuild 2 вы можете использовать задачу CreateItem
<Target Name='Build'>
<CreateItem Include='$(Source_Dir)'>
<Output ItemName='SRCDIR' TaskParameter='Include' />
</CreateItem>
а с MSBuild 3.5 вы можете иметь ItemGroups внутри задачи
<Target Name='Build'>
<ItemGroup>
<SRCDIR2 Include='$(Source_Dir)' />
</ItemGroup>
<Message Text = "%(SRCDIR2.FullPath)" />
<Message Text = "%(SRCDIR.FullPath)" />
</Target>
В 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>, он не будет относиться к этому файлу.
В MSBuild 2.0, есть подход, который не разрешает "..". Однако он ведет себя так же, как абсолютный путь:
<PropertyGroup>
<Source_Dir_Abs>$(MSBuildProjectDirectory)$(Source_Dir)</Source_Dir_Abs>
</PropertyGroup>
Зарезервированное свойство $ (MSBuildProjectDirectory) всегда является каталогом сценария, содержащего эту ссылку.
Это также будет относиться к «исходному» файлу проекта, поэтому, если оно будет помещено в файл, который получает <Import>, он не будет относиться к этому файлу.
Будьте осторожны с [System.IO.Path]::GetFullPath. Я столкнулся с ошибкой построения в Visual Studio, потому что текущий рабочий каталог в msbuild был C:\Windows\System32. GetFullPath разрешается относительно рабочего каталога, а не каталога проекта.
@ChrisChilvers Это прискорбно. В прошлый раз, когда я тестировал это (правда, очень давно), это относилось к файлу, содержащему код.
Он также работает для обратной трассировки путей в стиле ..\..\your\path. Также обратите внимание, что макрос $(MSBuildThisFileDirectory) уже включает в себя завершающую косую черту, поэтому вы должны указать your\path без ведущей косой черты, то есть $(MSBuildThisFileDirectory)your\path. Один из случаев, когда это имеет значение, - это когда вы используете его для OutDir для Microsoft Unit Testing Framework Test, когда вы пытаетесь запустить тесты, он не сможет оценить `\\` в конкатенированном пути, чтобы найти построенную dll.
@AdamYaxley GetFullPath автоматически сворачивает двойную обратную косую черту, поэтому он будет работать, даже если у вас есть эта дополнительная обратная косая черта. Ваша проблема должна быть связана с чем-то другим.
В MSBuild 4.0 добавлен Функции собственности, который позволяет вызывать статические функции в некоторых системных dll .net. Что действительно хорошо в функциях свойств, так это то, что они будут оценивать вне целевой области.
Чтобы оценить полный путь, вы можете использовать System.IO.Path.GetFullPath при определении свойства следующим образом:
<PropertyGroup>
<Source_Dir>$([System.IO.Path]::GetFullPath('..\..\..\Public\Server\'))</Source_Dir>
</PropertyGroup>
Синтаксис немного уродливый, но очень мощный.
+1 Ой, чувак. Отлично! Именно то, что я искал. Спасибо.
Он также оценивает путь относительно (насколько я понимаю) файла проекта, в котором определено свойство, что очень удобно, если вы хотите включить это свойство в другие файлы. Для меня это было идеальное решение.
@JeanHominal Если вы используете <Import>, он все еще относительно места, куда он импортирован, что очень жаль. Тем не менее, это единственный подход, который также работает за пределами целей, что дает мне +1. См. этот ответ, чтобы узнать, как обойти проблему <Import>.
Да, я ошибся, когда сказал, что сделал - все относительные пути всегда относятся к пути «выполняемого проекта» (проекта, который в настоящее время выполняется MSBuild); однако вы можете использовать $(MSBuildThisFileDirectory), чтобы получить полный путь к каталогу исполняемого в данный момент файла.
Именно то, что мне нужно. Спасибо!
Я думаю, что метаданные FullPath применяются только к элементам <ItemGroup>, а не к свойствам <PropertyGroup>.