Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSBUild: Copy files with a name based on the original (following a pattern)

I have a set of files inside a folder. They all have a name which matches the pattern DR__.*. I want to copy them to another folder, but removing the DR__ prefix. How can I do this with MSBuild? I used to do it like this using NAnt:

<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>
like image 658
dario_ramos Avatar asked Mar 21 '11 13:03

dario_ramos


2 Answers

I agree with @Si's solution. But with MSBuild 4.0 you can do it with built in functionality. NAnt script is much clearer than mine. But I will add it as a solution just to show MSBuild 4.0 techniques:

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

Edit (by OP): To get this working, I had to replace $(DestinationFullPath)in Copy with @(DestinationFullPath), to match the number of Source and Destination Files. Also, I had to change the prefix to DR__, since DR__. wouldn't work.

like image 63
Sergio Rykov Avatar answered Sep 21 '22 05:09

Sergio Rykov


Recently I had to solve similar task and I did it using Item's metadata. Advantages of this solution are:

  1. Small build script size.
  2. Using standard System.String functions to get modified name.
  3. Custom metadata is copying with definition of new items, that based on existing items (e.g. Items <TempItemsBak Include="@(TempItems-> ... CustomTransform ... )"> will get original item's metadata values so you can use it for further processing)

<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>
like image 26
Ivan Samygin Avatar answered Sep 21 '22 05:09

Ivan Samygin