Настройка общей папки пакетов nuget для всех решений, когда некоторые проекты включены в несколько решений

Я использую NuGet для извлечения пакетов из внешних и внутренних источников пакетов, что очень удобно. Но я понял, что пакеты по умолчанию хранятся на одно решение, что очень расстраивает, когда некоторые проекты с ссылками NuGet включены в несколько решений. Затем ссылки заменяются на другую папку пакета решений, которая на самом деле может быть недоступна другой машине разработчика или сборки.

Я видел, что есть способы указать общее местоположение пакета (возможно, на корневом уровне проекта, мы используем контроль источника TFS) с выпуском 2.1 NuGet, см. примечания к выпуску. Я использую NuGet v2.7

Но я попытался добавить файлы nuget.config, не увидев никакого эффекта этого. Пакеты все еще хранятся в папке решения. Я что-то пропустил? Кажется, существуют разные структуры xml node для добавления в файл nuget.config, в зависимости от того, кто отвечает на этот вопрос: Schwarzie предлагает qaru.site/info/54711/...:

<settings>
  <repositoryPath>..\..\[relative or absolute path]</repositoryPath>
</settings>

Примечания к выпуску для NuGet 2.1 (см. ссылку выше) предлагает этот формат:

<configuration>
  <config>
    <add key="repositoryPath" value="..\..\[relative or absolute path]" />
  </config>
</configuration>

Я не знаю, какой из них, или любой, или оба будут работать в конце. Я пробовал оба на уровне решения. Может ли файл nuget.config размещаться на корневом уровне проекта TFS или он должен находиться в каталоге решений? Похоже, что NuGet считывает и применяет настройки из этих файлов в определенном порядке, поэтому имеет смысл добавить их на несколько уровней, где файл nuget.config на уровне решения переопределяет один из уровней корня проекта TFS. Можно ли это уточнить?

Нужно ли мне удалять все установленные пакеты до того, как эти ссылки будут работать? Мне бы очень хотелось, если бы кто-то мог предоставить пошаговую инструкцию для перехода от решения nuget к конкретному решению к общей папке пакета, где проекты, принадлежащие нескольким решениям, могут найти необходимые пакеты nuget.

Ответ 1

У меня похожая ситуация с внешними и внутренними источниками пакетов с проектами, на которые ссылается более чем одно решение. Я просто получил эту работу с одной из наших баз кода сегодня и, похоже, работает с рабочими станциями разработчиков и нашим сервером сборки. Следующий процесс имеет в виду этот сценарий (хотя его не должно быть трудно адаптировать, чтобы иметь общую папку пакетов где-то еще).

  • Codebase
    • Проект A
    • Проект B
    • Проект C
    • Решения
      • Решение 1
      • Решение 2
      • Решение 3
      • Пакеты (общие для всех решений)

Обновлен ответ с NuGet 3.5.0.1484 с обновлением Visual Studio 2015 3

Этот процесс немного проще, чем когда я изначально решил это и подумал, что пришло время обновить его. В общем, процесс такой же, как и при меньших шагах. Результатом является процесс, который решает или обеспечивает следующее:

  • Все, что требуется для управления исходным кодом, видимо и отслеживается в решении
  • Установка новых пакетов или обновление пакетов с помощью диспетчера пакетов в Visual Studio будет использовать правильный путь репозитория
  • После начальной настройки не происходит взлома файлов .csproj.
  • Никаких изменений рабочей станции разработчика (код готов к завершению)

Есть некоторые потенциальные недостатки, о которых нужно знать (я их еще не испытал, YMMV). См. ответ и комментарии Бенола ниже.

Добавить NuGet.Config

Вам нужно создать файл NuGet.Config в корневом каталоге \Solutions \. Убедитесь, что это кодированный файл UTF-8, который вы создаете, если вы не знаете, как это сделать, используйте меню Visual Studio File- > New- > File и затем выберите шаблон XML файла. Добавьте в NuGet.Config следующее:

<?xml version="1.0" encoding="utf-8"?>
<configuration>  
  <config>
    <add key="repositoryPath" value="$\..\Packages" />
  </config>
</configuration>

Для параметра repositoryPath вы можете указать абсолютный путь или относительный путь (рекомендуется) с помощью $token. $Token основан на том, где находится NuGet.Config(токен $фактически равен одному уровню ниже местоположения NuGet.Config). Итак, если у меня есть \Solutions\NuGet.Config, и я хочу \Solutions\Packages, мне нужно будет указать $\..\Packages как значение.

