MSBUild: копировать файлы с именем на основе оригинала (по шаблону)
У меня есть набор файлов внутри папки. Все они имеют имя, которое соответствует шаблону 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>
Ответы
Ответ 1
Я согласен с решением @Si. Но с MSBuild 4.0 вы можете сделать это со встроенной функциональностью. NAnt script намного яснее моего. Но я добавлю это как решение, чтобы показать методы 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__.
не работает.
Ответ 2
Недавно мне пришлось решить аналогичную задачу, и я сделал это, используя метаданные Item.
Преимуществами этого решения являются:
- Малый размер сборки script.
- Использование стандартных функций System.String для получения измененного имени.
- Пользовательские метаданные копируют с определением новых элементов, которые основаны на существующих элементах (например, Элементы
<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 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>
Ответ 3
Можете ли вы использовать MSBuild 4.0? Если да, обратитесь к этому answer (и справка по MSDN). В противном случае задача RegexReplace в MSBuildCommunityTasks также должна работать, за счет необходимости поддержки внешнего инструмента (так что по возможности отправляйте MSBuild 4.0).
Другой (непроверенный) вариант - это TextString в MSBuildExtensionPack.
В противном случае выполните свою собственную задачу?
Ответ 4
Недавно мне пришлось сделать что-то похожее на это, и в итоге появилось хакерское, но работоспособное решение, основанное на встроенных пользовательских задачах.
<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)"/>