2012-07-24 12 views
19

Mam projekt z następującym packages.config.Nuget Przywróćmy Pakiet kładzie nacisk na konkretne wersje pakietów

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

których ramy * Pakiety siedzą w naszym lokalnym repozytorium.

Włączyłem funkcję przywracania pakietów i dodałem nasze wewnętrzne repo do źródeł. Jednak przy próbie przywrócenia paczki od packages.config (które zasadniczo nie nuget install packages.config -sources....), otrzymuję następujące błędy:

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

Repozytorium nie zawiera już 1.4.0.6 wersję pakietu (co było istotne kilka miesięcy temu), ale raczej jego nowa wersja (np. 1.5.1.6).

Dlaczego NuGet nie znajduje nowych wersji pakietów? Czy jest jakaś składnia, którą mogę określić w packages.config, aby upewnić się, że zostaną pobrane najnowsze wersje?

Krótko mówiąc, czy istnieje coś innego niż napisanie niestandardowego skryptu, aby zaktualizować pakiety, które mogę zrobić?

Dziękuję.

Odpowiedz

39

Myślę, że niektórzy ludzie nie rozumieją, co ma zrobić przywracanie pakietów. Ta funkcja została dodana do NuGet wyłącznie w celu niewymagania sprawdzania pakietów w kontroli wersji. Wiele osób narzekało na to, że polecanie plików binarnych eksplodowało rozmiar ich repozytoriów, a jeszcze gorzej, gdy używa się DVCS jak git, gdzie całe repo jest pobierane lokalnie i zawiera każdą wersję pakietu Foo.

Co dokładnie robi przywracanie pakietu? Zasadniczo wygląda to w pliku packages.config każdego projektu i po prostu usuwa konkretną wersję wymienionego pakietu. To tak jak usuwanie folderu paczek, a następnie wykonanie git reset --hard, aby je przywrócić (zakładając, że folder został zaznaczony).

Dlaczego jest to ważne? Dlaczego nie uaktualnić do najnowszej wersji pakietu? Jeśli weźmiesz pod uwagę najczęstszy przypadek użycia funkcji przywracania pakietów, która polega na wykonywaniu zautomatyzowanych kompilacji, powinna dać ci wskazówkę. Serwer budujący powinien budować tylko projekt, który został przetestowany i zatwierdzony przez programistę. Jeśli pozwolisz, aby serwer kompilacji zdecydował, kiedy zaktualizować pakiet, masz projekt, który nie został przetestowany przez nikogo. Jako programista powinieneś być tym, który zdecyduje, kiedy dokonać aktualizacji.

Pamiętaj, że instalacja lub aktualizacja pakietu nie polega po prostu na usunięciu pliku .nupkg i dodaniu odnośników. Wiele pakietów ma skutki uboczne, takie jak aktualizowanie plików .config, dodawanie kodu, itp. Podczas instalowania pakietu wszystkie te skutki uboczne występują w lokalnej kopii. Możesz teraz zatwierdzić swój kod i wykluczyć pliki pakietów.

Gdy inny programista lub serwer kompilacji sprawdzi kod, otrzyma on ten sam kod efektu ubocznego, co minus pliki pakietu. Przywracanie pakietów po prostu ściąga te pliki z repozytorium NuGet, a teraz mamy wszystko, co potrzebne do pracy nad tym projektem.

Zespół NuGet obiecał utrzymywać wszystkie wersje pakietów, dzięki czemu zawsze będzie można pobrać właściwą wersję. Jednak, jak widzieliśmy kilka miesięcy temu, kiedy serwer NuGet przestał działać, prawie sparaliżowało Przywracanie pakietów i wielu ludzi nie udało się zbudować.

Polecam skonfigurować własne repozytorium NuGet (wystarczy zwykły udział w pliku) i zachować kopie wszystkich pakietów, których tam używasz. W ten sposób nie jesteś zależny od zewnętrznego serwera dla twoich kompilacji. I tak jak zespół NuGet, powinieneś zachować WSZYSTKIE wersje pakietu. W ten sposób, jeśli będziesz musiał wrócić i zbudować starszą wersję swojego projektu, będziesz mieć pewność, że dostępne są poprawne wersje pakietów.

Mam nadzieję, że to wyjaśni, jak działa ta funkcja i dlaczego działa w ten sposób.

0

Jeśli po prostu usuniesz i zainstalujesz ponownie pakiety z nuget, właściwość version odwoła się do najnowszej wersji.

Może zajść potrzeba ręcznej edycji pliku packages.config, aby usunąć stare odwołanie przed ponowną instalacją z nuget (ponieważ ostatnio miałem sytuację, w której nuget nie pozwoliłby mi zainstalować nowego pakietu, ponieważ uważał, że mam stary pakiet obecny)

+0

To jest sprzeczne z punktem przywracania pakietu, czyż nie? .. –

+0

Tak, robi to, ale OP wspomniano, jeśli istniała jakakolwiek konfiguracja składni pakietów, aby uzyskać najnowsze wersje. Gdy raz zostanie to zrobione, każda osoba korzystająca z repozytorium będzie mogła pobrać projekt przy użyciu przywracania pakietu. – dougajmcdonald

