Пакет Восстановления NuGet настаивает на определенных версиях пакета
У меня есть проект со следующими пакетами.config:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Framework.Infrastructure.Core" version="1.4.0.6" />
<package id="Framework.Infrastructure.Extensions" version="1.4.0.6" />
</packages>
Где находятся пакеты Framework.* В нашем локальном репозитории.
Я включил Восстановление пакетов и добавил наше внутреннее репо к источникам. Тем не менее, когда я пытаюсь восстановить пакеты из packages.config (который по существу делает nuget install packages.config -sources....
), Я получаю следующие ошибки:
error : Unable to find version '1.4.0.6' of package 'Framework.Infrastructure.Extensions'
error : Unable to find version '1.4.0.6' of package 'Framework.Infrastructure.Core'.
Хранилище больше не содержит версию пакета 1.4.0.6 (которая была актуальна пару месяцев назад), а скорее его новую версию (например, 1.5.1.6).
Почему NuGet не находит новые версии пакетов? Есть ли какой-то синтаксис, который я могу указать в packages.config, чтобы гарантировать загрузку последних версий?
Короче говоря, есть ли что-то кроме написания собственного скрипта для обновления пакетов, которые я могу сделать?
Спасибо.
4 ответа
Я думаю, что некоторые люди неправильно понимают, для чего предназначено восстановление пакетов. Эта функция была добавлена в NuGet исключительно для того, чтобы не требовать проверки пакетов в системе контроля версий. Многие люди жаловались на то, что исполняемые двоичные файлы увеличивали размер своих репозиториев, и это еще хуже при использовании DVCS, такого как git, где все репозитории загружаются локально и включают каждую версию пакета Foo.
Так что же делает Package Restore? По сути, он просматривается в packages.config каждого проекта и просто выводит конкретную версию указанного пакета. Это как удалить папку с вашими пакетами, а затем делать git reset --hard
вернуть их (при условии, что папка была проверена).
Почему это важно? Почему бы не обновить до последней версии пакета? Если вы рассматриваете наиболее распространенный вариант использования Package Restore, который заключается в создании автоматических сборок, это должно дать вам подсказку. Сервер сборки должен создавать только проект, который был протестирован и передан разработчиком. Если вы позволите серверу сборки решать, когда обновлять пакет, то у вас есть проект, который никто не проверял. Как разработчик, вы должны решить, когда выполнять обновление.
Помните, что установка или обновление пакета - это не просто извлечение файла.nupkg и добавление ссылок. У многих пакетов есть побочные эффекты, такие как обновление файлов.config, добавление кода и т. Д. При установке пакета все эти побочные эффекты возникают в вашей локальной копии. Теперь вы можете зафиксировать свой код и исключить файлы пакета.
Когда другой разработчик или сервер сборки проверит код, он получит тот же код побочных эффектов, что и у вас, за исключением файлов пакета. Восстановление пакетов просто извлекает эти файлы из репозитория NuGet, и теперь у нас есть все необходимое для работы над этим проектом.
Команда NuGet пообещала сохранить все версии пакетов, чтобы вы всегда могли найти нужную версию. Однако, как мы видели несколько месяцев назад, когда сервер NuGet вышел из строя, он в значительной степени нанёс ущерб Восстановлению пакетов, и многие люди не смогли его собрать.
Я рекомендую вам установить свой собственный репозиторий NuGet (подойдет простой общий файловый ресурс) и хранить копии всех пакетов, которые вы там используете. Таким образом, вы не зависите от внешнего сервера для ваших сборок. И, как это делает команда NuGet, вы должны хранить ВСЕ версии пакета. Таким образом, если вам придется вернуться и построить более старую версию вашего проекта, вы будете уверены, что у вас будут правильные версии пакетов.
Я надеюсь, что это объясняет, как работает эта функция и почему она работает таким образом.
Я предлагаю вам прочитать документацию NuGet для управления версиями. Это объясняет, как номера версий (и диапазоны) могут быть использованы в packages.config
файлы для учета Update-Package
Команда, чтобы узнать, какие приемлемые версии для обновления.
Тем не менее, функция восстановления пакетов не будет обновлять пакеты для вас автоматически.
С этой информацией лучший рабочий процесс IMO:
- Установите самую новую стабильную версию любой новой зависимости, которую вы добавляете, если только вам действительно не нужна более старая (или предварительная) версия
- Используйте восстановление пакетов в ваших сборках CI, что позволяет вам не регистрировать пакеты NuGet в вашей VCS
- Только
Update-Package
если...- Вам нужен новый вызов API или исправление ошибки из последней версии
- У вас есть отличный набор тестов на уверенность
- У вас есть время, чтобы справиться с потенциальными последствиями
Я не рекомендую регулярно обновлять пакеты только потому, что. Лучше оставить проект работающим как есть со старыми зависимостями, если они работают достаточно хорошо, потому что существует риск при обновлении версии любых пакетов.
Предполагается, что пакеты NuGet следуют семантическому версионированию, в котором есть хорошие правила, позволяющие обеспечить максимально легкое обновление пакетов, но поскольку это не является обязательным (поверьте мне, многие издатели пакетов не следуют SemVer), вы не можете полагаться на Это. Даже если пакет обновляется с незначительным увеличением версии, вы не можете быть уверены (без достаточного тестирования), что новая версия будет работать с вашим кодом.
Таким образом, автоматическое обновление любых пакетов обычно является плохой идеей. Лучше позволить разработчикам явно выбрать вариант обновления любых пакетов, и только по достаточно веской причине.
На случай, если кто-то столкнется с этим, я написал модуль PowerShell и обернул его в пакет NuGet, который пользователи должны запускать при создании шаблона. Сценарий просматривает каждый проект C# в решении, находит его "packages.config" (если есть), затем удаляет и переустанавливает каждый упомянутый там пакет.
Ясно, что есть много возможностей для улучшения, как с точки зрения общего подхода, так и с точки зрения мелких ошибок (например, команда nuget в разделе установки не будет выполняться для решений, в которых есть пробелы в полном имени), но это Начните.
Файл NuGet-RestorePackagesInAllProjects.psm1
$NuGetSources = "https://nuget.org/api/v2/;" # put your internal sources here as needed
function NuGet-RestorePackagesInAllProjects {
# get the solution directory
$solutionDir = (get-childitem $dte.Solution.FullName).DirectoryName
# for each C# project in the solution, process packages.config file, if there is one
$dte.Solution.Projects | Where-Object { $_.Type -eq "C#" } | ForEach-Object {
$currentProject = $_
$currentProjectName = $currentProject.ProjectName
$currentProjectDir = (get-childitem $_.FullName).DirectoryName
Write-Host ******* Starting processing $currentProjectName
# get the packages.config file for the current project
$packagesFile = $currentProject.ProjectItems | Where-Object { $_.Name -eq "packages.config" }
# if there's no packages.config, print a message and continue to the next project
if ($packagesFile -eq $null -or $packagesFile.count -gt 1) {
write-host ------- Project $currentProjectName doesn''t have packages.config
return
}
# read the contents of packages.config file and extract the list of packages in it
$fileName = $currentProjectDir + "\packages.config"
[xml]$content = Get-Content $fileName
$packageList = $content.packages.package | % { $_.id }
# for each package in the packages.config, uninstall the package (or simply remove the line from the file, if the uninstall fails)
$packageList | ForEach-Object {
$currentPackage = $_
write-host Uninstalling $currentPackage from $currentProjectName
try {
Uninstall-Package $currentPackage -ProjectName $currentProjectName -RemoveDependencies -Force
}
catch {
write-host '!!!!!!! $_.Exception.Message is' $_.Exception.Message
$node = $content.SelectSingleNode("//package[@id='$currentPackage']")
[Void]$node.ParentNode.RemoveChild($node)
$content.Save($fileName)
}
}
# download each package into the $(SolutionDir)packages folder, and install it into the current project from there
$packageList | ForEach-Object {
$currentPackage = $_
$localPackagesDir = $solutionDir + "\packages"
$cmd = $solutionDir + "\.nuget\nuget.exe install " + $currentPackage + " -Source """ + $NuGetSources + """ -o " + $localPackagesDir
write-host Installing $currentPackage to $currentProjectName
invoke-expression -command $cmd
Install-Package $currentPackage -ProjectName $currentProjectName -Source $localPackagesDir
}
Write-Host ******* Finished processing $currentProjectName
}
}
Export-ModuleMember NuGet-RestorePackagesInAllProjects
Файл init.ps1
param($installPath, $toolsPath, $package)
Import-Module (Join-Path $toolsPath NuGet-RestorePackagesInAllProjects.psm1)
Enable-PackageRestore
NuGet-RestorePackagesInAllProjects
Файл .nuspec для пакета
<?xml version="1.0" encoding="utf-16"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>NuGet-RestorePackagesInAllProjects</id>
<version>0.5.0</version>
<title>Custom NuGet Package Restore</title>
<authors>Me (c) 2012</authors>
<owners />
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Restore all packages in a given solution from packages.config in each project. For each packages.config, uninstalls all packages and then re-install them again from the sources specified in the script.</description>
<dependencies>
<dependency id="NuGetPowerTools" />
</dependencies>
</metadata>
<files>
<file src="init.ps1" target="tools\init.ps1" />
<file src="NuGet-RestorePackagesInAllProjects.psm1" target="tools\NuGet-RestorePackagesInAllProjects.psm1" />
</files>
</package>
Если вы просто удалите и переустановите пакеты из nuget, свойство version будет ссылаться на последнюю версию.
Возможно, вам придется отредактировать вручную файл packages.config, чтобы удалить старую ссылку перед повторной установкой из nuget (поскольку у меня недавно была ситуация, когда nuget не позволял мне устанавливать новый пакет, так как считал, что у меня есть старый пакет).)