【问题标题】:Setting file properties with NuGet using .targets file使用 .targets 文件使用 NuGet 设置文件属性
【发布时间】:2018-09-22 03:48:29
【问题描述】:

我正在构建一个要作为 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 - 你的意思是文件 FrameworkTests.feature 没有添加到你的项目中,你在解决方案资源管理器中看不到它吗?
  • 是的。如果我使用target="content\Framework\FrameworkTests.feature",我只能看到它被添加到解决方案资源管理器中

标签: visual-studio-2015 nuget nuget-package-restore nuget-spec


【解决方案1】:

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

这是 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 将不起作用。因为当你把文件夹改成内容的时候,在.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

更新:

我也应用了您描述的更改,但仍然无法更新 CopyToOutputDirectory 文件属性。

找到了。有两点需要更新,还有一点需要知道。

第一点:

我在您的.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 会在您构建项目时应用此更改。那是因为&lt;Import Project="....\MyProject.targets" Condition="Exists('...')" /&gt;会在你编译项目的时候被解析。

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

更新2:

很多 cmets 流传说 PowerShell 脚本无法运行 构建服务器,因为 install 命令不运行它们;仅有的 VisualStudio 将

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

尝试在 PowerShell 中输入:

set-executionpolicy remotesigned

在 Visual Studio 2015 中,您需要安装扩展 PowerShell Tools for Visual Studio 2015Windows 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

希望这会有所帮助。

【讨论】:

  • 我已经尝试添加一个content 文件夹并将文件放入其中,但是在安装nuget 包时它们没有被复制到目标项目中。我通过提供 .csproj 的名称来打包 - 这是否意味着不同?我也应用了您描述的更改,但仍然无法更新 CopyToOutputDirectory 文件属性。
  • @MattW,应该有我没解释清楚的地方,我稍后会更新我的答案,让你知道。
  • @MattW,在使用您的.nuspec.targets 文件创建样本后,我找到了它不适合您的原因,有两点您需要更新,还有一点应该知道.请查看我的更新答案以获取详细信息。我已经对其进行了测试,它在我这边工作正常,如果它仍然不适合你,请告诉我。
  • @MattW,由于您受到 SpecFlow/xUnit 的限制,您可以使用我在答案中提到的另一种方式。使用Install.ps1文件,在这种情况下,当您完成安装nuget包时,nuget会更改属性。stackoverflow.com/questions/8474253/…
  • @MattW,不确定 PowerShell 脚本无法在构建服务器上运行的所有原因,但绝大多数是因为 PowerShell 的默认安全级别。您可以查看我的 update2 答案以了解详细信息,当我在 VS2015 中安装该 nuget 包时,它工作正常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-02
  • 2011-03-21
  • 1970-01-01
  • 1970-01-01
  • 2018-07-20
  • 2018-07-19
相关资源
最近更新 更多