2011-03-21 13 views
15

Tengo un conjunto de archivos dentro de una carpeta. Todos ellos tienen un nombre que coincide con el patrón DR __. *. Quiero copiarlos a otra carpeta, pero eliminando el prefijo DR__. ¿Cómo puedo hacer esto con MSBuild? Solía ​​hacerlo así usando NAnt:MSBUild: Copiar archivos con un nombre basado en el original (siguiendo un patrón)

<mkdir dir="${ClientPath + '\bin\' + ConfigurationName + '\Parameters'}"/> 
<foreach item="File" property="Filename" in="CVParameters"> 
    <if test="${string::contains(Filename, Client + '_')}"> 
     <property name="newFilename" value="${ string::substring(Filename, string::last-index-of(Filename, '__') + 2, string::get-length(Filename) - string::last-index-of(Filename, '__') - 2) }"/> 
     <copy file="${ Filename }" tofile="${ ClientPath + '\bin\' + ConfigurationName + '\Parameters\' + newFilename }" overwrite="true"/> 
    </if> 
</foreach> 
+0

Posible duplicado de [No se puede hacer que MSBuild Community Task RegexReplace funcione] (http://stackoverflow.com/questions/7177257/cant-get-msbuild-community-task-regexreplace-to-work) –

Respuesta

14

Estoy de acuerdo con la solución de @ Si. Pero con MSBuild 4.0 puedes hacerlo con funcionalidad incorporada. La secuencia de comandos de NAnt es mucho más clara que la mía. Pero voy a añadir como una solución sólo para mostrar MSBuild 4.0 técnicas:

<ItemGroup> 
     <CVParameters Include="$(YourBaseDir)\**\DR__*" /> 
    </ItemGroup> 

    <Target Name="CopyAndRename" 
      Condition="'@(CVParameters)'!=''" 
      Outputs="%(CVParameters.Identity)"> 
     <PropertyGroup> 
      <OriginalFileName>%(CVParameters.FileName)%(CVParameters.Extension)</OriginalFileName>   
      <Prefix>DR__</Prefix> 
      <PrefixLength>$(Prefix.Length)</PrefixLength> 
      <OriginalFileNameLength>$(OriginalFileName.Length)</OriginalFileNameLength> 
      <SubstringLength>$([MSBuild]::Subtract($(OriginalFileNameLength),$(PrefixLength)))</SubstringLength> 
      <ModifiedFileName>$(OriginalFileName.Substring($(PrefixLength),$(SubstringLength)))</ModifiedFileName> 
      <DestinationFullPath>$([System.IO.Path]::Combine($(DestinationDir),$(ModifiedFileName)))</DestinationFullPath> 
     </PropertyGroup>                                   

     <Copy SourceFiles="%(CVParameters.FullPath)" 
       DestinationFiles="@(DestinationFullPath)" 
       SkipUnchangedFiles="true" /> 
    </Target> 

Editar (por OP): Para conseguir este trabajo, he tenido que cambiar $(DestinationFullPath) en Copy con @(DestinationFullPath), para que coincida con el número de origen y Archivos de destino. Además, tuve que cambiar el prefijo a DR__, ya que DR__. no funcionaría.

+0

Esta respuesta es más directa, me puso en el camino correcto y me dio una idea de las técnicas de MSBuild. ¡Gracias! –

+0

No se puede saber cómo llamar a ese objetivo desde afuera ... –

2

¿Se puede usar MSBuild 4.0? Si es así, consulte este answer (y MSDN help). De lo contrario, la tarea RegexReplace en MSBuildCommunityTasks también debería funcionar, a costa de tener que admitir una herramienta externa (así que vaya a MSBuild 4.0 si es posible).

Otra opción (no probados) es la tarea TextString en MSBuildExtensionPack.

En su defecto, ¿realiza su propia tarea?

+0

MSDN Documentation about MSBuild falta un poco, por lo que la respuesta de Sergio fue más útil. Pero no había visto nada sobre las funciones de propiedad, así que gracias a ti también. –

+0

Sin problemas Darío, ¡estoy de acuerdo en que la respuesta de Sergio fue útil! +1 para mí 2 :) – si618

2

Recientemente, tuve que hacer algo similar a esto, y terminé con una solución ingeniosa pero útil basada en tareas personalizadas en línea.