+1

Ten projekt jest częścią niestandardowego szablonu rozwiązania, który robię dla naszych wewnętrznych projektów. Chodzi o to, że programista utworzy nowe rozwiązanie z szablonu i udostępni całą strukturę (w tym gotowe odniesienia do pakietów infrastruktury) i będzie gotowy do pracy. Nie mam problemu z napisaniem niestandardowego skryptu, który przejdzie przez wszystkie projekty w roztworze i ponownie zainstaluje pakiety w razie potrzeby, ale mówienie ludziom, aby zaczęli grzebać w szablonie, aby działało, jest złe ... –

0

Jeśli ktoś na to wpisze, napisałem moduł PowerShell i opakowałem go w pakiet NuGet, który użytkownicy muszą uruchomić po utworzeniu szablonu. Skrypt przechodzi przez każdy projekt C# w rozwiązaniu, lokalizuje jego "packages.config" (jeśli istnieje), a następnie usuwa i ponownie instaluje każdy wymieniony tam pakiet.

Oczywiście istnieje wiele możliwości poprawy, zarówno pod względem ogólnego podejścia, jak i małych błędów (na przykład polecenie nuget w sekcji instalacji nie będzie działać na rozwiązaniach, które mają spacje w pełnej nazwie), ale to jest początek.

pliku 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 

pliku init.ps1

param($installPath, $toolsPath, $package) 

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

Enable-PackageRestore 

NuGet-RestorePackagesInAllProjects 

.nuspec pliku dla pakietu

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

Sugeruję przeczytanie NuGet documentation for Versioning. Wyjaśnia, w jaki sposób numery wersji (i zakresy) mogą być używane w plikach packages.config, aby umożliwić komendzie Update-Package poznanie dopuszczalnych wersji do uaktualnienia.

W związku z tym funkcja przywracania pakietów nie będzie automatycznie aktualizować pakietów dla użytkownika.

Dzięki tej informacji, najlepiej workflow IMO jest:

  • zainstalować najnowsze, stabilne wersje każdego nowego uzależnienia dodawanego chyba naprawdę potrzebują starsze (lub pre-release) wersji
  • Użyj funkcji przywracania pakietów w kompilacjach CI, co pozwala na nie zameldowanie pakietów NuGet w systemie VCS
  • Tylko Update-Package, jeśli ...
    • Potrzebujesz nowego wywołania API lub bug fix z najnowszej wersji
    • masz świetny zestaw testów dla zaufania
    • Masz czas do czynienia z potencjalnym fallout

I nie zachęcaj do regularnego aktualizowania pakietów tylko dlatego, że. Lepiej jest pozostawić projekt działający tak jak jest ze starszymi zależnościami, jeśli działają one wystarczająco dobrze, ponieważ istnieje ryzyko aktualizacji wersji pakietów.

Pakiety NuGet mają być zgodne z Semantic Versioning, który ma dobre zasady pozwalające na najbardziej bezstresową aktualizację pakietu, ale ponieważ nie jest to wymuszane (i wierz mi, wielu wydawców pakietów nie śledzi SemVer), możesz ' na czymś polegać. Nawet jeśli pakiet jest aktualizowany tylko z niewielkim wzrostem wersji, nie można mieć pewności (bez wystarczających testów), że nowa wersja będzie działała z twoim kodem.

Podsumowując, aktualizacja pakietów automatycznie jest zazwyczaj złym pomysłem. Lepiej pozwolić programistom wyraźnie wybrać aktualizację dowolnych pakietów i tylko z wystarczającej przyczyny.

+3

Problem polega na tym, że na podstawie specyfikacji wersji wersja 'version =" 1.4.0.6 "' (która jest domyślnie w packages.config) powinna zostać przetłumaczona na 'version> = 1.4.0.6', ale tak nie jest. I myślę, że to błąd w przywracaniu nugetu, ponieważ "aktualizacja" w ogóle nie używa packages.config (wydaje się, że używa tylko folderów w katalogu 'packages' - więc jeśli nie masz żadnych pakietów," aktualizacja "nic nie da jeśli masz plik packages.config). –

+4

@FuriCuri Opisane zakresy wersji są używane tylko w plikach '.nuspec', a nie' packages.config'. Służą do opisania zależności między pakietami. Podczas określania zależności w projekcie używa się plików 'packages.config', które zawsze będą odwoływać się do konkretnej wersji. I owszem, masz rację, polecenie 'Update-Package' nie zadziała, chyba że niedawno zbudowałeś swój projekt i wszystkie zależności NuGet są obecne w katalogu'/packages'.Może to być niewygodne lub nieintuicyjne, ale nie uważam, że jest to błąd; jest to po prostu sposób działania NuGet. –

+1

Rozumiem. Cóż, opisałem to tutaj https://nuget.codeplex.com/workitem/3264 Największym problemem jest to, że jeśli spróbujesz nuget przywrócić projekt i masz pakiet, do którego odwołuje się stara wersja, która nie jest już dostępna w repozytorium (ale jest nowsza wersja) nie ma sposobu, aby tworzyć wersje aktualizacji nuget w pliku packages.config i .proj dla tego pakietu. –

Powiązane problemy