首页 > 解决方案 > MSBuild:复制文件条件输出路径

问题描述

我目前有一个具有以下项目布局的解决方案(此示例已简化和浓缩)

src
├──2019
|  └── Project.2019
|     └── Input
|        └── 1.txt
└──2020
   └── Project.2020
      └── Input
         └── 1.txt

我想将所有输入文件复制到以下层次结构

Input
├──2019
|  └── 1.txt
└──2020
   └── 1.txt

[System.IO.Directory]::GetDirectories能够匹配我想要的目录,但我不确定如何提取年份,并DestinationFolder使用复制任务正确设置

标签: msbuild

解决方案


Project.2019 和 Project.2020 是否包括项目?

我已经假设它确实如此,遵循以下结构:

directory.build.props
│
└───src
    │   CopyFiles.sln
    │
    ├───2019
    │   └───Project.2019
    │       │   Program.cs
    │       │   Project.2019.csproj
    │       │
    │       └───input
    │               1.txt
    │               2.txt
    │
    └───2020
        └───Project.2020
            │   Program.cs
            │   Project.2020.csproj
            │
            └───input
                    1.txt
                    2.txt

在每个文件夹中都有一个项目文件,允许我们在每个项目的上下文中执行自定义构建目标。这提供了一种构建文件列表(包含)的简单方法,并允许我们从 MSBuildProjectDirectory 上一个文件夹来获取年份。

输入文件 (InputOutputPath) 的最终输出路径假定存在 OutputRootPath 并且 OutputPath 用于覆盖默认的 msbuild 文件夹。我通常这样做是为了让所有输出都在 \output 中。但是您可以根据需要自定义这些。

它还期望每个需要复制文件的项目都将 CopyInputFiles 指定为 true。这也可以使用条件来完成,以防您希望它始终复制文件(如果 project\input*.txt 中有任何文件)

<PropertyGroup>
    <CopyInputFiles>true</CopyInputFiles>
</PropertyGroup>

目录.build.props:

<Target Name="CopyFiles" Condition="'$(CopyInputFiles)' == 'true'" >
  <ItemGroup>
    <InputFiles Include="$(MSBuildProjectDirectory)\input\*.txt" />
  </ItemGroup>
  <PropertyGroup>
    <Year>$([System.IO.Directory]::GetParent($(MSBuildProjectDirectory)).Name)</Year>
    <InputOutputPath>$(OutputRootPath)\$(Configuration)\Input\$(Year)\</InputOutputPath>
  </PropertyGroup>
  <Copy SourceFiles="@(InputFiles)" DestinationFolder="$(InputOutputPath)" />
</Target>

示例输出:

PS e:\repos\CopyFiles> msbuild .\src\CopyFiles.sln /t:copyfiles
Microsoft (R) Build Engine version 16.8.2+25e4d540b for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

Building the projects in this solution one at a time. To enable parallel build, please add the "-m" switch.
Build started 12/6/2020 12:56:07 PM.
Project "E:\repos\CopyFiles\src\CopyFiles.sln" on node 1 (copyfiles target(s)).
ValidateSolutionConfiguration:
  Building solution configuration "Debug|Any CPU".
Project "E:\repos\CopyFiles\src\CopyFiles.sln" (1) is building "E:\repos\CopyFiles\src\2019\Project.2019\Project.2019.csproj" (2) on node 1 (copyfiles target(s)).
CopyFiles:
  Creating directory "E:\repos\CopyFiles\Drops\Debug\Input\2019".
  Creating directory "E:\repos\CopyFiles\Drops\Debug\Input\2019".
  Copying file from "E:\repos\CopyFiles\src\2019\Project.2019\input\1.txt" to "E:\repos\CopyFiles\Drops\Debug\Input\2019\1.txt".
  Copying file from "E:\repos\CopyFiles\src\2019\Project.2019\input\2.txt" to "E:\repos\CopyFiles\Drops\Debug\Input\2019\2.txt".
Done Building Project "E:\repos\CopyFiles\src\2019\Project.2019\Project.2019.csproj" (copyfiles target(s)).

Project "E:\repos\CopyFiles\src\CopyFiles.sln" (1) is building "E:\repos\CopyFiles\src\2020\Project.2020\Project.2020.csproj" (3) on node 1 (copyfiles target(s)).
CopyFiles:
  Creating directory "E:\repos\CopyFiles\Drops\Debug\Input\2020".
  Copying file from "E:\repos\CopyFiles\src\2020\Project.2020\input\1.txt" to "E:\repos\CopyFiles\Drops\Debug\Input\2020\1.txt".
  Creating directory "E:\repos\CopyFiles\Drops\Debug\Input\2020".
  Copying file from "E:\repos\CopyFiles\src\2020\Project.2020\input\2.txt" to "E:\repos\CopyFiles\Drops\Debug\Input\2020\2.txt".
Done Building Project "E:\repos\CopyFiles\src\2020\Project.2020\Project.2020.csproj" (copyfiles target(s)).

Done Building Project "E:\repos\CopyFiles\src\CopyFiles.sln" (copyfiles target(s)).

使用生成的结构:

Drops
└───Debug
    ├───AnyCPU
    │   ├───Project.2019
    │   │   └───netcoreapp3.1
    │   └───Project.2020
    │       └───netcoreapp3.1
    └───Input
        ├───2019
        │       1.txt
        │       2.txt
        │
        └───2020
                1.txt
                2.txt

您可以在以下位置找到一个完整的示例:https ://github.com/Kencdk/msbuild_copyfiles_example

通过将目标设置为在项目中正在执行的任何其他构建目标之后执行,您可以将其连接到您的构建。例如:

<Target Name="CopyFiles" Condition="'$(CopyInputFiles)' == 'true'" AfterTargets="Build">

推荐阅读