คัดลอกไฟล์และโฟลเดอร์ทั้งหมดโดยใช้ msbuild


94

แค่สงสัยว่าจะมีใครช่วยฉันด้วยสคริปต์ msbuild ที่ฉันพยายามเขียนอยู่ สิ่งที่ฉันต้องการทำคือคัดลอกไฟล์และโฟลเดอร์ย่อยทั้งหมดจากโฟลเดอร์ไปยังโฟลเดอร์อื่นโดยใช้ msbuild

{ProjectName}
      |----->Source
      |----->Tools
              |----->Viewer
                       |-----{about 5 sub dirs}

สิ่งที่ฉันต้องทำได้คือคัดลอกไฟล์และโฟลเดอร์ย่อยทั้งหมดจากโฟลเดอร์ tools ไปยังโฟลเดอร์ debug สำหรับแอปพลิเคชัน นี่คือรหัสที่ฉันมีจนถึงตอนนี้

 <ItemGroup>
<Viewer Include="..\$(ApplicationDirectory)\Tools\viewer\**\*.*" />
 </ItemGroup>

<Target Name="BeforeBuild">
        <Copy SourceFiles="@(Viewer)" DestinationFolder="@(Viewer->'$(OutputPath)\\Tools')" />
  </Target>

สคริปต์สร้างทำงาน แต่ไม่คัดลอกไฟล์หรือโฟลเดอร์ใด ๆ

ขอบคุณ

คำตอบ:


136

ฉันกำลังค้นหาความช่วยเหลือเกี่ยวกับเรื่องนี้ด้วย ฉันใช้เวลาสักพัก แต่นี่คือสิ่งที่ฉันทำได้ดีจริงๆ

<Target Name="AfterBuild">
    <ItemGroup>
        <ANTLR Include="..\Data\antlrcs\**\*.*" />
    </ItemGroup>
    <Copy SourceFiles="@(ANTLR)" DestinationFolder="$(TargetDir)\%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>

สิ่งนี้คัดลอกซ้ำเนื้อหาของโฟลเดอร์ที่ชื่อantlrcsไปยังไฟล์$(TargetDir).


4
ใช่นี่คือคำตอบที่ดีที่สุด เช่นเดียวกับที่แนะนำในบล็อกmsdn
Karsten

18
เคล็ดลับดูเหมือนว่าการเพิ่ม%(RecursiveDir)ไปยังโฟลเดอร์ปลายทางจะสร้างโครงสร้างไดเรกทอรีขึ้นมาใหม่ มิฉะนั้นเอาต์พุตจะแบน นี่คือคำตอบที่ดีที่สุด
. กับโมนิกา.

1
ต้องใส่ไว้ที่ด้านล่างของไฟล์. fsproj มิฉะนั้นจะไม่ใช้
Henrik

ช่วงเวลาสำคัญที่ได้ผลสำหรับฉันคือการย้ายการประกาศตัวแปร ( <ANTLR Include = ".. \ Data \ antlrcs ***. *" /> ) ภายใต้เป้าหมาย AfterBuild ในกรณีของฉันมันถูกประกาศในขอบเขตภายนอกและไม่ทำงาน
Shpand

นี่เป็นความคิดที่ดี! ฉันพบ%(RecursiveDir)ในข้อมูลเมตาของรายการที่รู้จักกันดีของ MSBuild : docs.microsoft.com/en-us/visualstudio/msbuild/…
kenjiuno

72

ฉันคิดว่าปัญหาอาจเกิดจากวิธีสร้าง ItemGroup ของคุณและเรียกงาน Copy ดูว่าเหมาะสมหรือไม่:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
    <PropertyGroup>
        <YourDestinationDirectory>..\SomeDestinationDirectory</YourDestinationDirectory>
        <YourSourceDirectory>..\SomeSourceDirectory</YourSourceDirectory>
    </PropertyGroup>

    <Target Name="BeforeBuild">
        <CreateItem Include="$(YourSourceDirectory)\**\*.*">
            <Output TaskParameter="Include" ItemName="YourFilesToCopy" />
        </CreateItem>

        <Copy SourceFiles="@(YourFilesToCopy)"
                DestinationFiles="@(YourFilesToCopy->'$(YourDestinationDirectory)\%(RecursiveDir)%(Filename)%(Extension)')" />
    </Target>
</Project>

CreateItemเลิกใช้งานแล้ว regex มีทางเลือกอื่น msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Ray Cheng

