MSBUild:使用基于原始文件的名称复制文件(遵循模式)

MSBUild:使用基于原始文件的名称复制文件(遵循模式),msbuild,copy,design-patterns,rename,Msbuild,Copy,Design Patterns,Rename,我在文件夹中有一组文件。它们都有一个与DR_uu;.*模式匹配的名称。我想将它们复制到另一个文件夹,但删除了DR__;前缀。如何使用MSBuild执行此操作?我以前用NAnt这样做: <mkdir dir="${ClientPath + '\bin\' + ConfigurationName + '\Parameters'}"/> <foreach item="File" property="Filename" in="CVParameters"> <if

我在文件夹中有一组文件。它们都有一个与DR_uu;.*模式匹配的名称。我想将它们复制到另一个文件夹,但删除了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>

您可以使用MSBuild 4.0吗?如果是,请参阅此(和)。否则,中的RegexReplace任务也应该可以工作,代价是必须支持外部工具(如果可能,请转到MSBuild 4.0)

另一个(未测试)选项是中的任务


如果这些都失败了,就开始你自己的任务吧?

我同意@Si的解决方案。但是,使用MSBuild 4.0,您可以使用内置功能完成此操作。南特文字比我的要清楚得多。但我将添加它作为解决方案,只是为了展示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>

%(CVParameters.FileName)%(CVParameters.Extension)
博士__
$(前缀.Length)
$(OriginalFileName.Length)
$([MSBuild]::减去($(原始文件名长度),$(前缀长度)))
$(原始文件名.子字符串($(前缀长度),$(子字符串长度)))
$([System.IO.Path]::合并($(DestinationDir),$(ModifiedFileName)))

编辑(按操作):为了使此工作正常,我必须将
$(DestinationFullPath)
中的
替换为
@(DestinationFullPath)
,以匹配源文件和目标文件的数量。此外,我还不得不将前缀改为
DR_uuuu
,因为
DR_uuu.
不起作用。

我最近也不得不做类似的事情,并最终得到了一个基于在线自定义任务的老练但可行的解决方案

    <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)"/>






最近,我不得不解决类似的任务,我使用项目的元数据来完成。 此解决方案的优点是:

  • 小的构建脚本大小
  • 使用标准System.String函数获取修改后的名称
  • 自定义元数据是使用新项目的定义进行复制的,新项目基于现有项目(例如,项目
    将获取原始项目的元数据值,以便您可以使用它进行进一步处理)
  • 
    .
    输出
    %(身份)
    %(递归目录)
    
    这个答案更直截了当,让我走上了正确的道路,让我对MSBuild技术有了一种感觉。谢谢关于MSBuild的MSDN文档有点缺乏,因此Sergio的回答更有帮助。但是我没有看到关于属性函数的东西,所以也要感谢你。没问题,达里奥,我同意塞吉奥的回答很有用+1对我来说2:)+1:我不知道这个选择。谢谢分享!可能重复的
      <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>