MSBuild:以通用的方式复制多个目录

3

我有一个Visual Studio解决方案,其中包含多个Web项目(例如WebappA、WebappB、WebappC)。当TFS构建该解决方案时,它会将构建结果放在一个名为_PublishedWebsites的文件夹中。文件夹结构可能如下所示:

$(OutDir)
|
+-- _PublishedWebsites
    |
    +-- WebappA
    |
    +-- WebappA_Package
    |
    +-- WebappB
    |
    +-- WebappB_Package
    |
    +-- WebappC
    |
    +-- WebappC_Package

我希望为我们的运营部门建立一个部署包,以zip文件的形式提供。因此,我让TFS运行一个MSBuild脚本,将_Package文件夹复制到自定义目录结构中,并在随后的步骤中进行压缩。

$(PackageDirectory)
|
+-- Web
    |
    +-- WebappA
    |
    +-- WebappB
    |
    +-- WebappB

我能够创建一堆MSBuild目标来执行复制操作。但是我对我的解决方案不满意。我以显式方式引用每个webapp,这就是为什么我最终得到了很多重复的代码。更糟糕的是,每次添加新的webapp时,我都必须扩展构建脚本。

<Target Name="Pack" DependsOnTargets="Pack-WebappA;Pack-WebappB;Pack-WebappC" />

<Target Name="Pack-WebappA">
    <ItemGroup>
        <WebAppFile Include="$(OutDir)_PublishedWebsites\WebappA_Package\*.*" />
    </ItemGroup>
    <Copy SourceFiles="@(WebAppFile)" DestinationFolder="$(PackageDirectory)Web\WebappA\"  />
</Target>

<Target Name="Pack-WebappB">
    <ItemGroup>
        <WebAppFile Include="$(OutDir)_PublishedWebsites\WebappB_Package\*.*" />
    </ItemGroup>
    <Copy SourceFiles="@(WebAppFile)" DestinationFolder="$(PackageDirectory)Web\WebappB\"  />
</Target>

<Target Name="Pack-WebappC">
    <ItemGroup>
        <WebAppFile Include="$(OutDir)_PublishedWebsites\WebappC_Package\*.*" />
    </ItemGroup>
    <Copy SourceFiles="@(WebAppFile)" DestinationFolder="$(PackageDirectory)Web\WebappC\"  />
</Target>

我正在寻找一种通用的解决方案,不需要引用具体的Web应用程序。实质上,MSBuild所要做的就是查看_PublishedWebsites文件夹,并将每个带有“_Package”后缀的子文件夹复制到另一个文件夹中,并删除后缀。这听起来很简单,但我没有想出可行的解决方案。我尝试使用批处理,但未成功。
2个回答

3
您基本上是正确的,不满意当前解决方案:自动化这些事情是必须的。我同意 MsBuild 并不总是那么简单;批处理是正确的方式,但您需要添加一些筛选/操作项目。使用属性函数并不算难:property functions

实质上,MSBuild 应该做的就是查看 _PublishedWebsites 文件夹,将每个带有 _Package 后缀的子文件夹复制到另一个文件夹并删除后缀。

我们来翻译一下:
  • 列出 _PublishedWebsites 中的所有目录
  • 筛选列表,并仅包括以 _Package 结尾的目录
  • 列出这些目录中的所有文件,并将它们的目的地设置为 PackageDirectory 的子目录,删除后缀
  • 将每个文件复制到相应的目录
第3步实际上是两件事情(列表+指定目录),因为这是常见的 msbuild 方式。还有其他方法可以实现此功能,但是这种方式在这里似乎很合适。
<Target Name="BatchIt">
  <PropertyGroup>
    <SourceDir>$(OutDir)_PublishedWebsites\</SourceDir>
    <DestDir>$(PackageDirectory)Web\</DestDir>
    <PackageString>_Package</PackageString>
  </PropertyGroup>

  <ItemGroup>
    <!-- step 1 -->
    <Dirs Include="$([System.IO.Directory]::GetDirectories( `$(SourceDir)`, `*`, System.IO.SearchOption.AllDirectories ) )"/>

    <!-- step 2 -->
    <PackageDirs Include="%(Dirs.Identity)" Condition="$([System.Text.RegularExpressions.Regex]::IsMatch( %(Filename), '.*$(PackageString)' ) )"/>

    <!-- step 3 -->
    <PackageFiles Include="%(PackageDirs.Identity)\*.*">
      <DestDir>$(PackageDirectory)$([System.IO.Path]::GetFilename( %(PackageDirs.Identity) ).Replace( $(PackageString), '' ) )</DestDir>
    </PackageFiles>
  </ItemGroup>

  <!-- step 4 -->
  <Copy SourceFiles="%(PackageFiles.Identity)" DestinationFolder="%(PackageFiles.DestDir)" />
</Target>

编辑 更高效、更合乎逻辑的方法是在构建PackageDir列表时直接指定DestDir:

  <ItemGroup>
    <Dirs Include="$([System.IO.Directory]::GetDirectories( `$(SourceDir)`, `*`, System.IO.SearchOption.AllDirectories))"/>
    <PackageDirs Include="%(Dirs.Identity)" Condition="$([System.Text.RegularExpressions.Regex]::IsMatch( %(Filename), '.*$(PackageString)' ))">
      <DestDir>$(DestDir)$([System.IO.Path]::GetFilename( %(Dirs.Identity) ).Replace( $(PackageString), '' ))</DestDir>
    </PackageDirs>
    <PackageFiles Include="%(PackageDirs.Identity)\*.*">
      <DestDir>%(PackageDirs.DestDir)</DestDir>
    </PackageFiles>
  </ItemGroup>

0

Stijn提供了一个非常好的答案。它对我几乎起作用了。我只改变了一两个东西。这是代码,至少在我的情况下可以解决问题。

<Target Name="PackWeb">
  <PropertyGroup>
    <SourceDir>$(OutDir.TrimEnd('\'))\_PublishedWebsites\</SourceDir>
    <PackDir>$(PackageDirectory.TrimEnd('\'))\Web\</PackDir>
    <PackageString>_Package</PackageString>
  </PropertyGroup>

  <ItemGroup>
    <Dirs Include="$([System.IO.Directory]::GetDirectories( `$(SourceDir)`, `*` ) )"/>

    <PackageDirs Include="%(Dirs.Identity)" Condition="$([System.Text.RegularExpressions.Regex]::IsMatch( %(FullPath), '.*$(PackageString)' ) )"/>

    <PackageFiles Include="%(PackageDirs.Identity)\*.*">
      <DestDir>$(PackDir)$([System.IO.Path]::GetFilename( %(PackageDirs.Identity) ).Replace( $(PackageString), '' ) )</DestDir>
    </PackageFiles>
  </ItemGroup>

  <Copy SourceFiles="%(PackageFiles.Identity)" DestinationFolder="%(PackageFiles.DestDir)" />
</Target>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接