35

ฉันยังใหม่กับ MSBuild แต่ฉันพบว่างาน EXEC มีประโยชน์สำหรับสถานการณ์เช่นนี้ ฉันเจอความท้าทายเดียวกันในโครงการของฉันและสิ่งนี้ได้ผลสำหรับฉันและง่ายกว่ามาก ใครบางคนโปรดแจ้งให้เราทราบหากไม่ใช่แนวทางปฏิบัติที่ดี

<Target Name="CopyToDeployFolder" DependsOnTargets="CompileWebSite">
    <Exec Command="xcopy.exe  $(OutputDirectory) $(DeploymentDirectory) /e" WorkingDirectory="C:\Windows\" />
</Target>

9
ฉันกล้าถามคำถามอีกรอบ มีเหตุผลใดบ้างที่เคยใช้งานการคัดลอกการกรอก msbuild?
bernd_k

4
อาจเป็นไปได้ หากคุณมีฟาร์มสร้าง (Jenkins, TeamCity และอื่น ๆ ) บริการตัวแทนอาจทำงานภายใต้บัญชีอื่นที่ไม่มี xcopy ในเส้นทาง คุณสามารถลองสิ่งต่างๆเช่น% windir% \ system32 ในเส้นทางได้ แต่บางครั้งก็ไม่ได้ผล
Andrew dh

นั่นเป็นวิธีแก้ปัญหาที่เหมาะกับฉัน นอกจากนี้ฉันไม่จำเป็นต้องตั้งค่า WorkingDirectory
Aebsubis

FYI ฉันต้องเพิ่ม / Y เพื่อระงับพรอมต์การแทนที่ไฟล์ / โฟลเดอร์ นอกจากนี้หาก $ (DeploymentDirectory) เป็นโฟลเดอร์การทิ้ง "\" ไว้หลังพา ธ จะลบข้อความแจ้ง: "destination is folder or file?"
Hoàng Long

6
ฉันรู้ว่าปัญหานี้ไม่ได้เกิดขึ้นบ่อยนัก แต่เหตุผลหลักของฉันในการใช้Copyงานแทนคำสั่งคือความเข้ากันได้ ฉันเคยสร้างบน Linux โดยใช้ Mono มาก่อนและเห็นได้ชัดว่าใช้xcopyไม่ได้
GregRos

13
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
    <PropertyGroup>
        <YourDestinationDirectory>..\SomeDestinationDirectory</YourDestinationDirectory>
        <YourSourceDirectory>..\SomeSourceDirectory</YourSourceDirectory>
    </PropertyGroup>

    <Target Name="BeforeBuild">
        <CreateItem Include="$(YourSourceDirectory)\**\*.*">
            <Output TaskParameter="Include" ItemName="YourFilesToCopy" />
        </CreateItem>

        <Copy SourceFiles="@(YourFilesToCopy)"
                DestinationFiles="$(YourFilesToCopy)\%(RecursiveDir)" />
    </Target>
</Project>

\**\*.*ช่วยรับไฟล์จากโฟลเดอร์ทั้งหมด RecursiveDir ช่วยใส่ไฟล์ทั้งหมดในโฟลเดอร์ตามลำดับ ...


2
ไฟล์ปลายทางหมายถึง 1 รายการและไฟล์ต้นทางหมายถึง 33 รายการ ต้องมีจำนวนรายการเท่ากัน ฮึ .. msbuild น่ากลัว แต่บางครั้งก็มีการบันทึกข้อมูลขยะไว้ไม่ดี
The Muffin Man

CreateItemเลิกใช้งานแล้ว regex มีทางเลือกอื่น msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Ray Cheng

4

คุณพยายามระบุไดเร็กทอรีปลายทางที่เป็นรูปธรรมแทนที่จะเป็น

DestinationFolder="@(Viewer->'$(OutputPath)\\Tools')" ? 

ฉันไม่ค่อยเชี่ยวชาญกับไวยากรณ์ MSBuild ขั้นสูง แต่

@(Viewer->'$(OutputPath)\\Tools') 

ดูแปลกสำหรับฉัน สคริปต์ดูดีดังนั้นปัญหาอาจอยู่ในค่า$(ApplicationDirectory)และ$(OutputPath)

แก้ไข:

นี่คือบล็อกโพสต์ที่อาจเป็นประโยชน์:

วิธีการ: คัดลอกไฟล์ซ้ำ ๆ โดยใช้งาน