Затем вам нужно добавить папку решений для решения, называемую "NuGet" (щелкните правой кнопкой мыши по вашему решению, Add- > New Solution Folder). Папки решений - это виртуальные папки, которые существуют только в решении Visual Studio и не создают фактическую папку на диске (и вы можете ссылаться на файлы из любого места). Щелкните правой кнопкой мыши папку "NuGet" и затем "Добавить" > "Существующий элемент" и выберите "Решения\NuGet.Config".

Причина, по которой мы это делаем, заключается в том, что она видна в решении и должна помочь с уверенностью, что она правильно привязана к вашему исходному коду. Вы можете сделать этот шаг для каждого решения в вашей кодовой базе, которая участвует в ваших общих проектах.

Поместив файл NuGet.Config в\Solutions\выше любые .sln файлы, мы воспользуемся тем фактом, что NuGet будет рекурсивно перемещать структуру папок вверх из "текущего рабочего каталога", ища файл NuGet.Config использовать. "Текущий рабочий каталог" означает здесь несколько разных вещей, один из них - путь выполнения NuGet.exe, а другой - это файл .sln.

Переключение папки с папками

Во-первых, я настоятельно рекомендую вам пройти через каждую из ваших папок решений и удалить все существующие\Packages\папки (сначала вам нужно закрыть Visual Studio). Это упрощает просмотр, где NuGet помещает вашу новую конфигурацию\Packages\в папку и гарантирует, что какие-либо ссылки на неправильную папку\Packages\не удастся и могут быть исправлены.

Откройте свое решение в Visual Studio и откройте Rebuild All. Игнорируйте все ошибки сборки, которые вы получите, это ожидается на этом этапе. Однако это должно начать функцию восстановления пакета NuGet в начале процесса сборки. Убедитесь, что папка\Solutions\Packages\создана в нужном месте. Если этого не произошло, просмотрите конфигурацию.

Теперь для каждого проекта в вашем решении вы захотите:

  • Щелкните правой кнопкой мыши проект и выберите "Выгрузить проект"
  • Щелкните правой кнопкой мыши проект и выберите "Изменить свой-xxx.csproj"
  • Найдите ссылки на\packages\и обновите их до нового местоположения.
    • Большинство из них будут <HintPath> ссылки, но не все из них. Например, WebGrease и Microsoft.Bcl.Build будут иметь отдельные параметры пути, которые необходимо будет обновить.
  • Сохраните .csproj, а затем щелкните правой кнопкой мыши проект и выберите "Обновить проект"

После того, как все ваши файлы .csproj были обновлены, откройте еще один файл Rebuild All, и у вас не должно быть больше ошибок сборки в отношении недостающих ссылок. На этом вы закончили, и теперь NuGet настроен на использование общей папки Packages.

Начиная с NuGet 2.7.1 (2.7.40906.75) с VStudio 2012

Прежде всего, нужно помнить, что nuget.config не контролирует все параметры пути в системе пакетов nuget. Это было особенно сложно понять. В частности, проблема в том, что msbuild и Visual Studio (вызов msbuild) не используют путь в nuget.config, а скорее переопределяют его в файле nuget.targets.

Подготовка среды

Сначала я перейду через вашу папку решений и удалю все существующие\packages\папки. Это поможет убедиться, что все пакеты явно установлены в правильной папке и помогут обнаружить любые неверные ссылки на пути в ваших решениях. Затем, я бы удостоверился, что у вас установлена ​​последняя версия расширения Visual Studio. Я также хотел бы убедиться, что в каждом решении установлен последний файл nuget.exe. Откройте командную строку и перейдите в каждую папку $(SolutionDir) \.nuget\и выполните следующую команду:

nuget update -self

Настройка общего пути папки пакета для NuGet

Откройте каждый файл $(SolutionDir) \.nuget\NuGet.Config и добавьте следующее внутри <configuration> раздел:

<config>
    <add key="repositorypath" value="$\..\..\..\Packages" />
</config>

Примечание. Вы можете использовать абсолютный путь или относительный путь. Имейте в виду, если вы используете относительный путь с $, который находится относительно одного уровня ниже местоположения NuGet.Config(полагайте, что это ошибка).

Настройка общего пути папки пакета для MSBuild и Visual Studio

Откройте каждый файл $(SolutionDir) \.nuget\NuGet.targets и измените следующий раздел (обратите внимание, что для не-Windows есть другой раздел ниже):

<PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
    <!-- Windows specific commands -->
    <NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
    <PackagesConfig>$([System.IO.Path]::Combine($(ProjectDir), "packages.config"))</PackagesConfig>
    <PackagesDir>$([System.IO.Path]::Combine($(SolutionDir), "packages"))</PackagesDir>
