使用MSBuild批量重命名

时间:2012-10-18 16:29:16

标签: msbuild continuous-integration batch-rename

我刚刚加入了一个没有CI流程的团队(甚至没有一夜之间的构建)和一些粗略的开发实践。有改变这一点的愿望,所以我现在的任务是创建一个过夜构建。我跟着this series篇文章来创建一个包含我们所有项目的主解决方案(一些Web应用程序,一个Web服务,一些Windows服务,以及编译成命令行可执行文件的几个关闭工具);创建了一个MSBuild脚本来自动构建,打包和部署我们的产品;并创建了一个.cmd文件,只需单击一下即可完成。这是我现在要完成的一项任务:

该团队目前的做法是将web.config和app.config文件保留在源代码控制之外,并放入名为web.template.config和app.template.config的源代码控制文件中。目的是开发人员将.template.config文件复制到.config以获取所有标准配置值,然后能够将.config文件中的值编辑为本地开发/测试所需的任何值。出于显而易见的原因,我想自动将.template.config文件重命名为.config。最好的方法是什么?

是否可以在构建脚本本身中执行此操作,而无需在脚本中规定每个需要重命名的文件(在将新项目添加到解决方案时需要对脚本进行维护)?或者我是否必须编写一些我只是从脚本运行的批处理文件?

此外,是否有一个更好的开发解决方案,我可以建议将整个过程变得不必要?

2 个答案:

答案 0 :(得分:6)

在阅读了很多关于项目组,目标和复制任务的内容后,我发现了如何做我需要的事情。

<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)')"/>



我创建了一个包含我要复制的文件的项目组。 **运算符告诉它递归整个目录树以查找具有指定名称的每个文件。然后,我为每个名为&#34; NewFilename&#34;的文件添加一段元数据。这就是我将每个文件重命名为。

此代码段添加名为app.template.config的目录结构中的每个文件,并指定我将命名新文件app.config:

<FilesToCopy Include="..\**\app.template.config">
    <NewFilename>app.config</NewFilename>
</FilesToCopy>

然后我创建一个目标来复制所有文件。此目标最初非常简单,只调用复制任务以便始终复制和覆盖文件。我将FilesToCopy项目组作为复制操作的来源传递。我使用transforms来指定输出文件名,以及我的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已被修改,开发人员可能 应该覆盖其本地文件,并且现在其中包含代码所需的新值。我尝试了很多不同的方法 - 设置Copy属性&#34; SkipUnchangedFiles&#34;使用&#34; Exist()&#34;功能 - 无济于事。

解决方法是building incrementally。这可确保只有app.template.config更新时才会覆盖文件。我将文件的名称作为目标输入传递,并将新文件名指定为目标输出:

<Target Name="CopyFiles"
        Input="@(FilesToCopy)"
        Output="@(FilesToCopy->'%(RootDir)%(Directory)%(NewFileName)')">
      ...
</Target>

这具有目标检查以查看当前输出是否相对于输入是最新的。如果它不是,即特定的.template.config文件比其对应的.config文件有更新的更新,那么它将通过现有的web.config复制web.template.config。否则,它将单独保留开发人员的web.config文件并且不进行修改。如果不需要复制任何指定的文件,则完全跳过目标。在完整的存储库克隆之后,将立即复制每个文件。

以上结果是一个令人满意的解决方案,因为我只是开始使用MSBuild而且我对其强大的功能感到惊讶。我唯一不喜欢的是我必须在两个地方重复完全相同的变换。我讨厌复制任何类型的代码,但我无法弄清楚如何避免这种情况。如果有人有小费,我们将不胜感激。此外,虽然我认为开发实践需要这一点非常糟糕,但这确实有助于减轻这个吸引因素。

答案 1 :(得分:1)

简答:
是的,您可以(并且应该)自动执行此操作。您应该可以使用MSBuild Move task重命名文件。

答案很长:
很高兴有一种从手动过程转变为自动过程的愿望。通常很少有真正的原因不能实现自动化。您的构建脚本将作为构建和部署实际工作方式的活文档。在我看来,一个好的构建脚本比静态文档更有价值(虽然我不是说你不应该有文档 - 毕竟它们相互排斥)。让我们分别解答您的问题。

最好的方法是什么?

我不完全了解您在这些文件中存储的配置,但我怀疑很多配置可以在开发团队中共享。

我建议提出以下问题:

  • 哪些设置是开发人员特定的?
  • 有没有办法标准化本地开发者机器以便共享设置?

是否可以在构建脚本本身中执行此操作,而无需在脚本中规定需要重命名的每个文件?

是的,请看MSBuild Move task。您应该可以使用它来重命名文件。

...只要将新项目添加到解决方案中,就需要对脚本进行维护?

这是不可避免的 - 您的构建脚本必须与您的解决方案一起发展。将此视为事实,并在您的估算中包含更改构建脚本的时间。

此外,是否有一个更好的开发解决方案,我可以建议这将使整个过程变得不必要?

我不了解所有要求,因此很难推荐非常具体的内容。我可以说建议:

  • 为您的解决方案创建共享构建脚本
  • 尽可能自动完成手动任务(在合理范围内)
  • 如果您正在努力实现自动化 - 它可能是需要重新考虑/重新设计的区域的指标
  • 确保您的团队成员了解构建的工作原理并能够自行更改 - 不要“拥有”构建并成为瓶颈

请记住,从无构建脚本到完全自动化不是一夜之间的过程。要有耐心,并首先关注导致最痛苦的区域的自动化。

如果我误解了你的任何问题,请告诉我,我会更新答案。