1
+1 สำหรับลิงก์ซึ่งกระชับกว่าคำตอบที่ยอมรับจาก zXen
bernd_k

3

นี่คือตัวอย่างที่ใช้งานได้:

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

   <ItemGroup>
      <MySourceFiles Include="c:\MySourceTree\**\*.*"/>
   </ItemGroup>

   <Target Name="CopyFiles">
      <Copy
        SourceFiles="@(MySourceFiles)"
        DestinationFiles="@(MySourceFiles->'c:\MyDestinationTree\%(RecursiveDir)%(Filename)%(Extension)')"
       />
    </Target>

</Project>

แหล่งที่มา: https://msdn.microsoft.com/en-us/library/3e54c37h.aspx


2

นี่คืองานคัดลอกที่ฉันใช้ในโปรเจ็กต์ของฉันมันทำงานได้อย่างสมบูรณ์แบบสำหรับฉันที่คัดลอกโฟลเดอร์ที่มีโฟลเดอร์ย่อยไปยังปลายทางสำเร็จ:

<ItemGroup >
<MyProjectSource Include="$(OutputRoot)/MySource/**/*.*" />
</ItemGroup>

<Target Name="AfterCopy" AfterTargets="WebPublish">
<Copy SourceFiles="@(MyProjectSource)" 
 OverwriteReadOnlyFiles="true" DestinationFolder="$(PublishFolder)api/% (RecursiveDir)"/>

ในกรณีของฉันฉันคัดลอกโฟลเดอร์เผยแพร่ของโครงการไปยังโฟลเดอร์ปลายทางอื่นฉันคิดว่ามันคล้ายกับกรณีของคุณ



0

วิธีที่ดีที่สุดในการคัดลอกไฟล์ซ้ำจากไดเร็กทอรีหนึ่งไปยังอีกไดเร็กทอรีโดยใช้ MSBuild คือการใช้งาน Copy โดยมี SourceFiles และ DestinationFiles เป็นพารามิเตอร์ ตัวอย่างเช่น - ในการคัดลอกไฟล์ทั้งหมดจากไดเร็กทอรี build ไปยังไดเร็กทอรีสำรองจะเป็น

<PropertyGroup>
<BuildDirectory Condition="'$(BuildDirectory)' == ''">Build</BuildDirectory>
<BackupDirectory Condition="'$(BackupDiretory)' == ''">Backup</BackupDirectory>
</PropertyGroup>

<ItemGroup>
<AllFiles Include="$(MSBuildProjectDirectory)/$(BuildDirectory)/**/*.*" />
</ItemGroup>

<Target Name="Backup">
<Exec Command="if not exist $(BackupDirectory) md $(BackupDirectory)" />
<Copy SourceFiles="@(AllFiles)" DestinationFiles="@(AllFiles-> 
'$(MSBuildProjectDirectory)/$(BackupDirectory)/%(RecursiveDir)/%(Filename)% 
(Extension)')" />
</Target>

ตอนนี้ในคำสั่งคัดลอกด้านบนไดเรกทอรีต้นทางทั้งหมดจะถูกส่งผ่านและไฟล์จะถูกคัดลอกไปยังไดเร็กทอรีปลายทาง


0

หากคุณกำลังทำงานกับ C ++ toolchain ทั่วไปอีกวิธีหนึ่งคือเพิ่มไฟล์ของคุณลงในรายการ CopyFileToFolders มาตรฐาน

<ItemGroup>
  <CopyFileToFolders Include="materials\**\*">
    <DestinationFolders>$(MainOutputDirectory)\Resources\materials\%(RecursiveDir)</DestinationFolders>
  </CopyFileToFolders>
</ItemGroup>

นอกจากจะง่ายแล้วนี่เป็นวิธีที่ดีเพราะงาน CopyFilesToFolders จะสร้างอินพุตเอาต์พุตและแม้แต่ไฟล์ TLog ที่เหมาะสมดังนั้นการดำเนินการคัดลอกจะทำงานเฉพาะเมื่อไฟล์อินพุตใดไฟล์หนึ่งมีการเปลี่ยนแปลงหรือไฟล์เอาต์พุตไฟล์ใดไฟล์หนึ่งหายไป ด้วย TLog Visual Studio จะรับรู้อย่างถูกต้องว่าโปรเจ็กต์ "เป็นปัจจุบัน" หรือไม่ (ใช้กลไก U2DCheck แยกต่างหากสำหรับสิ่งนั้น)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.