diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index aa38925..2150638 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -2,96 +2,82 @@ name: Check on: push: - branches: [main] + branches: [windows] pull_request: + branches: [windows] permissions: contents: write jobs: format: - name: Format - runs-on: macos-latest + name: Format & Lint + runs-on: windows-latest steps: - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4 + uses: actions/checkout@v4 with: ref: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.head_ref) || github.ref }} token: ${{ secrets.GITHUB_TOKEN }} - - name: Cache Homebrew - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v4 - with: - path: | - ~/Library/Caches/Homebrew - /usr/local/Cellar/shfmt - /usr/local/Cellar/shellcheck - /usr/local/Cellar/golangci-lint - key: ${{ runner.os }}-brew-quality-v2-${{ hashFiles('**/Brewfile') }} - restore-keys: | - ${{ runner.os }}-brew-quality-v2- - - - name: Install tools - run: brew install shfmt shellcheck golangci-lint - - name: Set up Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v5 + uses: actions/setup-go@v5 with: go-version: '1.24.6' - - name: Install goimports - run: go install golang.org/x/tools/cmd/goimports@latest - - - name: Format all code + - name: Install Go tools run: | - export PATH=$(go env GOPATH)/bin:$PATH - ./scripts/check.sh --format + go install golang.org/x/tools/cmd/goimports@latest + go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + + - name: Format Go code + run: | + $env:PATH = "$(go env GOPATH)\bin;$env:PATH" + Get-ChildItem -Path cmd -Recurse -Filter "*.go" | ForEach-Object { + goimports -w $_.FullName + } + shell: pwsh + + - name: Run golangci-lint + run: | + $env:PATH = "$(go env GOPATH)\bin;$env:PATH" + cd cmd/analyze + golangci-lint run --timeout 5m + cd ../status + golangci-lint run --timeout 5m + shell: pwsh + continue-on-error: true + + - name: Check PowerShell syntax + run: | + $hasErrors = $false + $scripts = Get-ChildItem -Path . -Recurse -Include "*.ps1" -Exclude "*.Tests.ps1" + foreach ($script in $scripts) { + $errors = $null + $null = [System.Management.Automation.Language.Parser]::ParseFile($script.FullName, [ref]$null, [ref]$errors) + if ($errors.Count -gt 0) { + Write-Host "Syntax errors in $($script.Name):" -ForegroundColor Red + $errors | ForEach-Object { Write-Host " $_" } + $hasErrors = $true + } + } + if ($hasErrors) { exit 1 } + Write-Host "All PowerShell scripts have valid syntax" -ForegroundColor Green + shell: pwsh - name: Commit formatting changes if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} run: | - git config user.name "Tw93" - git config user.email "tw93@qq.com" - if [[ -n $(git status --porcelain) ]]; then + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + $changes = git status --porcelain + if ($changes) { git add . git commit -m "chore: auto format code" git push - echo "✓ Formatting changes committed" - else - echo "✓ No formatting changes needed" - fi - - quality: - name: Check - runs-on: macos-latest - needs: format - - steps: - - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4 - with: - ref: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.head_ref) || github.ref }} - - - name: Cache Homebrew - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v4 - with: - path: | - ~/Library/Caches/Homebrew - /usr/local/Cellar/shfmt - /usr/local/Cellar/shellcheck - /usr/local/Cellar/golangci-lint - key: ${{ runner.os }}-brew-quality-v2-${{ hashFiles('**/Brewfile') }} - restore-keys: | - ${{ runner.os }}-brew-quality-v2- - - - name: Install tools - run: brew install shfmt shellcheck golangci-lint - - - name: Set up Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v5 - with: - go-version: '1.24.6' - - - name: Run check script - run: ./scripts/check.sh --no-format + Write-Host "Formatting changes committed" + } else { + Write-Host "No formatting changes needed" + } + shell: pwsh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6569766..7daea2d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,127 +3,104 @@ name: Release on: push: tags: - - 'V*' + - 'W*' # Windows releases use W prefix (e.g., W1.0.0) permissions: contents: write jobs: build: - name: Build - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - - os: macos-latest - target: release-amd64 - artifact_name: binaries-amd64 - - os: macos-latest - target: release-arm64 - artifact_name: binaries-arm64 + name: Build Windows + runs-on: windows-latest steps: - name: Checkout code - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v5 + uses: actions/setup-go@v5 with: go-version: "1.24.6" - name: Build Binaries run: | - make ${{ matrix.target }} - ls -l bin/ + cd cmd/analyze + go build -ldflags="-s -w" -o analyze.exe . + cd ../status + go build -ldflags="-s -w" -o status.exe . + shell: pwsh - - name: Package binaries for Homebrew + - name: Create release package run: | - cd bin - # Package binaries into tar.gz for Homebrew resource - if [[ "${{ matrix.target }}" == "release-arm64" ]]; then - tar -czf binaries-darwin-arm64.tar.gz analyze-darwin-arm64 status-darwin-arm64 - ls -lh binaries-darwin-arm64.tar.gz - else - tar -czf binaries-darwin-amd64.tar.gz analyze-darwin-amd64 status-darwin-amd64 - ls -lh binaries-darwin-amd64.tar.gz - fi + # Create release directory + New-Item -ItemType Directory -Force -Path release + + # Copy binaries + Copy-Item cmd/analyze/analyze.exe release/ + Copy-Item cmd/status/status.exe release/ + + # Copy PowerShell scripts + Copy-Item mole.ps1 release/ + Copy-Item install.ps1 release/ + Copy-Item -Recurse bin release/ + Copy-Item -Recurse lib release/ + + # Copy docs + Copy-Item README.md release/ + Copy-Item LICENSE release/ + + # Create zip + Compress-Archive -Path release/* -DestinationPath mole-windows.zip + shell: pwsh - name: Upload artifacts - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@v4 with: - name: ${{ matrix.artifact_name }} - path: bin/*-darwin-* - retention-days: 1 + name: windows-release + path: mole-windows.zip + retention-days: 5 release: name: Publish Release needs: build runs-on: ubuntu-latest steps: - - name: Download all artifacts - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + - name: Download artifacts + uses: actions/download-artifact@v4 with: - path: bin - pattern: binaries-* - merge-multiple: true + name: windows-release - - name: Display structure of downloaded files - run: ls -R bin/ + - name: Display downloaded files + run: ls -la - name: Create Release - uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 + uses: softprops/action-gh-release@v2 if: startsWith(github.ref, 'refs/tags/') with: - files: bin/* + files: mole-windows.zip generate_release_notes: true draft: false prerelease: false - - update-formula: - runs-on: ubuntu-latest - needs: release - steps: - - name: Extract version from tag - id: tag_version - run: | - TAG=${GITHUB_REF#refs/tags/} - VERSION=${TAG#V} - echo "tag=$TAG" >> $GITHUB_OUTPUT - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Releasing version: $VERSION (tag: $TAG)" - - - name: Update Homebrew formula (Personal Tap) - uses: mislav/bump-homebrew-formula-action@56a283fa15557e9abaa4bdb63b8212abc68e655c # v3.6 - with: - formula-name: mole - formula-path: Formula/mole.rb - homebrew-tap: tw93/homebrew-tap - tag-name: ${{ steps.tag_version.outputs.tag }} - commit-message: | - mole ${{ steps.tag_version.outputs.version }} - - Automated release via GitHub Actions - env: - COMMITTER_TOKEN: ${{ secrets.PAT_TOKEN }} - - - name: Update Homebrew formula (Official Core) - uses: mislav/bump-homebrew-formula-action@56a283fa15557e9abaa4bdb63b8212abc68e655c # v3.6 - with: - formula-name: mole - homebrew-tap: Homebrew/homebrew-core - tag-name: ${{ steps.tag_version.outputs.tag }} - commit-message: | - mole ${{ steps.tag_version.outputs.version }} - - Automated release via GitHub Actions - env: - COMMITTER_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }} - continue-on-error: true - - - name: Verify formula updates - if: success() - run: | - echo "✓ Homebrew formulae updated successfully" - echo " Version: ${{ steps.tag_version.outputs.version }}" - echo " Tag: ${{ steps.tag_version.outputs.tag }}" - echo " Personal tap: tw93/homebrew-tap" - echo " Official core: Homebrew/homebrew-core (PR created)" + name: "Mole for Windows ${{ github.ref_name }}" + body: | + ## Mole for Windows + + Windows port of the Mole system maintenance toolkit. + + ### Installation + + **Quick install:** + ```powershell + irm https://raw.githubusercontent.com/tw93/Mole/windows/install.ps1 | iex + ``` + + **Manual install:** + 1. Download and extract `mole-windows.zip` + 2. Run `install.ps1` + + ### Features + - Deep system cleanup (temp files, caches, logs) + - Smart app uninstaller with leftover detection + - Disk space analyzer (TUI) + - System status monitor (TUI) + - Developer artifact cleanup + - System optimization diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eb5a23c..b0a940e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,87 +2,141 @@ name: Validation on: push: - branches: [main, dev] + branches: [windows] pull_request: - branches: [main, dev] + branches: [windows] jobs: tests: name: Unit & Integration Tests - runs-on: macos-latest + runs-on: windows-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4 - - - name: Install tools - run: brew install bats-core shellcheck + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v5 + uses: actions/setup-go@v5 with: go-version: "1.24.6" - - name: Run test script - env: - MOLE_PERF_BYTES_TO_HUMAN_LIMIT_MS: "6000" - MOLE_PERF_GET_FILE_SIZE_LIMIT_MS: "3000" - BATS_FORMATTER: tap - LANG: en_US.UTF-8 - LC_ALL: en_US.UTF-8 - run: ./scripts/test.sh - - compatibility: - name: macOS - strategy: - matrix: - os: [macos-14, macos-15] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4 - - - name: Test on ${{ matrix.os }} + - name: Install Pester run: | - echo "Testing on ${{ matrix.os }}..." - bash -n mole - source lib/core/common.sh - echo "✓ Successfully loaded on ${{ matrix.os }}" + Install-Module -Name Pester -Force -SkipPublisherCheck -Scope CurrentUser + shell: pwsh + + - name: Run PowerShell tests + run: | + Import-Module Pester + $config = New-PesterConfiguration + $config.Run.Path = "./tests" + $config.Output.Verbosity = "Detailed" + $config.Run.Exit = $true + Invoke-Pester -Configuration $config + shell: pwsh + + - name: Run Go tests + run: | + cd cmd/analyze + go test -v ./... + cd ../status + go test -v ./... + shell: pwsh + + build: + name: Build + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.24.6" + + - name: Build Go binaries + run: | + cd cmd/analyze + go build -o analyze.exe . + cd ../status + go build -o status.exe . + shell: pwsh + + - name: Verify binaries + run: | + if (Test-Path cmd/analyze/analyze.exe) { + Write-Host "analyze.exe built successfully" + } else { + Write-Host "Failed to build analyze.exe" + exit 1 + } + if (Test-Path cmd/status/status.exe) { + Write-Host "status.exe built successfully" + } else { + Write-Host "Failed to build status.exe" + exit 1 + } + shell: pwsh security: name: Security Checks - runs-on: macos-latest + runs-on: windows-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4 + - uses: actions/checkout@v4 - - name: Check for unsafe rm usage + - name: Load core modules run: | - echo "Checking for unsafe rm patterns..." - if grep -r "rm -rf" --include="*.sh" lib/ | grep -v "safe_remove\|validate_path\|# "; then - echo "✗ Unsafe rm -rf usage found" - exit 1 - fi - echo "✓ No unsafe rm usage found" + . ./lib/core/base.ps1 + . ./lib/core/file_ops.ps1 + Write-Host "Core modules loaded successfully" + shell: pwsh - - name: Verify app protection + - name: Verify protected paths run: | - echo "Verifying critical file protection..." - bash -c ' - source lib/core/common.sh - if should_protect_from_uninstall "com.apple.Safari"; then - echo "✓ Safari is protected" - else - echo "✗ Safari protection failed" - exit 1 - fi - ' + . ./lib/core/base.ps1 + . ./lib/core/file_ops.ps1 + + $protectedPaths = @( + "C:\Windows", + "C:\Windows\System32", + "C:\Program Files", + "C:\Program Files (x86)" + ) + + foreach ($path in $protectedPaths) { + if (-not (Test-ProtectedPath -Path $path)) { + Write-Host "FAIL: $path should be protected!" -ForegroundColor Red + exit 1 + } + Write-Host "OK: $path is protected" -ForegroundColor Green + } + shell: pwsh + + - name: Check for unsafe patterns + run: | + $hasIssues = $false + + # Check for raw Remove-Item without safety + $unsafePatterns = Get-ChildItem -Path lib,bin -Recurse -Filter "*.ps1" | + Select-String -Pattern "Remove-Item.*-Recurse.*-Force" | + Where-Object { $_.Line -notmatch "Remove-SafeItem|function Remove-" } + + if ($unsafePatterns) { + Write-Host "Warning: Potential unsafe Remove-Item usage found:" -ForegroundColor Yellow + $unsafePatterns | ForEach-Object { Write-Host " $($_.Filename):$($_.LineNumber)" } + } + + Write-Host "Security check completed" -ForegroundColor Green + shell: pwsh - name: Check for secrets run: | - echo "Checking for hardcoded secrets..." - matches=$(grep -r "password\|secret\|api_key" --include="*.sh" . \ - | grep -v "# \|test" \ - | grep -v -E "lib/core/sudo\.sh|lib/core/app_protection\.sh|lib/clean/user\.sh|lib/clean/brew\.sh|bin/optimize\.sh|lib/clean/apps\.sh" || true) - if [[ -n "$matches" ]]; then - echo "$matches" - echo "✗ Potential secrets found" - exit 1 - fi - echo "✓ No secrets found" + $matches = Get-ChildItem -Path . -Recurse -Filter "*.ps1" | + Select-String -Pattern "password|secret|api_key" -CaseSensitive:$false | + Where-Object { $_.Line -notmatch "^\s*#" } + + if ($matches) { + Write-Host "Review these lines for potential secrets:" -ForegroundColor Yellow + $matches | ForEach-Object { Write-Host " $($_.Filename):$($_.LineNumber): $($_.Line.Trim())" } + } + + Write-Host "Secret scan completed" -ForegroundColor Green + shell: pwsh diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml index 7934087..2b2c20a 100644 --- a/.github/workflows/update-contributors.yml +++ b/.github/workflows/update-contributors.yml @@ -2,7 +2,7 @@ name: Update Contributors on: push: - branches: [main, dev] + branches: [windows] workflow_dispatch: schedule: - cron: "0 0 * * 0" # Every Sunday at midnight UTC diff --git a/CONTRIBUTORS.svg b/CONTRIBUTORS.svg index a12b041..b92e4ba 100644 --- a/CONTRIBUTORS.svg +++ b/CONTRIBUTORS.svg @@ -1,4 +1,4 @@ - + @@ -113,93 +113,16 @@ - + - - - Schlauer-Hax + + + purofle - - - - - - - - MohammedEsafi - - - - - - - - - - - ndbroadbent - - - - - - - - - - - Sizk - - - - - - - - - - - thijsvanhal - - - - - - - - - - - yuzeguitarist - - - - - - - - - - - zeldrisho - - - - - - - - - - - bunizao - - - @@ -210,15 +133,92 @@ huyixi - + - + - - - purofle + + + bunizao + + + + + + + + + + + zeldrisho + + + + + + + + + + + yuzeguitarist + + + + + + + + + + + thijsvanhal + + + + + + + + + + + Sizk + + + + + + + + + + + ndbroadbent + + + + + + + + + + + MohammedEsafi + + + + + + + + + + + Schlauer-Hax @@ -310,17 +310,6 @@ - - - - - - - - biplavbarua - - - diff --git a/go.mod b/go.mod index 5cb9f41..683a2ab 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,33 @@ go 1.24.0 require ( github.com/charmbracelet/bubbletea v1.3.10 + github.com/charmbracelet/lipgloss v1.1.0 github.com/shirou/gopsutil/v3 v3.24.5 - github.com/yusufpapurcu/wmi v1.2.4 - golang.org/x/sys v0.36.0 +) + +require ( + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect + github.com/charmbracelet/x/ansi v0.10.1 // indirect + github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.16.0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.3.8 // indirect ) diff --git a/go.sum b/go.sum index 1fce446..234c561 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,21 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM= -github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg= -github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= -github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I= -github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= -github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= +github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= +github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= +github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= +github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= +github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -17,55 +25,51 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= -github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= -github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= -github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= -github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= -github.com/shoenig/go-m1cpu v0.1.7 h1:C76Yd0ObKR82W4vhfjZiCp0HxcSZ8Nqd84v+HZ0qyI0= -github.com/shoenig/go-m1cpu v0.1.7/go.mod h1:KkDOw6m3ZJQAPHbrzkZki4hnx+pDRR1Lo+ldA56wD5w= -github.com/shoenig/test v1.7.0 h1:eWcHtTXa6QLnBvm0jgEabMRN/uJ4DMV3M8xUGgRkZmk= -github.com/shoenig/test v1.7.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= +golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/lib/clean/dev.ps1 b/lib/clean/dev.ps1 index 5e85d5e..1aff033 100644 --- a/lib/clean/dev.ps1 +++ b/lib/clean/dev.ps1 @@ -412,6 +412,198 @@ function Clear-CloudCliCaches { } } +# ============================================================================ +# Elixir/Erlang Ecosystem +# ============================================================================ + +function Clear-ElixirCaches { + <# + .SYNOPSIS + Clean Elixir Mix and Hex caches + #> + + # Mix archives - skip auto-cleanup to preserve globally installed Mix tools + # NOTE: This directory contains globally installed Mix tools and tasks (e.g., phx_new, hex). + # Clearing it would remove user-installed tools requiring reinstallation. + $mixArchivesPath = "$env:USERPROFILE\.mix\archives" + if (Test-Path $mixArchivesPath) { + Write-Debug "Skipping Mix archives at '$mixArchivesPath' - contains globally installed tools" + } + + # Hex cache + $hexCachePath = "$env:USERPROFILE\.hex\cache" + if (Test-Path $hexCachePath) { + Clear-DirectoryContents -Path $hexCachePath -Description "Hex cache" + } + + # Hex packages - use age-based cleanup to preserve actively used packages + $hexPackagesPath = "$env:USERPROFILE\.hex\packages" + if (Test-Path $hexPackagesPath) { + $cutoffDate = (Get-Date).AddDays(-90) + $oldHexPackages = Get-ChildItem -Path $hexPackagesPath -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.LastWriteTime -lt $cutoffDate } + if ($oldHexPackages) { + foreach ($pkg in $oldHexPackages) { + Remove-SafeItem -Path $pkg.FullName -Description "Old Hex package ($($pkg.Name))" -Recurse + } + } + } +} + +# ============================================================================ +# Haskell Ecosystem +# ============================================================================ + +function Clear-HaskellCaches { + <# + .SYNOPSIS + Clean Haskell Cabal and Stack caches + #> + + # Cabal packages cache - use age-based cleanup to preserve recently used packages + $cabalPackagesPath = "$env:USERPROFILE\.cabal\packages" + if (Test-Path $cabalPackagesPath) { + $cutoffDate = (Get-Date).AddDays(-90) + $oldCacheItems = Get-ChildItem -Path $cabalPackagesPath -Recurse -File -ErrorAction SilentlyContinue | + Where-Object { $_.LastWriteTime -lt $cutoffDate } + if ($oldCacheItems) { + $paths = $oldCacheItems | ForEach-Object { $_.FullName } + Remove-SafeItems -Paths $paths -Description "Cabal old packages cache" + } + } + + # Cabal store + $cabalStorePath = "$env:USERPROFILE\.cabal\store" + if (Test-Path $cabalStorePath) { + # Only clean old/unused packages - be careful here + $oldDirs = Get-ChildItem -Path $cabalStorePath -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-90) } + if ($oldDirs) { + foreach ($dir in $oldDirs) { + Remove-SafeItem -Path $dir.FullName -Description "Cabal old store ($($dir.Name))" -Recurse + } + } + } + + # Stack programs cache - use age-based cleanup (contains GHC installations) + # These can be large and time-consuming to re-download + $stackProgramsPath = "$env:USERPROFILE\.stack\programs" + if (Test-Path $stackProgramsPath) { + $cutoffDate = (Get-Date).AddDays(-90) + $oldProgramDirs = Get-ChildItem -Path $stackProgramsPath -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.LastWriteTime -lt $cutoffDate } + if ($oldProgramDirs) { + foreach ($dir in $oldProgramDirs) { + Remove-SafeItem -Path $dir.FullName -Description "Stack old program ($($dir.Name))" -Recurse + } + } + } + + # Stack snapshots (be careful - these are needed for builds) + $stackSnapshotsPath = "$env:USERPROFILE\.stack\snapshots" + if (Test-Path $stackSnapshotsPath) { + # Only clean temp files + $tempFiles = Get-ChildItem -Path $stackSnapshotsPath -Recurse -Filter "*.tmp" -ErrorAction SilentlyContinue + if ($tempFiles) { + $paths = $tempFiles | ForEach-Object { $_.FullName } + Remove-SafeItems -Paths $paths -Description "Stack temp files" + } + } +} + +# ============================================================================ +# OCaml Ecosystem +# ============================================================================ + +function Clear-OCamlCaches { + <# + .SYNOPSIS + Clean OCaml Opam caches + #> + + # Opam download cache + $opamDownloadCache = "$env:USERPROFILE\.opam\download-cache" + if (Test-Path $opamDownloadCache) { + Clear-DirectoryContents -Path $opamDownloadCache -Description "Opam download cache" + } + + # Opam repo cache + $opamRepoCache = "$env:USERPROFILE\.opam\repo" + if (Test-Path $opamRepoCache) { + $cacheDirs = Get-ChildItem -Path $opamRepoCache -Directory -Filter "*cache*" -ErrorAction SilentlyContinue + foreach ($dir in $cacheDirs) { + Clear-DirectoryContents -Path $dir.FullName -Description "Opam repo cache" + } + } +} + +# ============================================================================ +# Editor Caches (VS Code, Zed, etc.) +# ============================================================================ + +function Clear-EditorCaches { + <# + .SYNOPSIS + Clean VS Code, Zed, and other editor caches + #> + + # VS Code cached data + # NOTE: workspaceStorage excluded - contains workspace-specific settings and extension data + $vscodeCachePaths = @( + "$env:APPDATA\Code\Cache" + "$env:APPDATA\Code\CachedData" + "$env:APPDATA\Code\CachedExtensions" + "$env:APPDATA\Code\CachedExtensionVSIXs" + "$env:APPDATA\Code\Code Cache" + "$env:APPDATA\Code\GPUCache" + "$env:LOCALAPPDATA\Microsoft\vscode-cpptools" + ) + foreach ($path in $vscodeCachePaths) { + if (Test-Path $path) { + Clear-DirectoryContents -Path $path -Description "VS Code cache" + } + } + + # VS Code Insiders + # NOTE: workspaceStorage excluded - contains workspace-specific settings and extension data + $vscodeInsidersCachePaths = @( + "$env:APPDATA\Code - Insiders\Cache" + "$env:APPDATA\Code - Insiders\CachedData" + "$env:APPDATA\Code - Insiders\CachedExtensions" + "$env:APPDATA\Code - Insiders\CachedExtensionVSIXs" + "$env:APPDATA\Code - Insiders\Code Cache" + "$env:APPDATA\Code - Insiders\GPUCache" + ) + foreach ($path in $vscodeInsidersCachePaths) { + if (Test-Path $path) { + Clear-DirectoryContents -Path $path -Description "VS Code Insiders cache" + } + } + + # Zed editor cache + $zedCachePaths = @( + "$env:LOCALAPPDATA\Zed\cache" + "$env:APPDATA\Zed\cache" + ) + foreach ($path in $zedCachePaths) { + if (Test-Path $path) { + Clear-DirectoryContents -Path $path -Description "Zed cache" + } + } + + # Sublime Text cache + $sublimeCachePath = "$env:APPDATA\Sublime Text\Cache" + if (Test-Path $sublimeCachePath) { + Clear-DirectoryContents -Path $sublimeCachePath -Description "Sublime Text cache" + } + + # Atom cache (legacy) + $atomCachePath = "$env:APPDATA\.atom\compile-cache" + if (Test-Path $atomCachePath) { + Clear-DirectoryContents -Path $atomCachePath -Description "Atom compile cache" + } +} + # ============================================================================ # IDE Caches # ============================================================================ @@ -516,13 +708,25 @@ function Invoke-DevToolsCleanup { # JVM ecosystem Clear-JvmCaches + # Elixir/Erlang ecosystem + Clear-ElixirCaches + + # Haskell ecosystem + Clear-HaskellCaches + + # OCaml ecosystem + Clear-OCamlCaches + # Containers Clear-DockerCaches # Cloud CLI tools Clear-CloudCliCaches - # IDEs + # Editor caches (VS Code, Zed, etc.) + Clear-EditorCaches + + # IDEs (JetBrains, Visual Studio) Clear-IdeCaches # Git