アイテム グループ、ターゲット、およびコピー タスクについて多くのことを読んだ後、必要なことを実行する方法がわかりました。
<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.config に web.template.config がコピーされます。そうしないと、開発者の web.config ファイルがそのまま残り、変更されません。指定されたファイルのいずれもコピーする必要がない場合、ターゲットは完全にスキップされます。クリーンなリポジトリのクローンの直後に、すべてのファイルがコピーされます。
MSBuild を使い始めたばかりで、その強力な機能に驚いているため、上記は満足のいく解決策であることがわかりました。私が気に入らない唯一のことは、まったく同じ変換を 2 か所で繰り返さなければならなかったことです。どんな種類のコードも複製するのは嫌いですが、これを避ける方法がわかりませんでした。誰かがヒントを持っていれば、それは大歓迎です。また、これを必要とする開発プラクティスは完全に最悪だと思いますが、これはその最悪の要因を軽減するのに役立ちます。