2012-07-24 21 views
19

Tengo un proyecto con el siguiente packages.config:.NuGet de restauración paquete insiste en versiones de paquetes específicos

<?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> 

donde el marco * paquetes están sentados en nuestro repositorio local.

He habilitado la restauración de paquetes y he añadido nuestro repositorio interno a las fuentes. Sin embargo, cuando intento restaurar los paquetes de packages.config (que lo hace esencialmente nuget install packages.config -sources....), consigo los siguientes errores:

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'. 

El repositorio ya no contiene la versión del paquete 1.4.0.6 (que era relevante hace un par de meses), sino más bien la nueva versión de la misma (por ejemplo, 1.5.1.6).

¿Por qué NuGet no encuentra las nuevas versiones de los paquetes? ¿Hay alguna sintaxis que pueda especificar en packages.config para garantizar que se descargarán las últimas versiones?

En resumen, ¿hay algo menos que escribir un script personalizado para actualizar los paquetes que puedo hacer?

Gracias.

Respuesta

39

Creo que algunas personas no están entendiendo qué debe hacer la restauración de paquetes. Esta característica se agregó a NuGet con el único propósito de no requerir que los paquetes se verifiquen en el control de la versión. Mucha gente se quejaba de que los binarios comprometidos estaban explotando el tamaño de sus repositorios, y es aún peor cuando se usa un DVCS como git, donde todo el repositorio se descarga localmente e incluye todas las versiones del paquete Foo.

¿Qué hace exactamente Package Restore? Básicamente se ve en packages.config de cada proyecto y simplemente retira la versión específica del paquete en la lista. Es como eliminar la carpeta de paquetes y luego hacer git reset --hard para recuperarlos (suponiendo que la carpeta esté marcada).

¿Por qué es esto importante? ¿Por qué no actualizar a la última versión del paquete? Si considera el caso de uso más común de Restauración de paquetes, que es hacer compilaciones automáticas, eso debería darle una pista. El servidor de compilación solo debe construir el proyecto que un desarrollador haya probado y comprometido. Si permites que el servidor de compilación decida cuándo actualizar un paquete, entonces tienes un proyecto que no ha sido probado por nadie. Como desarrollador, debe ser el que decida cuándo realizar la actualización.

Recuerde, la instalación o actualización de un paquete no consiste simplemente en extraer un archivo .nupkg y agregar referencias. Muchos paquetes tienen efectos secundarios, como la actualización de sus archivos .config, la adición de código, etc. Cuando instala un paquete, todos esos efectos secundarios ocurren en su copia local. Ahora puede confirmar su código y excluir los archivos del paquete.

Cuando otro desarrollador o el servidor de compilación verifique el código, tendrá exactamente el mismo código de efecto secundario que tenía menos los archivos del paquete. Package Restore simplemente extrae estos archivos del repositorio NuGet y ahora tenemos todo lo necesario para trabajar en este proyecto.

El equipo NuGet ha prometido mantener todas las versiones de paquetes para que siempre pueda desplegar la versión correcta. Sin embargo, como vimos hace unos meses, cuando el servidor NuGet cayó, prácticamente paralizó la Restauración de paquetes y muchas personas no pudieron construir.

Te recomiendo que configures tu propio repositorio NuGet (un simple uso compartido de archivos) y guardes copias de todos los paquetes que usas allí. De esta forma, no dependes de un servidor externo para tus compilaciones. Y como lo hace el equipo NuGet, debes conservar TODAS las versiones de un paquete. De esta manera, si tiene que regresar y crear una versión anterior de su proyecto, tendrá las versiones correctas del paquete disponibles.

Espero que esto explique cómo funciona la función y por qué funciona de esa manera.

0

Si simplemente elimina y vuelve a instalar los paquetes de nuget, la propiedad de la versión hará referencia a la última versión.

Es posible que necesite editar el paquete.config manualmente para eliminar la referencia anterior antes de volver a instalar desde nuget (ya que tuve una situación reciente en la que nuget no me permitió instalar el nuevo paquete como creía que tenía el paquete anterior presente)

+0

Eso desafía el punto de restauración del paquete, ¿no? ... –

+0

Sí, lo hace, pero el OP mencionó si había alguna configuración de sintaxis de paquetes para obtener las últimas versiones. Una vez que esto se haya hecho una vez, cualquier persona que use el repositorio podrá tomar el proyecto utilizando el paquete restore restore – dougajmcdonald

+1

