2008-10-07 14 views
53

¿Cómo puedo hacer que MSBuild evalúe e imprima en una tarea <Message /> una ruta absoluta dada una ruta relativa?¿Cómo puedo obtener MSBUILD para evaluar e imprimir la ruta completa cuando se le da una ruta relativa?

Property Group

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

Tarea

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

salida

copia '' a 'c: \ Archivos de programa (x86) \ programa \ '

+0

Creo que los metadatos de FullPath solo se aplican a los elementos , no a las propiedades de . – lesscode

+0

Creo que tienes razón, ¿alguien sabe cómo llegar desde la propiedad a una ruta completa/absoluta? –

+1

Podrías "llegar" usando $ (ProjectDir) $ (Source_Dir), pero tendrías superfluo '..' s – lesscode

Respuesta

86

En MSBuild 4.0, la forma más fácil es la siguiente :

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

Este método funciona incluso si el guión es <Import> ed en otra secuencia de comandos; la ruta es relativa al archivo que contiene el código anterior.

(consolidado desde Aaron's answer, así como la última parte de Sayed's answer)


En MSBuild 3.5, se puede utilizar el ConvertToAbsolutePath tarea:

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

salida relevante:

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

Un poco largo si me preguntas, pero funciona. Esto será relativo al archivo de proyecto "original", por lo que si se coloca dentro de un archivo que obtiene <Import> ed, esto no será relativo a ese archivo.


En MSBuild 2.0, no es un enfoque que no se resuelve "..". Sin embargo, sí se comportan como una ruta absoluta:

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

El $(MSBuildProjectDirectory) propiedad reservada es siempre el directorio del script que contiene esta referencia.

Esto también será relativo al archivo de proyecto "original", por lo que si se coloca dentro de un archivo que obtiene <Import> ed, esto no será relativo a ese archivo.

+0

Tenga cuidado con' [System.IO.Path] :: GetFullPath '. Corrí a un edificio de error en Visual Studio porque el directorio de trabajo actual en msbuild era 'C: \ Windows \ System32'. 'GetFullPath' se resuelve en relación con el directorio de trabajo en lugar del directorio del proyecto. –

+0

@ChrisChilvers Eso es desafortunado. La última vez que probé esto (desde hace mucho tiempo), fue relativo al archivo que contiene el código. –

+0

También funciona para rutas de estilo '.. \ .. \ your \ path' de retroceso. También tenga en cuenta que la macro '$ (MSBuildThisFileDirectory)' ya incluye una barra inclinada, por lo que debe especificar 'su \ ruta' sin la barra inicial i.e '$ (MSBuildThisFileDirectory) your \ path'. Un caso en el que esto es importante es cuando lo usa para un 'OutDir' para una Prueba del Marco de Prueba de la Unidad de Microsoft, cuando intente ejecutar las pruebas no podrá evaluar el' \\\ 'en la ruta concatenada para encontrar el dll. –

6

Wayne tiene razón en que los metadatos bien conocidos no se aplican a las propiedades, solo a los elementos. Usar propiedades como "MSBuildProjectDirectory" funcionará, pero no conozco un camino integrado para resolver la ruta completa.

Otra opción es escribir una tarea simple y personalizada que tomará una ruta relativa y escupirá la ruta totalmente resuelta. Se vería algo como esto:

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

Y sus líneas de MSBuild sería algo como:

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

Dude, He aprendido más sobre cómo crear una tarea MS a partir de esa pieza de el código anterior, luego lo tengo en la documentación de MSBuild. ¡Gracias! :-) – evilhomer

5

Usted está intentando acceder a una propiedad del elemento de metadatos a través de una propiedad, lo cual no es posible. Lo que se quiere hacer es algo como esto:

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

que generará salida como:

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

(El script se ha ejecutado desde la carpeta Mis documentos, por lo .. \ Desktop es la ruta relativa correcta para llegar a mi escritorio.)

En su caso, reemplace ".. \ Desktop" con "...... \ Public \ Server" en el elemento Source_Dir y debe estar todo listo.

+0

+1 Esto funciona bien y yo (como otros) llegué aquí buscando una manera de canonicalizar un ItemGroup (suponiendo que era necesario un lote y copiar a un nuevo ItemGroup) - la sintaxis que muestra lo hace sin esa confusión . IOW Me había olvidado de 'FullPath' [Metadatos conocidos] (http://msdn.microsoft.com/en-us/library/ms164313.aspx) –

4

Si necesita convertir Propiedades en Elementos, tiene dos opciones. Con msbuild 2, puede utilizar la tarea CreateItem

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

y con MSBuild 3.5 se puede tener ItemGroups dentro de un grupo de

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

MSBuild 4.0 agregó Property Functions que le permiten llamar a funciones estáticas en algunos de los dlls del sistema .net. Algo realmente bueno acerca de las funciones de propiedad es que evaluarán el lado de un objetivo.

para evaluar una ruta completa se puede utilizar System.IO.Path.GetFullPath la hora de definir una propiedad de este modo:

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

La sintaxis es un poco feo, pero muy potente.

+0

+1 Oh hombre. ¡Esto es genial! Exactamente lo que estaba buscando. Gracias. – Asaf

+0

Un gran consejo. Gracias. –

+0

También evalúa la ruta relativa (hasta donde veo) el archivo de proyecto donde se define la propiedad, lo cual es muy bueno cuando se desea incluir esa propiedad en otros archivos. Para mí, fue la solución perfecta. –

Cuestiones relacionadas