MSBUild: копирование файлов с именем на основе оригинала (по шаблону) - PullRequest
16 голосов
/ 21 марта 2011

У меня есть набор файлов внутри папки. У всех них есть имя, которое соответствует шаблону DR __. *. Я хочу скопировать их в другую папку, но удаляя префикс DR__. Как я могу сделать это с MSBuild? Я делал это, используя 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>

Ответы [ 4 ]

14 голосов
/ 21 марта 2011

Я согласен с решением @ Si. Но с MSBuild 4.0 вы можете сделать это со встроенным функционалом. Сценарий NAnt намного понятнее моего. Но я добавлю это в качестве решения, чтобы показать методы MSBuild 4.0:

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

Редактировать (по OP): чтобы это работало, мне пришлось заменить $(DestinationFullPath) в Copy на @(DestinationFullPath), чтобы соответствовать количеству исходных и целевых файлов. Кроме того, мне пришлось изменить префикс на DR__, так как DR__. не будет работать.

10 голосов
/ 13 марта 2013

Недавно мне пришлось решить аналогичную задачу, и я сделал это, используя метаданные Предмета. Преимущества этого решения:

  1. Небольшой размер сценария сборки.
  2. Использование стандартных функций System.String для получения измененного имени.
  3. Пользовательские метаданные копируются с определением новых элементов, которые основаны на существующих элементах (например, элементы <TempItemsBak Include="@(TempItems-> ... CustomTransform ... )"> получат значения метаданных исходного элемента, чтобы вы могли использовать их для дальнейшей обработки)

<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>
2 голосов
/ 24 апреля 2012

Мне недавно пришлось сделать что-то похожее на это, и в итоге я получил хакерское, но работоспособное решение, основанное на встроенных пользовательских задачах.

    <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)"/>
2 голосов
/ 21 марта 2011

Можете ли вы использовать MSBuild 4.0?Если это так, то обратитесь к этому ответу MSDN help ).В противном случае задача RegexReplace в MSBuildCommunityTasks также должна работать за счет поддержки внешнего инструмента (поэтому, если возможно, перейдите в MSBuild 4.0).

Другой (непроверенный) параметр - TextString задача в MSBuildExtensionPack .

Если их не выполнить, откатить свою собственную задачу?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...