@@ -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