7

PowerShell 小工具 - 自動補齊離線安裝 NuGet 套件

 9 months ago
source link: https://blog.darkthread.net/blog/ps-nupkg-downloader/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

自動補齊離線安裝 NuGet 套件-黑暗執行緒

在一般情況下,NuGet 套件會在編譯時自動從網路下載安裝,不需我們費心。但現實世界不如想像美好,有時你需要在無法上網的環境編譯專案,簡單解法是開個本地資料夾當成 NuGet 套件來源參考,手動下載預先放入 .nupkg 檔以實現離線安裝 NuGet 套件。

NuGet Gallery 每個套件首頁都有個 Download Package,點下去可下載格式如 dapper.2.1.24.nupkg 的套件檔,將其放入本機資料夾即可用於離線安裝。

Fig1_638385933252304747.png

如果你耐心破表,人工比對參照清單或遇到編譯有缺再去查網頁另存 .nupkg,日子其實也能過,但我是現代王藍田哪可能受得了?要我重複做個三次,肯定又會上演氣到摔滑鼠,用腳踩再咬破吐掉的戲碼(喂)。

所以,小工具來了,我寫了一支 Download-Nupkg.ps1,有三種用法:

# 指定套件名稱及版號
.\Download-Nupkg.ps1 Dapper 2.1.1
# 指定套件名稱,列舉版號,預設下載最新版
.\Download-Nupkg.ps1 Newtonsoft.Json
# 掃瞄 packages.config (.NET Framework) 或 .csproj (.NET 6+) 列出有參照的 NuGet 套件
# 比對本機資料夾是否已存在該 .nupkg ,若沒有才下載
.\Download-Nupkg.ps1 "X:\Github\WebApiWithAspNetMvcDemo\src\DemoWeb\packages.config"

操作展示

附上程式碼,有需要的同學請自取:(註:程式用 NuGet API 查詢套件可用版號及下載 .nupkg 檔)

param (
    [Parameter(Mandatory = $true)]
    [string]$pkgNameOrPkgConfig,
    [string]$version,
    [string]$saveFolder = '.'
)
Function GenNupkgPath($pkgName, $version) {
    return Join-Path $saveFolder "$pkgName.$version.nupkg"
}
Function DownloadNupkg {
    param (
        [Parameter(Mandatory = $true)]
        [string]$packageName, [string]$version
    )

    # https://learn.microsoft.com/en-us/nuget/api/package-base-address-resource
    $lowerId = $packageName.ToLower()
    $url = "https://api.nuget.org/v3-flatcontainer/$lowerId/index.json"
    try {
        $json = (Invoke-WebRequest -Uri $url).Content
    }
    catch {
        Write-Host "Package not found - $packageName" -ForegroundColor Red
        return
    }
    $versions = ($json | ConvertFrom-Json).versions
    $latestVersion = $versions[-1]
    if ([string]::IsNullOrEmpty($version)) {
        $versionList = $versions -join ", "
        Write-Host "Versions: $versionList"
        $selVer = Read-Host "Select (default: $latestVersion)"
        if ([string]::IsNullOrEmpty($selVer)) {
            $selVer = $latestVersion
        }
        $version = $selVer
    }
    # Convert x.x.x.0 to x.x.x
    $verParts = $version.Split('.')
    if ($verParts.Length -eq 4 -and $verParts[-1] -eq '0') {
        $version = $verParts[0..2] -join '.'
    }
    if (!$versions.Contains($version)) {
        Write-Host "Failed to download $packageName $version" -ForegroundColor Red
        return
    }
    else {
        $lowerVersion = $version.ToLower()
        [string]$downloadUrl = "https://api.nuget.org/v3-flatcontainer/$lowerId/$lowerVersion/$lowerId.$lowerVersion.nupkg"
        $path = GenNupkgPath $packageName $version
        try {
            Invoke-WebRequest -Uri $downloadUrl -OutFile $path
            Write-Host "    $path saved" -ForegroundColor Gray
        }
        catch {
            Write-Host "Failed to download $downloadUrl" -ForegroundColor Red
        }
    }
}
$pkgList = @()
if ($pkgNameOrPkgConfig -match '(.config|.csproj)$') {
    try {
        [xml]$xml = Get-Content $pkgNameOrPkgConfig
        if ($xml.Project) {
            $xml.Project.ItemGroup | ForEach-Object {
                $_.PackageReference | ForEach-Object {
                    if (!(Test-Path (GenNupkgPath $_.Include $_.Version))) {
                        $pkgList += [PSCustomObject]@{
                            Name    = $_.Include
                            Version = $_.Version
                        }
                    }
                }
            }
        }
        elseif ($xml.packages) {
            $xml.packages.package | ForEach-Object {
                if (!(Test-Path (GenNupkgPath $_.id $_.version))) {
                    $pkgList += [PSCustomObject]@{
                        Name    = $_.id
                        Version = $_.version
                    }
                }
            }
        }
        else {
            Write-Host "Unknown XML schema" -ForegroundColor Red
            return
        }
        if ($pkgList.Count -gt 0) {
            Write-Host "Missing pakcages found:"
            $idx = 1
            $pkgList | ForEach-Object {
                Write-Host "$idx. $($_.Name) $($_.Version)"
                $idx++
            }
            $confirm = Read-Host "Download? (Y/n)"
            if (![string]::IsNullOrEmpty($confirm) -and $confirm -ine 'y') {
                Write-Host 'Abort' 
                return
            }
        }
    }
    catch {
        Write-Host "Failed to load $pkgNameOrPkgConfig - $_" -ForegroundColor Red
        return
    }
}
else {
    $pkgList += [PSCustomObject]@{
        Name    = $pkgNameOrPkgConfig
        Version = $version
    }
}
$pkgList | ForEach-Object {
    Write-Host "Downloading $($_.Name) $($_.Version)..." -ForegroundColor Yellow
    DownloadNupkg $_.Name $_.Version
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK