使用 .targets 文件通过 NuGet 设置文件属性

Setting file properties with NuGet using .targets file

我正在构建一个要作为 NuGet 包安装的项目,我想设置 SpecFlow 功能文件的属性(因为它是最新的 SpecFlow,不应为这些功能生成代码隐藏文件。)

为了达到选择文件、打开它的属性窗格并设置几个值的效果,我将我的项目结构设置如下:

\MyProject
  \build
    MyProject.targets
    \Framework <the folder containing the file I want to affect>
      FrameworkTests.feature <the file I want to affect>
  \Framework
    FrameworkTests.feature <the original location of the file I want to affect>

我的 .nuspec 是这样的:

<?xml version="1.0"?>
<package >
  <metadata minClientVersion="2.5">
    <id>$id$</id>
    <version>$version$</version>
    ...
  </metadata>
  <files>
    <file src="build\MyProject.targets" target="build\MyProject.targets" />
    <file src="build\FrameworkTests\FrameworkTests.feature" target="build\Framework\FrameworkTests.feature" />
  </files>
</package>

我的 .targets 文件是这样的:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <None Include="$(MSBuildThisFileDirectory)FrameworkTests\FrameworkTests.feature">
      <Link>FrameworkTests.feature</Link>
      <CopyToOutputDirectory>Copy if newer</CopyToOutputDirectory>
      <CustomToolNamespace></CustomToolNamespace>
    </None>
  </ItemGroup>
</Project>

安装包时,我没有看到 FrameworkTests.feature 文件被复制到项目中。我需要更改什么?

I am not seeing the FrameworkTests.feature file get copied to the project when the package is installed. What do I need to change?

这是 nuget 文件夹约定的默认行为。如果您在 content 文件夹中设置文件,nuget 会将这些内容复制到项目根目录,然后您将在解决方案资源管理器中看到它们。如果您在 build 文件夹中设置文件,nuget 将自动将它们插入到项目文件或 project.lock.json 中,如项目文件中的以下脚本:

<Import Project="..\packages\MyProject.1.0.0\build\MyProject.targets" Condition="Exists('..\packages\MyProject.1.0.0\build\MyProject.targets')" />

所以,这就是您在解决方案资源管理器中看不到文件 FrameworkTests.feature 的原因,除非您将文件夹更改为 content

详情可参考文档Creating the .nuspec file

此外,如果将文件夹更改为内容,.targets将不起作用。因为当你把文件夹改成content的时候,在.targets文件中,需要把路径从:

改成
<None Include="$(MSBuildThisFileDirectory)FrameworkTests\FrameworkTests.feature">

收件人:

<None Include="$(MSBuildThisFileDirectory)..\content\FrameworkTests\FrameworkTests.feature">

但 MSBuild 无法解析路径 ..\content。要解决此问题,我们需要将 .targets 文件更改为:

<None Include="$(ProjectDir)FrameworkTests.feature">

或者,您可以将 属性 个文件更改为 Install.ps1 个文件,并将其设置到 nuget 包中。

有关详细信息,请参阅 this thread

更新:

I have also applied the changes you've described, but still cannot get the CopyToOutputDirectory file property to be updated.

找到了。有两点你需要更新,有一点你应该知道。

第一点:

我在您的 .nuspec 中找到以下脚本:

  <files>
    <file src="build\MyProject.targets" target="build\MyProject.targets" />
    <file src="build\FrameworkTests\FrameworkTests.feature" target="build\Framework\FrameworkTests.feature" />
  </files>

注意: 您为 build\Framework 设置了目标文件夹,但在您的 .targets 文件中,您将其包含在 FrameworkTests;

<None Include="$(MSBuildThisFileDirectory)FrameworkTests\FrameworkTests.feature">

因此,将其更改为内容文件夹时,您的 .nuspec 文件应为:

  <files>
    <file src="build\MyProject.targets" target="build\MyProject.targets" />
    <file src="content\FrameworkTests\FrameworkTests.feature" target="content\FrameworkTests\FrameworkTests.feature" />
  </files>

.targets 文件应该是:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <None Include="$(ProjectDir)FrameworkTests\FrameworkTests.feature">
      <Link>FrameworkTests.feature</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CustomToolNamespace></CustomToolNamespace>
    </None>
  </ItemGroup>
</Project>

第二点需要更新:

.targets 文件中 CopyToOutputDirectory 的值应该是 PreserveNewest 如果较新则不复制。

你需要知道的要点:

当您使用此方法更改 FrameworkTests.feature 的 属性 时,此文件的 属性 在解决方案资源管理器中不会更改,但是,MSBuild 将应用此更改当你构建项目时。那是因为 <Import Project="....\MyProject.targets" Condition="Exists('...')" /> 会在你编译项目的时候被解析。

因此,您可以在构建项目后检查 CopyToOutputDirectory 文件 属性 的输出(构建项目后,文件 FrameworkTests.feature 将被复制到输出文件夹。)

更新2:

A lot of comments circulating that PowerShell scripts can't be run on build servers because the install command doesn't run them; Only VisualStudio will

不确定 PowerShell 脚本不能在构建服务器上 运行 的所有原因,但绝大多数是因为 PowerShell 的默认安全级别。

尝试在 PowerShell 中输入:

set-executionpolicy remotesigned

在Visual Studio2015中,您需要安装扩展程序PowerShell Tools for Visual Studio 2015 and the Windows Management Framework 4.0。安装后,install.ps1 就可以正常工作了。以下是我的 .nuspec 文件和 install.ps1 个脚本。

.nuspec 文件:

  <files>
    <file src="content\FrameworkTests\FrameworkTests.feature" target="content\FrameworkTests\FrameworkTests.feature" />
    <file src="scripts\Install.ps1" target="tools\Install.ps1" />
  </files>

注意:不要忘记删除 .nuspec 文件中的 MyProject.targets

install.ps`1 个脚本:

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

function MarkDirectoryAsCopyToOutputRecursive($item)
{
    $item.ProjectItems | ForEach-Object { MarkFileASCopyToOutputDirectory($_) }
}

function MarkFileASCopyToOutputDirectory($item)
{
    Try
    {
        Write-Host Try set $item.Name
        $item.Properties.Item("CopyToOutputDirectory").Value = 2
    }
    Catch
    {
        Write-Host RecurseOn $item.Name
        MarkDirectoryAsCopyToOutputRecursive($item)
    }
}

#Now mark everything in the a directory as "Copy to newer"
MarkDirectoryAsCopyToOutputRecursive($project.ProjectItems.Item("FrameworkTests"))

然后,安装nuget包后,文件FrameworkTests.feature的属性会变成copy if newer:

希望这对您有所帮助。