Установите файлы содержимого для "копирования локального: всегда" в пакете nuget

Я генерирую пакет nuget из проекта с этой командой в событии post-build. переменная %conf% установлена ​​в правильную конфигурацию (отладка или выпуск), а %1 - это имя проекта (например, "MyCompany.MyProject" ).

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

Этот пакет предназначен только для нашего собственного использования, он никогда не будет опубликован в nuget. Он заканчивается в нашем частном репозитории.

В проекте есть файл, который установлен на generate action : content и copy local : always. (Моя визуальная студия на французском языке, так что я не уверен на 100% в результате трюка). Назовите его importantfile.xml.

В сгенерированном пакете я получаю следующую структуру:

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

Что хорошо, я хочу, чтобы importantfile.xml был развернут в пакете, потому что, ну, этот файл важен!

Когда я устанавливаю пакет в другой проект, importantfile.xml развертывается в корне проекта. Это нормально. Но он не установлен в copy local : always.

Мне нужно importantfile.xml быть copy local : always в этом проекте, где я устанавливаю свой пакет.

Как я могу это достичь?

Примечания:

Я могу установить copy local : always в файл сразу после установки пакета, что не имеет большого значения. Я бы жил с ним, если последующие обновления пакета позволят это свойство как есть, чего не происходит. При обновлении пакета copy local сбрасывается на never (как указано здесь).

В папке проекта есть файл 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>

Ответ 1

Вы можете использовать PowerShell и hook Install.ps1, предоставляемые NuGet.

См. документацию .

Через PowerShell вам нужно "искать" элемент контента, который включает ваш importantfile.xml в атрибуте. Когда script нашел его, он должен добавить <CopyToOutputDirectory>Always</CopyToOutputDirectory> в качестве дочернего элемента.

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

Ниже вы можете найти фрагменты PowerShell здесь. Просто взгляните на файлы .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). Если я нажму на перезагрузку до того, как команда будет полностью завершена, она иногда вызывает ошибки. Хитрость заключается в том, чтобы оставить диалог там до тех пор, пока процесс не завершится, а затем перезагрузите проекты.

Ответ 2

Вместо использования PowerShell script другой подход заключается в использовании целей или реквизитов MSBuild с тем же именем, что и идентификатор пакета:

<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 также каждый со своим собственным файлом целей.

Преимущества использования файла целей над PowerShell script с каталогом NuGet Content:

  • требуемые файлы содержимого не отображаются в проекте в Visual Studio
  • файлы содержимого связаны, а не копируются в каталог каждого проекта, который ссылается на пакет NuGet (предотвращая наличие нескольких копий и сохраняя поведение так же, как для сборок/библиотек из пакетов NuGet).
  • Сценарии PowerShell работают только в Visual Studio и не запускаются, когда NuGet запускается из командной строки (серверы сборки, другие IDE и другие ОС), этот подход будет работа везде
  • Скрипты установки PowerShell не поддерживаются в системе NuGet 3.x project.json.

Ответ 3

поэтому я знаю, что у вас, ребята, есть рабочее решение, но это не сработало для меня, поэтому я собираюсь поделиться тем, что я вытащил из NLog.config пакет NuGet install.ps1

ПРИМЕЧАНИЕ: это не мой код, это содержимое install.ps1 из пакет NLog.config nuget просто делится знаниями.

кажется немного более прямым для меня и просто надеется помочь другим, которые, скорее всего, наткнутся на это.

вы можете найти принятые значения int для BuildAction здесь и принятые значения для CopyToOutputDirectory здесь.

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

Ответ 4

Я сделал это, который копирует файлы из моей папки сборки в выходную папку (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>

Ответ 5

Я написал небольшой инструмент под названием NuGetLib для автоматического добавления файлов в пакет nuget после сборки.

  • создайте папку tools со своим Install.ps1 script
  • создайте nugetPackage
  • добавьте папку инструментов в построенный nugetPackage

fooobar.com/info/76532/...