使用 .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.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>
注意:不要忘记删除 .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
:
希望这对您有所帮助。
我正在构建一个要作为 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.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>
注意:不要忘记删除 .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
:
希望这对您有所帮助。