El proyecto en cuestión es parte de una plantilla de solución personalizada que estoy haciendo para nuestros proyectos internos. La idea es que un desarrollador cree una nueva solución a partir de la plantilla y obtenga toda la estructura (incluidas las referencias listas para los paquetes de infraestructura) en su lugar y lista para funcionar. No tengo problemas para escribir un script personalizado que repase todos los proyectos de la solución y vuelva a instalar los paquetes según sea necesario, pero decirles a las personas que comiencen a hurgar en una plantilla para que funcione correctamente ... –

0

En caso de que alguien se encuentre con esto, escribí un módulo PowerShell y lo envolví en un paquete NuGet que los usuarios necesitan ejecutar al momento de la creación de la plantilla. El script revisa cada proyecto de C# en la solución, localiza su "packages.config" (si corresponde), luego elimina y vuelve a instalar cada paquete mencionado allí.

Claramente, hay mucho margen de mejora, tanto en términos de enfoque general como en términos de pequeños errores (por ejemplo, el comando nuget en la sección de instalación no se ejecutará en soluciones que tengan espacios en el nombre completo), pero esto es un comienzo.

Archivo 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 

Archivo init.ps1

param($installPath, $toolsPath, $package) 

Import-Module (Join-Path $toolsPath NuGet-RestorePackagesInAllProjects.psm1) 

Enable-PackageRestore 

NuGet-RestorePackagesInAllProjects 

El .nuspec archivo para el paquete

<?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> 
8

Sugiero que lea NuGet documentation for Versioning. Explica cómo se pueden utilizar los números de versión (y rangos) en los archivos packages.config para permitir que el comando Update-Package sepa cuáles son las versiones aceptables para actualizar.

Dicho esto, la función Restaurar paquete no hará la actualización automática de los paquetes de actualización.

Con esta información, el mejor flujo de trabajo OMI es:

  • instala la última versión estable de cualquier nueva dependencia que está añadiendo a menos que realmente necesita una versión previa (o pre-lanzamiento)
  • Use Restaurar paquete en sus compilaciones CI, lo que le permite no registrar paquetes NuGet en su VCS
  • Solo Update-Package si ...
    • necesita una nueva llamada a la API o la corrección de errores de la versión más reciente
    • te banco de pruebas para la confianza
    • Usted tiene tiempo para lidiar con potenciales consecuencias

I no anime la actualización de paquetes regularmente simplemente porque. Es mejor dejar el proyecto funcionando tal como está con las dependencias más antiguas si funcionan lo suficientemente bien porque existe un riesgo al actualizar la versión de cualquier paquete.

Se supone que los paquetes NuGet siguen Semantic Versioning que tienen buenas reglas para permitir la experiencia de actualización de paquetes más libre de estrés, pero como esto no se aplica (y créanme, muchos editores de paquetes no siguen SemVer), puede confío en eso Incluso si un paquete se actualiza con un aumento de versión menor, no puede estar seguro (sin pruebas suficientes) de que la nueva versión funcionará con su código.

En resumen, actualizar cualquier paquete automáticamente suele ser una mala idea. Es mejor dejar que los desarrolladores elijan explícitamente actualizar cada paquete, y solo por una buena razón.

+3

El problema es que, según la especificación de versiones, la versión 'version =" 1.4.0.6 "' (que está predeterminada en packages.config) debe traducirse a 'versión> = 1.4.0.6' pero no lo es. Y creo que es un error en Nuget restore porque "update" no usa packages.config en absoluto (parece que solo usa carpetas en el directorio 'packages', así que si no tienes paquetes," update "no hará nada, ni siquiera si tiene el archivo packages.config). –

+4

@FuriCuri Los rangos de versión que describes solo se usan en los archivos '.nuspec', no en' packages.config'. Se usan para describir dependencias entre paquetes. Al especificar dependencias en su proyecto, utiliza el archivo 'packages.config' que siempre hará referencia a una versión específica. Y sí, tiene razón, el comando 'Update-Package' no funcionará a menos que haya construido su proyecto recientemente y todas las dependencias NuGet estén presentes en el directorio'/packages'.Esto puede ser inconveniente o poco intuitivo, pero no creo que sea un error; es simplemente la forma en que opera NuGet. –

+1

Ya veo. Bueno, lo he descrito aquí https://nuget.codeplex.com/workitem/3264 El mayor problema es que si intentas nuget restaurar el proyecto y tener algún paquete referenciado con una versión anterior que ya no está disponible en el repositorio (pero hay una versión más nueva) no hay forma de hacer versiones de actualización nuget en packages.config y .proj para ese paquete. –

Cuestiones relacionadas