Includes/Download.provider.url.ps1
|
<#
Provider : url (direct download) Dependencies : PwSh.Fw.Web (Download-File) The local asset name is derived from the leaf of the URL path. When the URL does not point to a file (e.g. query-string urls like https://host/?product=...&os=win64), the name is taken from the Content-Disposition header of the response (HEAD request), falling back to '<codename>-<version>'. v1 limitation : no signature verification (no companion file that can be located by pattern). #> <# .SYNOPSIS Compute the local file name for a direct URL. .DESCRIPTION Fallback chain : leaf of the URL path → Content-Disposition filename from a HEAD request → '<codename>-<version>'. #> function Get-AssetLocalName { [CmdletBinding()] [OutputType([string])] Param ( [Parameter(Mandatory = $true)][string]$Url, # Fallback values when no name can be derived [Parameter(Mandatory = $false)][string]$Codename, [Parameter(Mandatory = $false)][string]$Version ) Begin { Write-EnterFunction } Process { $uri = [uri]$Url # query-string urls (https://host/?product=...) have an empty path leaf if ($uri.AbsolutePath.TrimEnd('/') -ne '') { $leaf = [uri]::UnEscapeDataString($uri.AbsolutePath.TrimEnd('/')) | Split-Path -Leaf if ($leaf) { return $leaf } } try { $resp = Invoke-WebRequest -Uri $Url -Method Head -UseBasicParsing -MaximumRedirection 5 -ErrorAction Stop $cd = $resp.Headers['Content-Disposition'] if ($cd -match 'filename\*?=[''"]?(?<name>[^''";]+)[''"]?') { $name = [uri]::UnEscapeDataString($Matches.name.Trim()) if ($name) { return $name } } } catch { Write-Verbose "Could not derive asset name from Content-Disposition : $_" } if ($Codename -and $Version) { return "$Codename-$Version" } return 'download' } End { Write-LeaveFunction } } <# .SYNOPSIS Get asset information from a direct URL without downloading. #> function Get-AssetInfoFromUrl { [CmdletBinding()] [OutputType([array])] Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][object]$pkgdef, [Parameter(Mandatory = $false)][string]$CachePath, [Parameter(Mandatory = $false)][hashtable]$mustacheValues = @{} ) Begin { Write-EnterFunction $assets = @() } Process { $url = Render-MustacheField -value $pkgdef.download.url -mustacheValues $mustacheValues $fileName = Get-AssetLocalName -Url $url -Codename $pkgdef.codename -Version ($mustacheValues.VERSION ?? $pkgdef.version) $assets += @{ name = $fileName download_url = $url local_path = "$CachePath/$fileName" } } End { Write-LeaveFunction return $assets } } <# .SYNOPSIS Download an asset from a direct URL. .DESCRIPTION Renders the mustache URL, computes the local file name, downloads the file (skipping when already cached). Returns the local path. #> function Download-AssetFromUrl { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "", Justification="Download is a more intuitive verb for this function because Get- is too generic.")] [CmdletBinding()] [OutputType([String])] Param ( # Resolved package definition [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][object]$pkgdef, # Destination path (cache directory) [Parameter()][String]$DestinationPath, # Template values (uppercase keys, mustache compatible) [Parameter(Mandatory = $false)][hashtable]$mustacheValues = @{} ) Begin { Write-EnterFunction } Process { # Resolve DestinationPath: parameter > pkgdef.download.destination > temp path if ([string]::IsNullOrEmpty($DestinationPath)) { if ($pkgdef.download.destination) { $DestinationPath = $pkgdef.download.destination } else { $DestinationPath = [io.path]::GetTempPath() } } $url = Render-MustacheField -value $pkgdef.download.url -mustacheValues $mustacheValues $fileName = Get-AssetLocalName -Url $url -Codename $pkgdef.codename -Version ($mustacheValues.VERSION ?? $pkgdef.version) $destFile = "$DestinationPath/$fileName" if (Test-FileExist $destFile) { Write-Verbose "Asset $fileName already exists in $DestinationPath, skipping download" return $destFile } Write-Verbose "Downloading $url to $destFile" $null = Download-File -Url $url -To $DestinationPath -Filename $fileName -PassThru if (-not (Test-FileExist $destFile)) { Write-Fatal "Error downloading asset from $url" return $null } return $destFile } End { Write-LeaveFunction } } |