docs: 重构 README 新手使用说明,添加一键安装脚本文档
This commit is contained in:
161
uv-installer.ps1
161
uv-installer.ps1
@@ -33,6 +33,90 @@ param (
|
||||
[Parameter(HelpMessage = "Print Help")]
|
||||
[switch]$Help
|
||||
)
|
||||
function WebProxyFromUrl {
|
||||
param([string]$ProxyUrl)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($ProxyUrl)) {
|
||||
return $null
|
||||
}
|
||||
|
||||
try {
|
||||
# Parse the proxy URL
|
||||
$uri = [System.Uri]$ProxyUrl
|
||||
|
||||
# Create WebProxy instance
|
||||
$webProxy = New-Object System.Net.WebProxy($uri)
|
||||
|
||||
# Set credentials if provided in URL
|
||||
if (-not [string]::IsNullOrEmpty($uri.UserInfo)) {
|
||||
$userInfo = $uri.UserInfo.Split(':')
|
||||
$username = [System.Uri]::UnescapeDataString($userInfo[0])
|
||||
$password = if ($null -eq $userInfo[1]) { "" } else { [System.Uri]::UnescapeDataString($userInfo[1]) }
|
||||
$webProxy.Credentials = New-Object System.Net.NetworkCredential($username, $password)
|
||||
}
|
||||
|
||||
return $webProxy
|
||||
}
|
||||
catch {
|
||||
Write-Verbose("Failed to parse proxy URL '$ProxyUrl': $($_.Exception.Message)")
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function WebProxyFromEnvironment {
|
||||
$httpsProxy = [System.Environment]::GetEnvironmentVariable("HTTPS_PROXY")
|
||||
$allProxy = [System.Environment]::GetEnvironmentVariable("ALL_PROXY")
|
||||
$proxyUrl = if (-not [string]::IsNullOrWhiteSpace($httpsProxy)) { $httpsProxy } else { $allProxy }
|
||||
$webProxy = WebProxyFromUrl -ProxyUrl $proxyUrl
|
||||
return $webProxy
|
||||
}
|
||||
|
||||
# Downloads a URL to a local file using HttpClient with:
|
||||
# * a configurable per-request timeout (WebClient has none)
|
||||
# * proxy support from HTTPS_PROXY / ALL_PROXY
|
||||
# * bearer auth, attached ONLY when the target host is a trusted first-party
|
||||
# (github.com / astral.sh). This prevents leaking UV_GITHUB_TOKEN to
|
||||
# third-party mirrors configured in $ArtifactDownloadUrls.
|
||||
function Invoke-HttpDownload {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Url,
|
||||
[Parameter(Mandatory = $true)][string]$Destination,
|
||||
[int]$TimeoutSec = 30,
|
||||
[switch]$IncludeAuth
|
||||
)
|
||||
|
||||
$handler = New-Object System.Net.Http.HttpClientHandler
|
||||
$proxy = WebProxyFromEnvironment
|
||||
if ($null -ne $proxy) {
|
||||
$handler.Proxy = $proxy
|
||||
$handler.UseProxy = $true
|
||||
}
|
||||
|
||||
$client = New-Object System.Net.Http.HttpClient($handler)
|
||||
$client.Timeout = [TimeSpan]::FromSeconds($TimeoutSec)
|
||||
$client.DefaultRequestHeaders.Add("User-Agent", "PowerShell/uv-installer")
|
||||
|
||||
if ($IncludeAuth -and $auth_token -and ($Url -match 'github\.com|astral\.sh')) {
|
||||
$client.DefaultRequestHeaders.Add("Authorization", "Bearer $auth_token")
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $client.GetAsync($Url, [System.Net.Http.HttpCompletionOption]::ResponseHeadersRead).Result
|
||||
if (-not $response.IsSuccessStatusCode) {
|
||||
throw "HTTP $([int]$response.StatusCode) downloading $Url"
|
||||
}
|
||||
$stream = $response.Content.ReadAsStreamAsync().Result
|
||||
$fileStream = [System.IO.File]::Create($Destination)
|
||||
try {
|
||||
$stream.CopyTo($fileStream)
|
||||
} finally {
|
||||
$fileStream.Dispose()
|
||||
}
|
||||
} finally {
|
||||
$client.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
function Get-LatestVersion {
|
||||
if ($env:UV_INSTALLER_VERSION) {
|
||||
return $env:UV_INSTALLER_VERSION
|
||||
@@ -41,10 +125,22 @@ function Get-LatestVersion {
|
||||
$fallback_version = "0.11.20"
|
||||
|
||||
try {
|
||||
$http = New-Object System.Net.Http.HttpClient
|
||||
$http.Timeout = [TimeSpan]::FromSeconds(5)
|
||||
$handler = New-Object System.Net.Http.HttpClientHandler
|
||||
$proxy = WebProxyFromEnvironment
|
||||
if ($null -ne $proxy) {
|
||||
$handler.Proxy = $proxy
|
||||
$handler.UseProxy = $true
|
||||
}
|
||||
|
||||
$http = New-Object System.Net.Http.HttpClient($handler)
|
||||
# Bumped from 5s -> 10s. The API call is small but in proxy/restricted
|
||||
# networks 5s was almost always too tight and forced the fallback version.
|
||||
$http.Timeout = [TimeSpan]::FromSeconds(10)
|
||||
$http.DefaultRequestHeaders.Add("User-Agent", "PowerShell/uv-installer")
|
||||
$http.DefaultRequestHeaders.Add("Accept", "application/vnd.github+json")
|
||||
if ($auth_token) {
|
||||
$http.DefaultRequestHeaders.Add("Authorization", "Bearer $auth_token")
|
||||
}
|
||||
$response = $http.GetStringAsync("https://api.github.com/repos/astral-sh/uv/releases/latest").Result
|
||||
$json = $response | ConvertFrom-Json
|
||||
$version = $json.tag_name
|
||||
@@ -60,6 +156,9 @@ function Get-LatestVersion {
|
||||
}
|
||||
|
||||
$app_name = 'uv'
|
||||
# NOTE: $auth_token must be defined *before* Get-LatestVersion / Invoke-HttpDownload
|
||||
# are invoked, since both reference it.
|
||||
$auth_token = $env:UV_GITHUB_TOKEN
|
||||
$app_version = Get-LatestVersion
|
||||
if ($env:UV_DOWNLOAD_URL) {
|
||||
$ArtifactDownloadUrls = @($env:UV_DOWNLOAD_URL)
|
||||
@@ -72,6 +171,10 @@ if ($env:UV_DOWNLOAD_URL) {
|
||||
$installer_base_url = $env:UV_INSTALLER_GITHUB_BASE_URL
|
||||
$ArtifactDownloadUrls = @("$installer_base_url/astral-sh/uv/releases/download/$app_version")
|
||||
} else {
|
||||
# Default download sources, ordered by priority.
|
||||
# Mirror entries exist to work around GitHub connectivity issues in mainland China.
|
||||
# If you are outside China or these mirrors become unavailable, you can safely
|
||||
# delete the two mirror lines and rely on the official URLs (first + last).
|
||||
$ArtifactDownloadUrls = @(
|
||||
"https://releases.astral.sh/github/uv/releases/download/$app_version",
|
||||
"https://mirror.ghproxy.com/https://github.com/astral-sh/uv/releases/download/$app_version",
|
||||
@@ -80,8 +183,6 @@ if ($env:UV_DOWNLOAD_URL) {
|
||||
)
|
||||
}
|
||||
|
||||
$auth_token = $env:UV_GITHUB_TOKEN
|
||||
|
||||
$receipt = @"
|
||||
{"binaries":["CARGO_DIST_BINS"],"binary_aliases":{},"cdylibs":["CARGO_DIST_DYLIBS"],"cstaticlibs":["CARGO_DIST_STATICLIBS"],"install_layout":"unspecified","install_prefix":"AXO_INSTALL_PREFIX","modify_path":true,"provider":{"source":"cargo-dist","version":"0.31.0"},"source":{"app_name":"uv","name":"uv","owner":"astral-sh","release_type":"github"},"version":"$app_version"}
|
||||
"@
|
||||
@@ -269,44 +370,6 @@ function Get-Arch() {
|
||||
}
|
||||
}
|
||||
|
||||
function WebProxyFromUrl {
|
||||
param([string]$ProxyUrl)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($ProxyUrl)) {
|
||||
return $null
|
||||
}
|
||||
|
||||
try {
|
||||
# Parse the proxy URL
|
||||
$uri = [System.Uri]$ProxyUrl
|
||||
|
||||
# Create WebProxy instance
|
||||
$webProxy = New-Object System.Net.WebProxy($uri)
|
||||
|
||||
# Set credentials if provided in URL
|
||||
if (-not [string]::IsNullOrEmpty($uri.UserInfo)) {
|
||||
$userInfo = $uri.UserInfo.Split(':')
|
||||
$username = [System.Uri]::UnescapeDataString($userInfo[0])
|
||||
$password = if ($null -eq $userInfo[1]) { "" } else { [System.Uri]::UnescapeDataString($userInfo[1]) }
|
||||
$webProxy.Credentials = New-Object System.Net.NetworkCredential($username, $password)
|
||||
}
|
||||
|
||||
return $webProxy
|
||||
}
|
||||
catch {
|
||||
Write-Verbose("Failed to parse proxy URL '$ProxyUrl': $($_.Exception.Message)")
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function WebProxyFromEnvironment {
|
||||
$httpsProxy = [System.Environment]::GetEnvironmentVariable("HTTPS_PROXY")
|
||||
$allProxy = [System.Environment]::GetEnvironmentVariable("ALL_PROXY")
|
||||
$proxyUrl = if (-not [string]::IsNullOrWhiteSpace($httpsProxy)) { $httpsProxy } else { $allProxy }
|
||||
$webProxy = WebProxyFromUrl -ProxyUrl $proxyUrl
|
||||
return $webProxy
|
||||
}
|
||||
|
||||
function Download($download_url, $platforms, $arch) {
|
||||
# Lookup what we expect this platform to look like
|
||||
$info = $platforms[$arch]
|
||||
@@ -324,15 +387,7 @@ function Download($download_url, $platforms, $arch) {
|
||||
$url = "$download_url/$artifact_name"
|
||||
Write-Verbose " from $url"
|
||||
Write-Verbose " to $dir_path"
|
||||
$wc = New-Object Net.Webclient
|
||||
$proxy = WebProxyFromEnvironment
|
||||
if ($null -ne $proxy) {
|
||||
$wc.Proxy = $proxy
|
||||
}
|
||||
if ($auth_token) {
|
||||
$wc.Headers["Authorization"] = "Bearer $auth_token"
|
||||
}
|
||||
$wc.downloadFile($url, $dir_path)
|
||||
Invoke-HttpDownload -Url $url -Destination $dir_path -TimeoutSec 30 -IncludeAuth
|
||||
|
||||
Write-Verbose "Unpacking to $tmp"
|
||||
|
||||
@@ -377,7 +432,7 @@ function Download($download_url, $platforms, $arch) {
|
||||
$updater_url = "$download_url/$updater_id"
|
||||
$out_name = "$tmp\uv-update.exe"
|
||||
|
||||
$wc.downloadFile($updater_url, $out_name)
|
||||
Invoke-HttpDownload -Url $updater_url -Destination $out_name -TimeoutSec 30 -IncludeAuth
|
||||
$bin_paths += $out_name
|
||||
}
|
||||
|
||||
@@ -549,7 +604,7 @@ function Invoke-Installer($artifacts, $platforms) {
|
||||
# .NET's APIs which actually do what you tell them (also apparently utf8NoBOM is the
|
||||
# default in newer .NETs but I'd rather not rely on that at this point).
|
||||
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
|
||||
[IO.File]::WriteAllLines("$receipt_home/uv-receipt.json", "$receipt", $Utf8NoBomEncoding)
|
||||
[IO.File]::WriteAllLines("$receipt_home\uv-receipt.json", "$receipt", $Utf8NoBomEncoding)
|
||||
}
|
||||
|
||||
# Respect the environment, but CLI takes precedence
|
||||
|
||||
Reference in New Issue
Block a user