</PropertyGroup>

Обновить пакетыDir для

<PackagesDir>$([System.IO.Path]::GetFullPath("$(SolutionDir)\..\Packages"))</PackagesDir>

Примечание.. GetFullPath разрешит наш относительный путь в абсолютный путь.

Восстановление всех пакетов nuget в общей папке

Откройте командную строку и перейдите к каждому $(SolutionDir) \.nuget и выполните следующую команду:

nuget restore ..\YourSolution.sln

В этот момент у вас должна быть одна папка\packages\в вашем общем месте и ни одна из ваших папок решений. Если нет, проверьте свои пути.

Фиксация проектных ссылок

Откройте каждый файл .csproj в текстовом редакторе и найдите ссылки на \packages и обновите их до правильного пути. Большинство из них будет <HintPath> ссылки, но не все из них. Например, WebGrease и Microsoft.Bcl.Build будут иметь отдельные параметры пути, которые необходимо будет обновить.

Создайте свое решение

Откройте свое решение в Visual Studio и начните сборку. Если он жалуется на недостающие пакеты, которые необходимо восстановить, не предполагайте, что пакет отсутствует и его необходимо восстановить (ошибка может вводить в заблуждение). Это может быть плохой путь в одном из ваших файлов .csproj. Перед первым восстановлением пакета убедитесь в этом.

Есть ли ошибка сборки отсутствующих пакетов?

Если вы уже подтвердили правильность путей в ваших файлах .csproj, у вас есть два варианта попробовать. Если это результат обновления кода из исходного кода, вы можете попробовать проверить чистую копию и затем создать ее. Это работало для одного из наших разработчиков, и я думаю, что в файле .suo был артефакт или что-то подобное. Другим вариантом является принудительное восстановление пакета с помощью командной строки в папке .nuget соответствующего решения:

nuget restore ..\YourSolution.sln

Ответ 2

Вместо того, чтобы устанавливать общее расположение пакетов для всех проектов, также можно изменить HintPath в проекте следующим образом:

<HintPath>$(SolutionDir)\packages\EntityFramework.6.1.0\lib\net40\EntityFramework.dll</HintPath>

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

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

Ответ 3

Мой опыт, пробующий это с последней версией NuGet (2.7) и VS2012:

  • Удалите папку .nuget(на диске и в решении)
  • Поместите файл NuGet.Config в общую родительскую папку всех решений.
  • Удалить все существующие папки пакетов
  • Пройдите через все файлы csproj и измените HintPaths, чтобы указать на новое местоположение.
  • Profit

В моем случае я хотел поместить все пакеты в .packages, поэтому мой NuGet.Config выглядел ниже.

 <?xml version="1.0" encoding="utf-8"?>
 <configuration>
   <config>
     <add key="repositorypath" value=".packages" />
   </config>
 </configuration>

Обратите внимание, что есть несколько "странных" вещей, которые могут произойти, но я думаю, что они терпимы:

  • Если вы обновляете пакет из одного решения, он быстро удалит более старую версию из папки ваших пакетов (она не может знать, есть ли у вас другое решение, указывающее там). Это меня не сильно беспокоит, так как другое решение будет просто восстанавливаться, когда потребуется.
  • Если вы попытаетесь добавить пакет из контекстного клика на решение, если пакет уже присутствует в другом решении, он увидит его там и покажет вам "зеленый тик" вместо кнопки "установить". Обычно я устанавливаю из щелчка правой кнопкой мыши на проекте, так что это меня совсем не беспокоит.

Отказ от ответственности. Я просто пробовал это сегодня, у меня нет многолетнего опыта для его поддержки!

Ответ 4

У меня есть версия NuGet 2.8.50926 с VS 2013. Вам не нужно использовать несколько файлов nuget.config или использовать сложные структуры каталогов. Просто измените файл по умолчанию, расположенный здесь:

%APPDATA%\Roaming\NuGet\NuGet.Config

Вот содержание моего файла:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <add key="repositoryPath" value="C:\Projects\nugetpackages" />
  </config>
  <activePackageSource>
    <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
  </activePackageSource>
</configuration>

Таким образом, все пакеты переходят в папку "C:\Projects\nugetpackages", независимо от того, где это решение.

Во всех ваших решениях просто удалите существующие папки "пакеты". Затем создайте свое решение, и NuGet автоматически восстановит недостающие пакеты в новом, централизованном каталоге, который вы указали.

Ответ 5

