在nuget包中将内容文件设置为“copy local:always”

时间:2014-01-15 17:08:42

标签: visual-studio visual-studio-2012 nuget nuget-package copy-local

我在post-build事件中使用此命令从项目生成nuget包。变量%conf%设置为正确的配置(调试或发布),%1是项目名称(例如“MyCompany.MyProject”)。

nuget pack -Prop Configuration=%conf% "%1.csproj" -exclude *.sql -IncludeReferencedProjects

此软件包仅供我们自己使用,永远不会在nuget上发布。它以我们的私人存储库结束。

在项目中,有一个文件设置为generate action : contentcopy local : always。 (我的视觉工作室是法语,所以我不是百分之百地确定了它的变形)。我们将其命名为importantfile.xml

在生成的包中,我最终得到了这个结构:

- content
    - importantfile.xml
- lib
    -net45 (.NetFramework,Version=v4.5)
        -MyCompany.MyProject.dll

哪个好,我希望importantfile.xml部署在包中,因为这个文件很重要!

当我在另一个项目中安装软件包时,importantfile.xml部署在项目的根目录下。没关系。但它未设置为copy local : always

在我安装软件包的项目中,我需要importantfile.xmlcopy local : always

我该如何实现?

注意:

可以在安装软件包之后在文件上设置copy local : always,这没什么大不了的。如果以后更新软件包会让这个属性按原样,我会忍受它,但事实并非如此。更新包时,copy local将重置为never(如here所述)。

项目文件夹中有一个nuspec文件,这里是:

<?xml version="1.0"?>
<package >
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <title>$title$</title>
    <authors>$author$</authors>
    <owners>$author$</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
    <copyright>Copyright 2014</copyright>
    <tags>some random tags</tags>
  </metadata>
</package>

5 个答案:

答案 0 :(得分:133)

不使用PowerShell脚本,而是使用与包ID同名的MSBuild targets or props file

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <None Include="$(MSBuildThisFileDirectory)importantfile.xml">
      <Link>importantfile.xml</Link>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

然后,在nuspec文件中,不是将所需文件添加到Content目录,而是将它们与目标文件一起添加到Build目录。

  • 生成
    • importantfile.xml
    • MyPackage.targets
  • LIB
    • net45
      • MyAssembly.dll程序

如果您需要针对不同体系结构的不同内容,则可以在Build下添加体系结构文件夹,每个体系结构文件夹都有自己的目标文件。

使用NuGet Content目录在PowerShell脚本上使用目标文件的好处:

  • 所需内容文件未在Visual Studio
  • 项目中显示
  • 内容文件链接到而不是复制到引用NuGet包的每个项目的目录中(防止存在多个副本并保持行为与NuGet包中的程序集/库相同)
  • PowerShell脚本仅适用于Visual Studio和aren't run when NuGet is run from the commandline(构建服务器,其他IDE和其他操作系统),此方法可在任何地方使用
  • PowerShell安装脚本为not supported in NuGet 3.x project.json system

答案 1 :(得分:38)

我知道你们有一个可行的解决方案,但这对我不起作用所以我要分享我从NLog.config NuGet package install.ps1(github source here中取出的内容)。

  

注意:这不是我的代码,这是install.ps1的内容   NLog.config nuget包只是分享知识。

对我来说似乎更直接一点,只是希望能帮助那些可能偶然发现这一点的人。

您可以找到BuildAction here的已接受int值以及CopyToOutputDirectory here的可接受值。

如果链接再次中断 enter image description here

字段 prjBuildActionCompile 1
该文件已编译。

prjBuildActionContent 2
该文件包含在Content项目输出组中(请参阅部署应用程序,服务和组件)

prjBuildActionEmbeddedResource 3
该文件包含在主生成的程序集中或作为资源包含在附属程序集中。

prjBuildActionNone 0
不采取任何行动。

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

$configItem = $project.ProjectItems.Item("NLog.config")

# set 'Copy To Output Directory' to 'Copy if newer'
$copyToOutput = $configItem.Properties.Item("CopyToOutputDirectory")

# Copy Always Always copyToOutput.Value = 1
# Copy if Newer copyToOutput.Value = 2  
$copyToOutput.Value = 2

# set 'Build Action' to 'Content'
$buildAction = $configItem.Properties.Item("BuildAction")
$buildAction.Value = 2

答案 2 :(得分:5)

我做了这个,它将我的构建文件夹中的文件复制到输出文件夹(bin / debug或bin / release)。对我来说就像是一种魅力。

Nuspec文件:

<package>
  <files>
    <file src="\bin\Release\*.dll" target="lib" />
    <file src="\bin\Release\x64\*.dll" target="build\x64" />
    <file src="\bin\Release\x86\*.dll" target="build\x86" />
    <file src="MyProject.targets" target="build\" />    
  </files>
</package>

MyProject.targets

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <NativeLibs Include="$(MSBuildThisFileDirectory)**\*.dll" />
    <None Include="@(NativeLibs)">
      <Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

答案 3 :(得分:2)

您可以使用PowerShell和NuGet提供的Install.ps1挂钩。

请参阅documentation

通过PowerShell,您必须“搜索”包含属性中importantfile.xml的内容元素。当脚本找到它时,它必须添加<CopyToOutputDirectory>Always</CopyToOutputDirectory>作为子元素。

    <Content Include="importantfile.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>

您可以找到一些PowerShell代码段here。只需查看.ps1个文件。

您可以尝试以下方法(未经测试)。该文件必须命名为Install.ps1并复制到tools文件夹中:

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

# Load project XML.
$doc = New-Object System.Xml.XmlDocument
$doc.Load($project.FullName)
$namespace = 'http://schemas.microsoft.com/developer/msbuild/2003'

# Find the node containing the file. The tag "Content" may be replace by "None" depending of the case, check your .csproj file.
$xmlNode = Select-Xml "//msb:Project/msb:ItemGroup/msb:Content[@Include='importantfile.xml']" $doc -Namespace @{msb = $namespace}


#check if the node exists.
if($xmlNode -ne $null)
{
    $nodeName = "CopyToOutputDirectory"

    #Check if the property already exists, just in case.
    $property = $xmlNode.Node.SelectSingleNode($nodeName)
    if($property -eq $null)
    {
        $property = $doc.CreateElement($nodeName, $namespace)
        $property.AppendChild($doc.CreateTextNode("Always"))
        $xmlNode.Node.AppendChild($property)

        # Save changes.
        $doc.Save($project.FullName)
    }
}

卸载软件包时,还应检查是否所有内容都已完全删除。

Jonhhy5的注释

通过update-package更新软件包时,Visual Studio会警告项目已在“环境之外”进行修改。这是由$doc.Save($project.FullName)引起的。如果在命令完全终止之前单击“重新加载”,则有时会导致错误。诀窍是将对话框留在那里直到进程完成,然后 重新加载项目。

答案 4 :(得分:0)

我编写了一个名为NuGetLib的小工具,用于在构建后自动将文件添加到nuget包中。

  1. 使用您的tools脚本
  2. 创建一个Install.ps1文件夹
  3. 构建您的nugetPackage
  4. 将tools文件夹添加到构建的nugetPackage
  5. https://stackoverflow.com/a/47134733/6229375