Skip to content

Commit caea454

Browse files
marcelopepisclaude
andcommitted
release: v0.2.3 — serviços expandidos, CPU vendor tweaks, fTPM detection, Docker cleanup
- 11 serviços atualizados com nomes PT-BR e notas condicionais revisadas - 4 serviços Xbox com warnings críticos (campo warning na struct ServiceItem) - Filtragem de serviços por cpu_vendor (2 serviços Intel telemetria) - AMD Ryzen Power Plan tweak (hardware_filter: cpu_vendor=amd) - Intel Power Throttling Off tweak (hardware_filter: cpu_vendor=intel) - Intel Turbo Boost Agressivo tweak (hardware_filter: cpu_vendor=intel) - Detecção fTPM AMD no Dashboard com aviso de stuttering - Seção Docker na página de Limpeza (scan, preview, cleanup com opções) - TWEAK_HARDWARE_MAP atualizado com 3 novos tweaks vendor-specific - Bump de versão para 0.2.3 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2fe9ef2 commit caea454

19 files changed

+1400
-28
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "frameguard",
33
"private": true,
4-
"version": "0.2.2",
4+
"version": "0.2.3",
55
"license": "GPL-3.0-or-later",
66
"author": "Marcelo Pepis",
77
"repository": "https://github.com/marcelopepis/FrameGuard",

src-tauri/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "frameguard"
3-
version = "0.2.2"
3+
version = "0.2.3"
44
description = "Utilitário de manutenção e otimização Windows 11 para gamers"
55
authors = ["Marcelo Pepis"]
66
license = "GPL-3.0-or-later"

src-tauri/src/commands/cleanup.rs

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,3 +2103,171 @@ fn get_item_category(item_id: &str) -> &'static str {
21032103
_ => "Outros",
21042104
}
21052105
}
2106+
2107+
// ═══════════════════════════════════════════════════════════════════════════════
2108+
// Docker Cleanup
2109+
// ═══════════════════════════════════════════════════════════════════════════════
2110+
2111+
use crate::utils::command_runner::run_command;
2112+
2113+
/// Preview de limpeza Docker — tamanhos e contagens para exibição na UI.
2114+
#[derive(Debug, Clone, Serialize)]
2115+
pub struct DockerCleanupInfo {
2116+
pub stopped_containers: u32,
2117+
pub dangling_images: u32,
2118+
pub build_cache_size: String,
2119+
pub volumes_count: u32,
2120+
}
2121+
2122+
/// Opções de limpeza Docker — cada flag controla uma operação.
2123+
#[derive(Debug, Clone, Deserialize)]
2124+
#[serde(rename_all = "camelCase")]
2125+
pub struct DockerCleanupOptions {
2126+
pub clean_containers: bool,
2127+
pub clean_images: bool,
2128+
pub clean_build_cache: bool,
2129+
pub clean_volumes: bool,
2130+
}
2131+
2132+
/// Verifica se Docker está instalado e acessível.
2133+
#[tauri::command]
2134+
pub async fn check_docker_installed() -> Result<bool, String> {
2135+
tokio::task::spawn_blocking(|| {
2136+
// Tenta `where docker` primeiro (encontra no PATH)
2137+
let result = run_command("where", &["docker"]);
2138+
if let Ok(out) = result {
2139+
if out.success && !out.stdout.trim().is_empty() {
2140+
return Ok(true);
2141+
}
2142+
}
2143+
2144+
// Fallback: verifica caminho padrão de instalação
2145+
let default_path = r"C:\Program Files\Docker\Docker\resources\bin\docker.exe";
2146+
Ok(std::path::Path::new(default_path).exists())
2147+
})
2148+
.await
2149+
.map_err(|e| e.to_string())?
2150+
}
2151+
2152+
/// Analisa o uso de espaço do Docker e retorna preview para a UI.
2153+
#[tauri::command]
2154+
pub async fn get_docker_cleanup_preview() -> Result<DockerCleanupInfo, String> {
2155+
tokio::task::spawn_blocking(|| {
2156+
// Containers parados
2157+
let stopped = run_command(
2158+
"docker",
2159+
&["ps", "--filter", "status=exited", "--filter", "status=created", "-q"],
2160+
)
2161+
.map(|o| {
2162+
if o.success {
2163+
o.stdout.lines().filter(|l| !l.trim().is_empty()).count() as u32
2164+
} else {
2165+
0
2166+
}
2167+
})
2168+
.unwrap_or(0);
2169+
2170+
// Imagens dangling
2171+
let dangling = run_command("docker", &["images", "--filter", "dangling=true", "-q"])
2172+
.map(|o| {
2173+
if o.success {
2174+
o.stdout.lines().filter(|l| !l.trim().is_empty()).count() as u32
2175+
} else {
2176+
0
2177+
}
2178+
})
2179+
.unwrap_or(0);
2180+
2181+
// Volumes não utilizados
2182+
let volumes = run_command("docker", &["volume", "ls", "--filter", "dangling=true", "-q"])
2183+
.map(|o| {
2184+
if o.success {
2185+
o.stdout.lines().filter(|l| !l.trim().is_empty()).count() as u32
2186+
} else {
2187+
0
2188+
}
2189+
})
2190+
.unwrap_or(0);
2191+
2192+
// Build cache — parsear de `docker system df`
2193+
let build_cache_size = run_command("docker", &["system", "df", "--format", "{{.Type}}\t{{.Size}}"])
2194+
.map(|o| {
2195+
if !o.success {
2196+
return "Desconhecido".to_string();
2197+
}
2198+
for line in o.stdout.lines() {
2199+
let parts: Vec<&str> = line.split('\t').collect();
2200+
if parts.len() >= 2 && parts[0].to_lowercase().contains("build cache") {
2201+
return parts[1].trim().to_string();
2202+
}
2203+
}
2204+
"0B".to_string()
2205+
})
2206+
.unwrap_or_else(|_| "Desconhecido".to_string());
2207+
2208+
Ok(DockerCleanupInfo {
2209+
stopped_containers: stopped,
2210+
dangling_images: dangling,
2211+
build_cache_size,
2212+
volumes_count: volumes,
2213+
})
2214+
})
2215+
.await
2216+
.map_err(|e| e.to_string())?
2217+
}
2218+
2219+
/// Executa limpeza Docker com as opções selecionadas.
2220+
#[tauri::command]
2221+
pub async fn run_docker_cleanup(options: DockerCleanupOptions) -> Result<String, String> {
2222+
tokio::task::spawn_blocking(move || {
2223+
let mut summary = Vec::new();
2224+
2225+
if options.clean_containers {
2226+
match run_command("docker", &["container", "prune", "-f"]) {
2227+
Ok(out) if out.success => {
2228+
summary.push(format!("Containers: {}", out.stdout.trim()));
2229+
}
2230+
Ok(out) => summary.push(format!("Containers: erro — {}", out.stderr.trim())),
2231+
Err(e) => summary.push(format!("Containers: erro — {}", e)),
2232+
}
2233+
}
2234+
2235+
if options.clean_images {
2236+
match run_command("docker", &["image", "prune", "-f"]) {
2237+
Ok(out) if out.success => {
2238+
summary.push(format!("Imagens: {}", out.stdout.trim()));
2239+
}
2240+
Ok(out) => summary.push(format!("Imagens: erro — {}", out.stderr.trim())),
2241+
Err(e) => summary.push(format!("Imagens: erro — {}", e)),
2242+
}
2243+
}
2244+
2245+
if options.clean_build_cache {
2246+
match run_command("docker", &["builder", "prune", "-f"]) {
2247+
Ok(out) if out.success => {
2248+
summary.push(format!("Build cache: {}", out.stdout.trim()));
2249+
}
2250+
Ok(out) => summary.push(format!("Build cache: erro — {}", out.stderr.trim())),
2251+
Err(e) => summary.push(format!("Build cache: erro — {}", e)),
2252+
}
2253+
}
2254+
2255+
if options.clean_volumes {
2256+
match run_command("docker", &["volume", "prune", "-f"]) {
2257+
Ok(out) if out.success => {
2258+
summary.push(format!("Volumes: {}", out.stdout.trim()));
2259+
}
2260+
Ok(out) => summary.push(format!("Volumes: erro — {}", out.stderr.trim())),
2261+
Err(e) => summary.push(format!("Volumes: erro — {}", e)),
2262+
}
2263+
}
2264+
2265+
if summary.is_empty() {
2266+
return Ok("Nenhuma operação selecionada.".to_string());
2267+
}
2268+
2269+
Ok(summary.join("\n"))
2270+
})
2271+
.await
2272+
.map_err(|e| e.to_string())?
2273+
}

0 commit comments

Comments
 (0)