在大量阅读有关项目组、目标和复制任务的信息后,我已经弄清楚了如何做我需要的事情。
<ItemGroup>
<FilesToCopy Include="..\**\app.template.config">
<NewFilename>app.config</NewFilename>
</FilesToCopy>
<FilesToCopy Include="..\**\web.template.config">
<NewFilename>web.config</NewFilename>
</FilesToCopy>
<FilesToCopy Include"..\Hibernate\hibernate.cfg.template.xml">
<NewFilename>hibernate.cfg.xml</NewFilename>
</FilesToCopy>
</ItemGroup>
<Target Name="CopyFiles"
Inputs="@(FilesToCopy)"
Outputs="@(FilesToCopy->'%(RootDir)%(Directory)%(NewFilename)')">
<Message Text="Copying *.template.config files to *.config"/>
<Copy SourceFiles="@(FilesToCopy)"
DestinationFiles="@(FilesToCopy->'%(RootDir)%(Directory)%(NewFilename)')"/>
我创建了一个项目组,其中包含我要复制的文件。** 运算符告诉它递归遍历整个目录树以查找具有指定名称的每个文件。然后,我将一段元数据添加到每个名为“NewFilename”的文件中。这就是我将每个文件重命名为的内容。
此代码段在名为 app.template.config 的目录结构中添加每个文件,并指定我将命名新文件 app.config:
<FilesToCopy Include="..\**\app.template.config">
<NewFilename>app.config</NewFilename>
</FilesToCopy>
然后我创建一个目标来复制所有文件。这个目标最初非常简单,只调用 Copy 任务以便始终复制和覆盖文件。我将 FilesToCopy 项目组作为复制操作的源传递。我使用转换来指定输出文件名,以及我的 NewFilename 元数据和众所周知的项目元数据。
下面的代码片段例如将文件 c:\Project\Subdir\app.template.config 转换为 c:\Project\Subdir\app.config 并将前者复制到后者:
<Target Name="CopyFiles">
<Copy SourceFiles="@(FilesToCopy)"
DestinationFiles="@(FilesToCopy->'%(RootDir)%(Directory)%(NewFileName)')"/>
</Target>
但后来我注意到开发人员可能不喜欢每次运行脚本时都覆盖他自定义的 web.config 文件。但是,如果存储库的 web.template.config 已被修改,开发人员可能应该覆盖他的本地文件,并且现在其中包含代码所需的新值。我尝试了多种不同的方法——使用“Exist()”函数将 Copy 属性“SkipUnchangedFiles”设置为 true——但无济于事。
解决方案是逐步构建。这可确保仅当 app.template.config 较新时才会覆盖文件。我将文件名作为目标输入传递,并将新文件名指定为目标输出:
<Target Name="CopyFiles"
Input="@(FilesToCopy)"
Output="@(FilesToCopy->'%(RootDir)%(Directory)%(NewFileName)')">
...
</Target>
这具有目标检查以查看当前输出相对于输入是否是最新的。如果不是,即特定的 .template.config 文件比其对应的 .config 文件具有更多的最新更改,那么它将复制 web.template.config 覆盖现有的 web.config。否则,它将单独保留开发人员的 web.config 文件且未修改。如果不需要复制任何指定的文件,则完全跳过目标。在干净的存储库克隆之后,将立即复制每个文件。
上面结果是一个令人满意的解决方案,因为我才开始使用 MSBuild,我对它的强大功能感到惊讶。我唯一不喜欢的是我必须在两个地方重复完全相同的变换。我讨厌复制任何类型的代码,但我不知道如何避免这种情况。如果有人有小费,将不胜感激。此外,虽然我认为需要这样做的开发实践完全糟糕,但这确实有助于减轻这种糟糕的因素。