Уже нет необходимости изменять nuget.targets. Он исправлен в nuget 2.8 (http://nuget.codeplex.com/workitem/2921). Вам нужно только установить путь к репозиторию.

Ответ 6

Обновление моего опыта с помощью nuget 2.8.3. Это было относительно просто. Все это было с помощью включенного восстановления пакета. Отредактированный NuGet.Config и добавил следующие строки:

  <config>
    <add key="repositorypath" value="..\Core\Packages" />
  </config>

Затем перестроил решение, он автоматически загрузил все пакеты в нужную папку и обновил ссылки. Я сделал то же самое для всех других моих проектов, где были загружены только инкрементные пакеты, и были добавлены существующие пакеты. Следовательно, общий пакетный репозиторий для всех проектов, которые были установлены.

Ниже приведена пошаговая процедура для восстановления пакета.

http://blogs.4ward.it/enable-nuget-package-restore-in-visual-studio-and-tfs-2012-rc-to-building-windows-8-metro-apps/

Ответ 7

Из версии Visual Studio 2013 Update 4 и версии Nugget Package Manager версии 2.8.5...

Создайте файл nuget.config в корневом каталоге репозитория.

содержимое файла:

<configuration>
  <config>
    <add key="repositoryPath" value="packages" />
  </config>
  <packageSources>
    <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
  </packageSources>
</configuration>

Это приведет к тому, что все пакеты перейдут в папку пакетов на уровне вашего файла nuget.config.

Теперь вы можете пойти для каждой консоли .sln nuget с командой "update-package -reinstall"

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

 <add key="repositoryPath" value="..\packages" />

Но таким образом вы вызываете, что ссылка на пакеты nuget csproj указывает одну папку вне вашего пути репозиториев.

Ответ 8

Для любого значительного решения вышеупомянутые ответы не оправдаются. Весьма просто, сложная структура рабочего пространства TFS с различными относительными путями, ветвями, совместными проектами и т.д. Делает невозможным единый центральный репозиторий.

Использование ($ SolutionDir) - это шаг в правильном направлении, но ручное кодирование файла csproj с ($ SolutionDir) станет довольно утомительным в базе кода с сотнями пакетов, которые обновляются регулярно (происходит каждое обновление, HintPath перезаписывается новым относительным путем). Что произойдет, если вам нужно запустить Update-Package -Reinstall.

Существует большое решение под названием NugetReferenceHintPathRewrite. Он автоматизирует инъекцию ($ SolutionDir) в HintPaths непосредственно перед сборкой (без фактического изменения файла csproj). Я предполагаю, что его можно легко включить в автоматизированные системы сборки.

Ответ 9

Я придумал пакет NuGet, который прозрачно преобразует все ссылки NuGet в проект в формат $(SolutionDir). Он делает это с использованием преобразования XSLT времени сборки, поэтому вам не нужно вручную взламывать файл проекта. Вы можете свободно обновлять свои пакеты, он ничего не сломает.

https://www.nuget.org/packages/NugetRelativeRefs

Или, если вы используете обновление Visual Studio 2015 Update 3, вы можете просто перенести ссылки на пакет в форму project.json, как описано здесь: https://oren.codes/2016/02/08/project-json-all-the-things

Ответ 10

Краткий обзор для VS 2013 профессионала с NuGet Версия: 2.8.60318.667

Так вы должны направить пакеты на путь относительно папки .nuget:

<configuration>
  <config>
    <add key="repositoryPath" value="../Dependencies" />
  </config>
</configuration>

Например, если ваше решение (файл .sln) находится в C:\Projects\MySolution, когда вы включаете восстановление пакета NuGet, папка .nuget создается так: C:\Projects\MySolution.nuget и пакеты будут загружены в каталог следующим образом: C:\Projects\MySolution\Dependencies

ПРИМЕЧАНИЕ.. По какой-то (неизвестной) причине каждый раз, когда я обновляю "репозиторий", мне нужно закрыть и снова открыть решение о том, чтобы изменения вступили в силу.

Ответ 11

Просто перетащите ссылку/пакеты в нужную общую папку. Тогда ваш проект не будет нарушен для других пользователей, у которых нет специального расположения пакетов.

Откройте командную строку как администратор и используйте

mklink /prefix link_path Target_file/folder_path

Ответ 12

Это инструкции по NuGet 2.1: http://docs.nuget.org/docs/release-notes/nuget-2.1

Не нужно редактировать файлы уровня решения.

Работает с Visual Studio 2013 и тремя решениями, совместно использующими проекты.

Не забудьте обновить уровень решения NuGet (каждый nuget.exe в папках .nuget).