Public/Clear-Junk.ps1
|
function Clear-Junk { <# .SYNOPSIS Find or remove ignored files in the active project folder. .DESCRIPTION Clear-Junk uses your project's `.gitignore` to identify files that are considered junk - build outputs, editor leftovers, temporary files, anything you have already declared as not worth saving. By default, Clear-Junk lists what would be removed but takes no action. Pass -Force to actually delete the listed files. Tracked files are never touched. Files that are untracked but not matched by `.gitignore` are not touched either; pass -Aggressive together with -Force to also remove those. Each invocation writes a self-contained diagnostic log file. Successful runs log silently; failures throw a plain-English message and point at the log file with the technical detail. .PARAMETER Force Actually remove the listed files. Without this switch, Clear-Junk only lists what it would remove. .PARAMETER Aggressive Together with -Force, also remove untracked files that are not matched by `.gitignore`. Without this, only ignored files are removed. .PARAMETER LogPath Override the directory where the diagnostic log for this run is written. .EXAMPLE Clear-Junk .EXAMPLE Clear-Junk -Force .EXAMPLE Find-CodeChange; Clear-Junk; Find-CodeChange .NOTES Safety: - Default is a list-only dry run; never deletes without -Force. - Tracked files are never touched. - Use Set-Vault -WriteIgnoreList if you want a starter .gitignore for a fresh project. - Refuses to run during an unfinished merge, rebase, cherry-pick, revert, or bisect. .LINK Find-CodeChange .LINK Set-Vault .LINK Save-Work .LINK Undo-Changes #> [CmdletBinding(SupportsShouldProcess)] [OutputType([PSCustomObject])] param( [Parameter()] [switch]$Force, [Parameter()] [switch]$Aggressive, [Parameter()] [string]$LogPath = '' ) $repoRoot = $null try { $rootProbe = Invoke-GEGit -ArgumentList @('rev-parse', '--show-toplevel') -AllowFailure if ($rootProbe.ExitCode -eq 0) { $repoRoot = $rootProbe.Output | Select-Object -First 1 } } catch { $repoRoot = $null } $session = Start-GELogSession -Command 'Clear-Junk' -Repository ([string]$repoRoot) -LogPath $LogPath $userMessageOnFailure = 'Could not scan for junk files.' try { Assert-GESafeSave -Path ([string]$repoRoot) -LogPath $session.Path | Out-Null if (-not $repoRoot) { $rootResult = Invoke-GEGit -ArgumentList @('rev-parse', '--show-toplevel') -LogPath $session.Path $repoRoot = $rootResult.Output | Select-Object -First 1 } $cleanFlags = if ($Aggressive) { '-fdx' } else { '-fdX' } $dryFlags = if ($Aggressive) { '-ndx' } else { '-ndX' } $dryResult = Invoke-GEGit -ArgumentList @('clean', $dryFlags) -WorkingDirectory $repoRoot -LogPath $session.Path $candidates = @($dryResult.Output | Where-Object { $_ -match '^Would remove\s+(.+)$' } | ForEach-Object { ($_ -replace '^Would remove\s+','').Trim() }) if ($candidates.Count -eq 0) { Write-Host 'No junk files found.' $result = [PSCustomObject]@{ Repository = $repoRoot Candidates = @() Removed = 0 Message = 'No junk files found.' } Complete-GELogSession -Path $session.Path -Outcome 'SUCCESS' return $result } if (-not $Force) { Write-Host "Found $($candidates.Count) junk file(s). Re-run with -Force to remove them:" foreach ($c in $candidates) { Write-Host " $c" } $result = [PSCustomObject]@{ Repository = $repoRoot Candidates = @($candidates) Removed = 0 Message = "$($candidates.Count) candidate(s) found. Pass -Force to remove." } Complete-GELogSession -Path $session.Path -Outcome 'SUCCESS' return $result } if (-not $PSCmdlet.ShouldProcess($repoRoot, "Remove $($candidates.Count) junk file(s)")) { Complete-GELogSession -Path $session.Path -Outcome 'SUCCESS' -UserMessage 'Skipped (WhatIf).' return } Invoke-GEGit -ArgumentList @('clean', $cleanFlags) -WorkingDirectory $repoRoot -LogPath $session.Path | Out-Null $verifyResult = Invoke-GEGit -ArgumentList @('clean', $dryFlags) -WorkingDirectory $repoRoot -LogPath $session.Path $remaining = @($verifyResult.Output | Where-Object { $_ -match '^Would remove\s+' }).Count $removed = $candidates.Count - $remaining Write-Host "Removed $removed junk file(s)." $result = [PSCustomObject]@{ Repository = $repoRoot Candidates = @($candidates) Removed = $removed Message = "Removed $removed junk file(s)." } Complete-GELogSession -Path $session.Path -Outcome 'SUCCESS' return $result } catch { $err = $_ $innerMessage = $err.Exception.Message if ($innerMessage -like 'git *') { $finalMsg = $userMessageOnFailure } else { $finalMsg = $innerMessage } Complete-GELogSession -Path $session.Path -Outcome 'FAILURE' -UserMessage $finalMsg -ErrorMessage $innerMessage throw "$finalMsg Details: $($session.Path)" } } |