NuGet 包:运行 安装后的 MSBUILD

NuGet Package: Run MSBUILD upon Installation

我正在创建一个 NuGet 程序包,并且有一个 .targets 文件在安装程序包时安装到目标 .csproj 文件中。这完全符合预期,.targets 文件有一个 Target 元素,该元素在 Build 和 TransformOnBuild 目标之前执行。

不过,我现在要做的是在安装包后执行这个Target。也就是说,我不希望用户在安装我的包后必须手动构建他们的 .csproj。我希望在将包安装到目标项目后将包安装到 运行 这个定义的 Target

原因是 Target 在目标项目中自动生成了一些文件(并且基于在目标项目中找到的属性),我希望这些文件在安装时使用初始数据生成,而不是等到用户构建该项目来创建数据。

FWIW,我发现最接近这个问题的是这个问题:Configure NuGet package to add a build event when installed,但这是针对构建管道的。我想在安装 NuGet 项目后启动构建(我的 Target 在 .targets 文件中)。

编辑:

多亏了@matt-ward,我才能够得出这个最终答案。我在这里分享完整的答案。它递归地遍历项目以查找任何 .tt 文件,并将其自定义工具设置为空白,然后编译项目以生成所需的工件。这是完整的安装。ps1:

# Runs every time a package is installed in a project

param($installPath, $toolsPath, $package, $project)

# $installPath is the path to the folder where the package is installed.
# $toolsPath is the path to the tools directory in the folder where the package is installed.
# $package is a reference to the package object.
# $project is a reference to the project the package was installed to.


function AdjustCustomTool( $folder )
{
    foreach ( $i in $folder.ProjectItems )
    {
        switch ( $i.Kind ) 
        { 
            "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}" # Folder
            {
                AdjustCustomTool( $i );
                break;
            } 
            "{6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}" # File
            {
                switch ( [System.IO.Path]::GetExtension( $i.Name ) )
                {
                    ".tt"
                    {
                        $i.Properties.Item("CustomTool").Value = "";
                        break;
                    }
                }
            }
        }       
    }
}
$templates = $project.ProjectItems.Item( "DragonSpark.Templates" );
AdjustCustomTool( $templates );

# Need to load MSBuild assembly if it's not loaded yet.
Add-Type -AssemblyName 'Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'

# Grab the loaded MSBuild project for the project
$project = [Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.GetLoadedProjects($project.FullName) | Select-Object -First 1
$project.Build( "GenerateTemplateReferences" );

FWIW,这是我的 .targets 文件:

        <Error Condition="'@(TargetReferenceFile -> Count())' == 0" Text="No DragonSpark.Templates\Generated\References.tt file found" />
        <Error Condition="'@(IncludesFile -> Count())' == 0" Text="No DragonSpark.Templates\Generated\Includes.tt file found" />

        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;# /* AUTOGENERATED FILE */ #&gt;" Overwrite="true" Encoding="Unicode" />

        <!-- T4Toolbox -->
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ include file=&quot;T4Toolbox.tt&quot; #&gt;" Overwrite="false" Encoding="Unicode" />
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ assembly name=&quot;&quot; completion=&quot;T4Toolbox.dll&quot; #&gt;" Overwrite="false" Encoding="Unicode" />

        <!-- Visual Studio IDE -->
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ assembly name=&quot;EnvDTE, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&quot; #&gt;" Overwrite="false" Encoding="Unicode" />
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ assembly name=&quot;EnvDTE80, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&quot; #&gt;" Overwrite="false" Encoding="Unicode" />
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ assembly name=&quot;VSLangProj, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&quot; #&gt;" Overwrite="false" Encoding="Unicode" />
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ assembly name=&quot;Microsoft.VisualStudio.Shell.Interop.8.0, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&quot; #&gt;" Overwrite="false" Encoding="Unicode" />
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ assembly name=&quot;Microsoft.VisualStudio.TextTemplating.Interfaces.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL&quot; #&gt;" Overwrite="false" Encoding="Unicode" />
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ assembly name=&quot;Microsoft.VisualStudio.TextTemplating.12.0, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL&quot; #&gt;" Overwrite="false" Encoding="Unicode" />

        <!-- With HintPath -->
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ assembly name=&quot;%24%28ProjectDir%29%(Reference.HintPath)&quot; #&gt;" Overwrite="false" Encoding="Unicode" Condition="'%(Reference.HintPath)' != '' And $([System.String]::new('%(Reference.HintPath)').Contains('T4Toolbox.dll')) == 'false'" />

        <!-- Without HintPath -->
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ assembly name=&quot;%(Reference.Identity)&quot; #&gt;" Overwrite="false" Encoding="Unicode" Condition="'%(Reference.HintPath)' == ''" />

        <!-- ProjectReference -->
        <WriteLinesToFile File="@(TargetReferenceFile)" Lines="&lt;#@ assembly name=&quot;%24%28ProjectDir%29%(ProjectReference.RelativeDir)bin$(Configuration)\%(ProjectReference.Name).dll&quot; #&gt;" Overwrite="false" Encoding="Unicode" Condition="'%(ProjectReference.Name)' != ''" />

        <!-- Includes -->
        <WriteLinesToFile File="@(IncludesFile)" Lines="&lt;# /* AUTOGENERATED FILE */ #&gt;" Overwrite="true" Encoding="Unicode" />
        <WriteLinesToFile File="@(IncludesFile)" Lines="&lt;#@ include file=&quot;..\Includes\%(Includes.Filename)%(Includes.Extension)&quot; #&gt;" Overwrite="false" Encoding="Unicode" />

        <Message Text="Generating %(TargetReferenceFile.FullPath) &amp;%(IncludesFile.FullPath)" Importance="high" />
    </Target>
</Project>

安装 NuGet 包后,您可以使用 PowerShell 脚本(安装。ps1)运行 构建。

PowerShell 脚本可以使用 Visual Studio API 进行构建。类似于以下内容将构建项目:

param($installPath, $toolsPath, $package, $project)

$config = $dte.Solution.SolutionBuild.ActiveConfiguration.Name
$dte.Solution.SolutionBuild.BuildProject($config, $project.UniqueName, $false)

构建特定的 MSBuild 目标更加棘手。您可以直接调用 MSBuild.exe。这是 PostSharp NuGet package 所做的事情。或者您可以使用 MSBuild API 来构建特定目标。类似于:

Add-Type -AssemblyName 'Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'

# Grab the loaded MSBuild project for the project
$buildProject = [Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.GetLoadedProjects($project.FullName) | Select-Object -First 1

$buildProject.Build("YourTargetName")

请注意,我尚未测试这些 PowerShell 脚本。它们旨在为您提供指向正确实现的指针。