mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-01 04:14:50 +00:00
266 lines
8.4 KiB
PowerShell
266 lines
8.4 KiB
PowerShell
# Qwen Code Desktop Windows Installer
|
|
# Usage: disabled until an owned update server is configured
|
|
|
|
& {
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$VERSIONS_URL = ""
|
|
$DOWNLOAD_DIR = "$env:TEMP\qwen-code-install"
|
|
$APP_NAME = "Qwen Code Desktop"
|
|
|
|
# Colors for output
|
|
function Write-Info { Write-Host "> $args" -ForegroundColor Blue }
|
|
function Write-Success { Write-Host "> $args" -ForegroundColor Green }
|
|
function Write-Warn { Write-Host "! $args" -ForegroundColor Yellow }
|
|
function Write-Err { Write-Host "x $args" -ForegroundColor Red; exit 1 }
|
|
|
|
Write-Err "Desktop installer is disabled until an owned update server is configured."
|
|
|
|
# Check for Windows
|
|
if ($env:OS -ne "Windows_NT") {
|
|
Write-Err "This installer is for Windows only."
|
|
}
|
|
|
|
# Detect architecture
|
|
$arch = if ([Environment]::Is64BitOperatingSystem) { "x64" } else { "x86" }
|
|
$platform = "win32-$arch"
|
|
|
|
Write-Host ""
|
|
Write-Info "Detected platform: $platform (arch: $arch)"
|
|
|
|
# Create download directory
|
|
New-Item -ItemType Directory -Force -Path $DOWNLOAD_DIR | Out-Null
|
|
|
|
# Fetch YAML manifest directly from /electron/latest/ (no version endpoint needed)
|
|
Write-Info "Fetching release info..."
|
|
$yamlPath = Join-Path $DOWNLOAD_DIR "latest.yml"
|
|
try {
|
|
Invoke-WebRequest -Uri "$VERSIONS_URL/latest/latest.yml" -OutFile $yamlPath -UseBasicParsing
|
|
} catch {
|
|
Write-Err "Failed to fetch release info: $_"
|
|
}
|
|
|
|
$yamlContent = Get-Content $yamlPath -Raw
|
|
if (-not $yamlContent) {
|
|
Write-Err "Failed to fetch release info from latest.yml"
|
|
}
|
|
|
|
# Extract version from YAML manifest
|
|
$version = $null
|
|
if ($yamlContent -match '(?m)^version:\s*(.+)') {
|
|
$version = $Matches[1].Trim()
|
|
}
|
|
|
|
if (-not $version) {
|
|
Write-Err "Failed to extract version from manifest"
|
|
}
|
|
|
|
Write-Info "Latest version: $version"
|
|
|
|
# Parse YAML to extract sha512, url (filename), and size for our architecture
|
|
# YAML format:
|
|
# files:
|
|
# - url: Qwen-Code-Desktop-x64.exe
|
|
# sha512: <base64>
|
|
# size: 123456789
|
|
# arch: x64
|
|
function Get-YamlEntryForArch {
|
|
param([string]$yaml, [string]$targetArch)
|
|
$lines = $yaml -split "`n"
|
|
$currentUrl = $null
|
|
$currentSha512 = $null
|
|
$currentSize = $null
|
|
|
|
foreach ($line in $lines) {
|
|
if ($line -match '^\s*-\s*url:\s*(.+)') {
|
|
$currentUrl = $Matches[1].Trim()
|
|
$currentSha512 = $null
|
|
$currentSize = $null
|
|
}
|
|
if ($line -match '^\s*sha512:\s*(.+)') {
|
|
$currentSha512 = $Matches[1].Trim()
|
|
}
|
|
if ($line -match '^\s*size:\s*(\d+)') {
|
|
$currentSize = [long]$Matches[1]
|
|
}
|
|
if ($line -match '^\s*arch:\s*(.+)') {
|
|
$entryArch = $Matches[1].Trim()
|
|
if ($entryArch -eq $targetArch -and $currentSha512 -and $currentUrl) {
|
|
return @{ url = $currentUrl; sha512 = $currentSha512; size = $currentSize }
|
|
}
|
|
}
|
|
}
|
|
return $null
|
|
}
|
|
|
|
$entry = Get-YamlEntryForArch -yaml $yamlContent -targetArch $arch
|
|
|
|
if (-not $entry) {
|
|
Write-Err "Architecture $arch not found in latest.yml"
|
|
}
|
|
|
|
$checksum = $entry.sha512
|
|
$filename = $entry.url
|
|
$fileSize = $entry.size
|
|
|
|
# Validate checksum format (SHA-512 base64 = 88 characters)
|
|
if (-not $checksum -or $checksum.Length -lt 80) {
|
|
Write-Err "Invalid checksum in manifest"
|
|
}
|
|
|
|
# Use default filename if not found
|
|
if (-not $filename) {
|
|
$filename = "Qwen-Code-Desktop-$arch.exe"
|
|
}
|
|
|
|
$installerUrl = "$VERSIONS_URL/latest/$filename"
|
|
|
|
Write-Info "Expected sha512: $($checksum.Substring(0, 20))..."
|
|
|
|
# Download installer with progress
|
|
$installerPath = Join-Path $DOWNLOAD_DIR $filename
|
|
$fileSizeMB = if ($fileSize -gt 0) { [math]::Round($fileSize / 1MB, 1) } else { 0 }
|
|
|
|
# Clean up any partial download from previous attempts
|
|
Remove-Item -Path $installerPath -Force -ErrorAction SilentlyContinue
|
|
|
|
Write-Info "Downloading $filename ($fileSizeMB MB)..."
|
|
|
|
try {
|
|
# Use WebRequest for download with progress
|
|
$webRequest = [System.Net.HttpWebRequest]::Create($installerUrl)
|
|
$webRequest.Timeout = 600000 # 10 minutes
|
|
$response = $webRequest.GetResponse()
|
|
$responseStream = $response.GetResponseStream()
|
|
$fileStream = [System.IO.File]::Create($installerPath)
|
|
|
|
$buffer = New-Object byte[] 65536
|
|
$totalRead = 0
|
|
$lastPercent = -1
|
|
|
|
while (($read = $responseStream.Read($buffer, 0, $buffer.Length)) -gt 0) {
|
|
$fileStream.Write($buffer, 0, $read)
|
|
$totalRead += $read
|
|
|
|
if ($fileSize -gt 0) {
|
|
$percent = [math]::Floor(($totalRead / $fileSize) * 100)
|
|
if ($percent -ne $lastPercent) {
|
|
$downloadedMB = [math]::Round($totalRead / 1MB, 1)
|
|
$barWidth = 40
|
|
# Cap at 100% for display (actual download may exceed manifest size slightly)
|
|
$displayPercent = [math]::Min($percent, 100)
|
|
$filled = [math]::Min([math]::Floor($displayPercent / (100 / $barWidth)), $barWidth)
|
|
$bar = "[" + ("#" * $filled) + ("-" * ($barWidth - $filled)) + "]"
|
|
Write-Host -NoNewline ("`r $bar $percent% ($downloadedMB / $fileSizeMB MB) ")
|
|
$lastPercent = $percent
|
|
}
|
|
}
|
|
}
|
|
|
|
$fileStream.Close()
|
|
$responseStream.Close()
|
|
$response.Close()
|
|
|
|
Write-Host ""
|
|
Write-Success "Download complete!"
|
|
} catch {
|
|
# Clean up partial download on failure
|
|
if ($fileStream) { $fileStream.Close() }
|
|
if ($responseStream) { $responseStream.Close() }
|
|
if ($response) { $response.Close() }
|
|
Remove-Item -Path $installerPath -Force -ErrorAction SilentlyContinue
|
|
Write-Err "Download failed: $_"
|
|
}
|
|
|
|
# Verify file was downloaded
|
|
if (-not (Test-Path $installerPath)) {
|
|
Write-Err "Download failed: file not found"
|
|
}
|
|
|
|
# Verify checksum (SHA-512, base64 encoded — matches electron-builder YAML manifest)
|
|
Write-Info "Verifying checksum..."
|
|
$sha512 = [System.Security.Cryptography.SHA512]::Create()
|
|
$stream = [System.IO.File]::OpenRead($installerPath)
|
|
$hashBytes = $sha512.ComputeHash($stream)
|
|
$stream.Close()
|
|
$sha512.Dispose()
|
|
$actualHash = [Convert]::ToBase64String($hashBytes)
|
|
|
|
if ($actualHash -ne $checksum) {
|
|
Remove-Item -Path $installerPath -Force -ErrorAction SilentlyContinue
|
|
Write-Err "Checksum verification failed`n Expected: $checksum`n Actual: $actualHash"
|
|
}
|
|
|
|
Write-Success "Checksum verified!"
|
|
|
|
# Close the app if it's running
|
|
$process = Get-Process -Name "Qwen Code Desktop", "Qwen Code" -ErrorAction SilentlyContinue
|
|
if ($process) {
|
|
Write-Info "Closing Qwen Code Desktop..."
|
|
$process | Stop-Process -Force
|
|
Start-Sleep -Seconds 2
|
|
}
|
|
|
|
# Run the installer
|
|
Write-Info "Running installer (follow the installer prompts)..."
|
|
|
|
try {
|
|
$installerProcess = Start-Process -FilePath $installerPath -PassThru
|
|
$spinner = @('|', '/', '-', '\')
|
|
$i = 0
|
|
|
|
while (-not $installerProcess.HasExited) {
|
|
Write-Host -NoNewline ("`r Installing... " + $spinner[$i % 4] + " ")
|
|
Start-Sleep -Milliseconds 200
|
|
$i++
|
|
}
|
|
|
|
Write-Host -NoNewline "`r `r"
|
|
|
|
if ($installerProcess.ExitCode -ne 0) {
|
|
Write-Err "Installation failed with exit code: $($installerProcess.ExitCode)"
|
|
}
|
|
} catch {
|
|
Write-Err "Installation failed: $_"
|
|
}
|
|
|
|
# Clean up installer
|
|
Write-Info "Cleaning up..."
|
|
Remove-Item -Path $installerPath -Force -ErrorAction SilentlyContinue
|
|
|
|
# Add command line shortcut
|
|
Write-Info "Adding 'qwen-code' command to PATH..."
|
|
|
|
$binDir = "$env:LOCALAPPDATA\Qwen Code\bin"
|
|
$cmdFile = "$binDir\qwen-code.cmd"
|
|
$exePath = "$env:LOCALAPPDATA\Programs\Qwen Code Desktop\Qwen Code Desktop.exe"
|
|
|
|
# Create bin directory
|
|
New-Item -ItemType Directory -Force -Path $binDir | Out-Null
|
|
|
|
# Create batch file launcher
|
|
$cmdContent = "@echo off`r`nstart `"`" `"$exePath`" %*"
|
|
Set-Content -Path $cmdFile -Value $cmdContent -Encoding ASCII
|
|
|
|
# Add to user PATH if not already there
|
|
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
if ($userPath -notlike "*$binDir*") {
|
|
$newPath = "$userPath;$binDir"
|
|
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
|
|
Write-Success "Added to PATH (restart terminal to use 'qwen-code' command)"
|
|
} else {
|
|
Write-Success "Command 'qwen-code' is ready"
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "---------------------------------------------------------------------"
|
|
Write-Host ""
|
|
Write-Success "Installation complete!"
|
|
Write-Host ""
|
|
Write-Host " Qwen Code Desktop has been installed."
|
|
Write-Host ""
|
|
Write-Host " Launch from:"
|
|
Write-Host " - Start Menu or desktop shortcut"
|
|
Write-Host " - Command line: qwen-code (restart terminal first)"
|
|
Write-Host ""
|
|
}
|