19

次のpackages.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.* パッケージがローカル リポジトリにある場所。

Package Restore を有効にして、内部リポジトリをソースに追加しました。ただし、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

4 に答える 4

39

Package Restore の目的を誤解している人がいると思います。この機能は、パッケージをバージョン管理にチェックインする必要がないという目的でのみ、NuGet に追加されました。多くの人が、バイナリをコミットするとリポジトリのサイズが爆発的に増加していると不満を漏らしていました。git のような DVCS を使用すると、リポジトリ全体がローカルにダウンロードされ、パッケージ Foo のすべてのバージョンが含まれます。

では、Package Restore は正確には何をするのでしょうか? 基本的に、各プロジェクトの packages.config を調べて、リストされているパッケージの特定のバージョンを単純にプルダウンします。これは、packages フォルダーを削除してgit reset --hardから、元に戻すようなものです (フォルダーがチェックインされていると仮定します)。

何でこれが大切ですか?最新のパッケージ バージョンにアップグレードしませんか? Package Restore の最も一般的な使用例である自動ビルドを検討すると、手がかりが得られるはずです。ビルド サーバーは、開発者によってテストおよびコミットされたプロジェクトのみをビルドする必要があります。パッケージをいつ更新するかをビルド サーバーに決定させると、誰もテストしていないプロジェクトになります。開発者として、いつアップグレードを行うかを決定する必要があります。

パッケージのインストールまたは更新は、単に .nupkg ファイルを取得して参照を追加するだけではないことに注意してください。多くのパッケージには、.config ファイルの更新、コードの追加などの副作用があります。パッケージをインストールすると、これらすべての副作用がローカル コピーで発生します。コードをコミットして、パッケージ ファイルを除外できるようになりました。

別の開発者またはビルド サーバーがコードをチェックアウトすると、パッケージ ファイルを除いたまったく同じ副作用コードが表示されます。Package Restore は単にこれらのファイルを NuGet リポジトリから取得するだけで、このプロジェクトで作業するために必要なものがすべて揃っています。

NuGet チームは、常に正しいバージョンを取得できるように、すべてのバージョンのパッケージを維持することを約束しています。しかし、数か月前に見たように、NuGet サーバーがダウンしたとき、Package Restore はほとんど機能しなくなり、多くの人がビルドできなくなりました。

独自の NuGet リポジトリをセットアップし (単純なファイル共有で十分です)、そこで使用するすべてのパッケージのコピーを保持することをお勧めします。このようにして、ビルド用の外部サーバーに依存しません。また、NuGet チームが行っているように、パッケージのすべてのバージョンを保持する必要があります。こうすることで、以前のバージョンのプロジェクトに戻ってビルドする必要がある場合でも、正しいパッケージ バージョンを利用できるようになります。

これで、この機能がどのように機能し、なぜそのように機能するのかを説明できれば幸いです。

于 2012-07-24T14:32:31.037 に答える
8

Versioning の NuGet ドキュメントを読むことをお勧めします。packages.configファイルでバージョン番号 (および範囲) を使用して、Update-Packageコマンドがアップグレード可能なバージョンを認識できるようにする方法について説明します。

そうは言っても、パッケージの復元機能はパッケージを自動的に更新しません。

この情報を使用すると、最適なワークフロー IMO は次のようになります。

  • 古い(またはプレリリースの)バージョンが本当に必要な場合を除き、追加する新しい依存関係の最新の安定したバージョンをインストールします
  • CI ビルドで Package Restore を使用して、NuGet パッケージを VCS にチェックインしないようにします。
  • 場合のみUpdate-Package...
    • 最新バージョンからの新しい API 呼び出しまたはバグ修正が必要です
    • 信頼できる優れたテスト スイートがあります
    • 潜在的な影響に対処する時間があります

という理由だけでパッケージを定期的にアップグレードすることはお勧めしません。パッケージのバージョンを更新するときにリスクがあるため、古い依存関係が十分に機能する場合は、プロジェクトをそのままにしておくことをお勧めします。

NuGet パッケージは、最もストレスのないパッケージ アップグレード エクスペリエンスを可能にする適切なルールを持つセマンティック バージョニングに従うことになっていますが、これは強制されていないため (そして、私を信じてください、多くのパッケージ発行者は SemVer に従っていません)、頼ることはできません。それ。パッケージが更新されてバージョンがわずかに増加しただけの場合でも、(十分なテストを行わないと) 新しいバージョンがコードで動作することを確認することはできません。

要約すると、パッケージを自動的にアップグレードすることは、通常は悪い考えです。十分な理由がある場合にのみ、開発者が特定のパッケージを更新することを明示的に選択できるようにすることをお勧めします。

于 2013-01-02T23:07:34.290 に答える
0

nugetからパッケージを削除して再インストールするだけの場合、バージョンプロパティは最新バージョンを参照します。

nugetから再インストールする前に、packages.configを手動で編集して古い参照を削除する必要がある場合があります(最近、古いパッケージが存在すると思っていたため、nugetで新しいパッケージをインストールできない状況が発生したためです。 )。

于 2012-07-24T12:03:18.337 に答える
0

誰かがこれに遭遇した場合に備えて、私は 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>
于 2012-07-26T05:22:30.783 に答える