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

时间:2018-04-12 05:54:43

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

我正在构建一个要作为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文件被复制到项目中。我需要改变什么?

1 个答案:

答案 0 :(得分:7)

  

安装软件包时,我没有看到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了解更多详情:

NuGet folder conventions

外,如果您将文件夹更改为内容,.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>

第二点需要更新:

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

您需要了解

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

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

<强> UPDATE2:

  

很多评论都说不能运行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.ps 1脚本。

.nuspec文件:

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

注意:请勿忘记删除MyProject.targets文件中的.nuspec

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

enter image description here

希望这有帮助。