From bf587cb49b410d3d5cf854b14951148cda5e9e7d Mon Sep 17 00:00:00 2001 From: Julian Freeman Date: Sat, 14 Mar 2026 17:12:47 -0400 Subject: [PATCH] fix list software --- src-tauri/src/winget.rs | 132 +++++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 55 deletions(-) diff --git a/src-tauri/src/winget.rs b/src-tauri/src/winget.rs index 3d46a94..eb2e0e5 100644 --- a/src-tauri/src/winget.rs +++ b/src-tauri/src/winget.rs @@ -24,85 +24,107 @@ struct WingetPackage { } pub fn ensure_winget_dependencies() -> Result<(), String> { - // 1. 检查 winget - let winget_check = Command::new("winget") - .arg("--version") + // 确保执行权限和模块存在 + let setup_script = r#" + $ErrorActionPreference = 'SilentlyContinue' + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force + if (-not (Get-Module -ListAvailable Microsoft.WinGet.Client)) { + Install-Module -Name Microsoft.WinGet.Client -Force -AllowClobber -Scope CurrentUser + } + "#; + + let _ = Command::new("powershell") + .args(["-NoProfile", "-Command", setup_script]) .creation_flags(0x08000000) .status(); - if winget_check.is_err() || !winget_check.unwrap().success() { - // 如果没有 winget,尝试安装 (这里简化处理,实际可能需要更复杂的脚本) - println!("Winget not found, attempting to install..."); - let _ = Command::new("powershell") - .args(["-Command", "Invoke-WebRequest -Uri https://github.com/microsoft/winget-cli/releases/latest/download/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -OutFile ./winget.msixbundle; Add-AppxPackage ./winget.msixbundle; Remove-Item ./winget.msixbundle"]) - .creation_flags(0x08000000) - .status(); - } - - // 2. 检查 Microsoft.WinGet.Client 模块 - let module_check = Command::new("powershell") - .args(["-Command", "Get-Module -ListAvailable Microsoft.WinGet.Client"]) - .creation_flags(0x08000000) - .output(); - - if let Ok(out) = module_check { - if out.stdout.is_empty() { - println!("Microsoft.WinGet.Client module not found, installing..."); - let install_res = Command::new("powershell") - .args(["-Command", "Install-Module -Name Microsoft.WinGet.Client -Force -AllowClobber -Scope CurrentUser -ErrorAction SilentlyContinue"]) - .creation_flags(0x08000000) - .status(); - - if install_res.is_err() || !install_res.unwrap().success() { - return Err("Failed to install Microsoft.WinGet.Client module".to_string()); - } - } - } - Ok(()) } pub fn list_all_software() -> Vec { - // 使用 PowerShell 获取结构化 JSON - let output = Command::new("powershell") - .args(["-Command", "Get-WinGetPackage | Select-Object Name, Id, InstalledVersion, IsUpdateAvailable, AvailableVersions | ConvertTo-Json"]) - .creation_flags(0x08000000) - .output(); + // 使用更健壮的脚本获取 JSON + let script = r#" + $OutputEncoding = [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 + $ErrorActionPreference = 'SilentlyContinue' + Import-Module Microsoft.WinGet.Client -ErrorAction SilentlyContinue + $pkgs = Get-WinGetPackage + if ($pkgs) { + $pkgs | ForEach-Object { + [PSCustomObject]@{ + Name = [string]$_.Name; + Id = [string]$_.Id; + InstalledVersion = [string]$_.InstalledVersion; + AvailableVersions = @() + } + } | ConvertTo-Json -Compress + } else { + "[]" + } + "#; - match output { - Ok(out) => parse_json_output(String::from_utf8_lossy(&out.stdout).to_string()), - Err(_) => vec![], - } + execute_powershell(script) } pub fn list_updates() -> Vec { - // 过滤出有更新的软件 + let script = r#" + $OutputEncoding = [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 + $ErrorActionPreference = 'SilentlyContinue' + Import-Module Microsoft.WinGet.Client -ErrorAction SilentlyContinue + $pkgs = Get-WinGetPackage | Where-Object { $_.IsUpdateAvailable } + if ($pkgs) { + $pkgs | ForEach-Object { + [PSCustomObject]@{ + Name = [string]$_.Name; + Id = [string]$_.Id; + InstalledVersion = [string]$_.InstalledVersion; + AvailableVersions = $_.AvailableVersions + } + } | ConvertTo-Json -Compress + } else { + "[]" + } + "#; + + execute_powershell(script) +} + +fn execute_powershell(script: &str) -> Vec { let output = Command::new("powershell") - .args(["-Command", "Get-WinGetPackage | Where-Object { $_.IsUpdateAvailable } | Select-Object Name, Id, InstalledVersion, IsUpdateAvailable, AvailableVersions | ConvertTo-Json"]) + .args(["-NoProfile", "-Command", script]) .creation_flags(0x08000000) .output(); match output { - Ok(out) => parse_json_output(String::from_utf8_lossy(&out.stdout).to_string()), + Ok(out) => { + let stdout = String::from_utf8_lossy(&out.stdout); + // 移除可能存在的 UTF-8 BOM + let clean_json = stdout.trim_start_matches('\u{feff}').trim(); + parse_json_output(clean_json.to_string()) + }, Err(_) => vec![], } } fn parse_json_output(json_str: String) -> Vec { - if json_str.trim().is_empty() { + if json_str.is_empty() || json_str == "[]" { return vec![]; } - // 处理单个对象或数组的情况 - let packages: Vec = if json_str.trim().starts_with('[') { - serde_json::from_str(&json_str).unwrap_or_default() - } else { - serde_json::from_str::(&json_str) - .map(|p| vec![p]) - .unwrap_or_default() - }; + // 尝试解析数组 + if let Ok(packages) = serde_json::from_str::>(&json_str) { + return packages.into_iter().map(map_package).collect(); + } - packages.into_iter().map(|p| Software { + // 尝试解析单个对象 + if let Ok(package) = serde_json::from_str::(&json_str) { + return vec![map_package(package)]; + } + + vec![] +} + +fn map_package(p: WingetPackage) -> Software { + Software { id: p.id, name: p.name, description: None, @@ -111,5 +133,5 @@ fn parse_json_output(json_str: String) -> Vec { icon_url: None, status: "idle".to_string(), progress: 0.0, - }).collect() + } }