<UsingTask TaskName="GetNewFileName" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"> 
    <ParameterGroup> 
     <OriginalFile ParameterType="System.String" Required="true" /> 
     <PackageVersion ParameterType="System.String" Required="true" /> 
     <NewFile Output="true" /> 
    </ParameterGroup> 
    <Task> 
     <Code Type="Fragment" Language="cs"> 
     <![CDATA[ 

     int versionIndex = OriginalFile.IndexOf(PackageVersion); 
     versionIndex = versionIndex < 0 ? OriginalFile.Length : versionIndex; 

     NewFile = OriginalFile.Substring(0,versionIndex) + "nupkg"; 

     ]]> 
     </Code> 
    </Task> 
    </UsingTask> 

    <UsingTask TaskName="Combine" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"> 
    <ParameterGroup> 
     <Path ParameterType="System.String" Required="true" /> 
     <File ParameterType="System.String" Required="true" /> 
     <FullPath Output="true" /> 
    </ParameterGroup> 
    <Task> 
     <Code Type="Fragment" Language="cs"> 
     <![CDATA[ 
     FullPath = System.IO.Path.Combine(Path, File); 
    ]]> 
     </Code> 
    </Task> 
    </UsingTask> 

<Target Name="AfterCompile" Condition="'$(IsDesktopBuild)'!='true'"> 

    <ItemGroup> 
     <Nuspecs Include="$(SolutionRoot)\$(WorkingBranch)\Nuspec\**\*.nuspec"/> 
    </ItemGroup> 

    <!-- Build nugets --> 
    <Message Text="DEBUG: Build nuget packages" /> 
    <Exec 
     WorkingDirectory="$(NuspecsPath)" 
      Condition="" 
      Command='$(NugetPath) pack "%(Nuspecs.FullPath)" -Version 1.0.0.$(PackageVersion)' /> 

    <ItemGroup> 
     <Nupkgs2 Include="$(NuspecsPath)\**\*.nupkg"/> 
    </ItemGroup> 

    <GetNewFileName OriginalFile="%(Nupkgs2.FileName)%(Nupkgs2.Extension)" PackageVersion="$(PackageVersion)"> 
     <Output ItemName="RenamedNuPkgs" TaskParameter="NewFile"/> 
    </GetNewFileName> 

    <Combine File="%(RenamedNuPkgs.Filename)%(RenamedNuPkgs.Extension)" Path="$(NugetRepository)"> 
     <Output ItemName="PackagesRepository" TaskParameter="FullPath"/> 
    </Combine> 

    <Message Text="Renamed nuget packages: @(RenamedNuPkgs)"/> 
    <Message Text="Repository Renamed nuget packages: @(PackagesRepository)"/> 

    <Copy SourceFiles="@(Nupkgs2)" DestinationFiles="@(PackagesRepository)"/> 
+0

+1: No sabía de esta alternativa. ¡Gracias por compartir! –

10

Recientemente tuve que resolver una tarea similar y lo hice usando los metadatos de Item. Las ventajas de esta solución son:

  1. Tamaño de script de construcción pequeño.
  2. Utilizando las funciones estándar de System.String para obtener el nombre modificado.
  3. metadatos personalizado es copiar la definición de nuevos artículos, que en base a los elementos existentes (por ejemplo partidas <TempItemsBak Include="@(TempItems-> ... CustomTransform ...)"> obtendrán valores de metadatos del elemento original para que pueda usarlo para su posterior procesamiento)

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

<PropertyGroup> 
    <InputDir Condition="'$(InputDir)' == '' ">.</InputDir> 
    <OutputDir Condition="'$(OutputDir)' == '' ">Output</OutputDir> 
    </PropertyGroup> 

    <ItemGroup> 
    <CVParameters Include="$(InputDir)\**\DR__.*" /> 
    </ItemGroup> 

    <Target Name="CopyNoPrefix"> 
    <ItemGroup> 
     <!-- Items with new name. Use System.String's Remove method to get full file name without prefix --> 
     <!-- http://msdn.microsoft.com/en-us/library/vstudio/ee886422(v=vs.100).aspx --> 
     <TempItems Include="@(CVParameters->'%(Filename)%(Extension)'->Remove(0, 5))"> 
     <!-- Define metadata based on original item for next step --> 
     <OriginalPath>%(Identity)</OriginalPath> 
     <SavedRecursiveDir>%(RecursiveDir)</SavedRecursiveDir> 
     </TempItems> 
    </ItemGroup> 

    <!-- Use new items along with their metadata for copying --> 
    <Copy SourceFiles="@(TempItems->'%(OriginalPath)')" DestinationFiles="@(TempItems->'$(OutputDir)\%(SavedRecursiveDir)%(Identity)')" /> 
    </Target> 

</Project> 
Cuestiones relacionadas