Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# ClearDisk - Change Log

All notable changes to ClearDisk are documented here.

## [1.8.3] - Unreleased
### Changed
- Universal binary for Apple Silicon and Intel (`arm64` + `x86_64` via `lipo`)

## [1.8.2] - 2026-07-16
### Added
- Added signed app produced pipeline to avoid `xattr -cr ...` quirk
Expand All @@ -24,7 +29,7 @@ All notable changes to ClearDisk are documented here.
- The large-file scanner no longer looks inside media library packages (`.photoslibrary`, `.fcpbundle`, `.imovielibrary`, …), where deleting a single file corrupts the whole library.

### Changed
- The version is declared once, in `scripts/build_app.sh`, and read back from the bundle at runtime.
- The version is declared once, in `CHANGELOG.md`, baked into the bundle by `scripts/build_app.sh`, and read back at runtime.
- Project cache actions use the same trash icon as the Developer tab — they perform the same destructive action.

## [1.7.0] - 2026-03-18
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

**Your Mac is hiding 50–500 GB of developer caches. ClearDisk finds them in seconds.**

A free, open-source macOS menu bar app that monitors and cleans developer caches, Xcode, npm, Homebrew, Docker, pip, Cargo, Go, Gradle, and more. 590 KB. Zero dependencies. No data collection. No analytics. No network access. Ever.
A free, open-source macOS menu bar app that monitors and cleans developer caches, Xcode, npm, Homebrew, Docker, pip, Cargo, Go, Gradle, and more. ~6 MB universal binary. Zero dependencies. No data collection. No analytics. No network access. Ever.

![macOS 14+](https://img.shields.io/badge/macOS-14%2B-blue)
![Swift](https://img.shields.io/badge/Swift-5.9-orange)
![License: MIT](https://img.shields.io/badge/License-MIT-green)
![Size](https://img.shields.io/badge/Size-590%20KB-brightgreen)
![Size](https://img.shields.io/badge/Size-~6%20MB-brightgreen)
[![GitHub stars](https://img.shields.io/github/stars/bysiber/cleardisk?style=social)](https://github.com/bysiber/cleardisk/stargazers)
[![GitHub release](https://img.shields.io/github/v/release/bysiber/cleardisk)](https://github.com/bysiber/cleardisk/releases/latest)
[![Homebrew](https://img.shields.io/badge/Homebrew-tap-brown)](https://github.com/bysiber/homebrew-cleardisk)
Expand Down Expand Up @@ -109,7 +109,7 @@ That's it. Click the disk icon in your menu bar.

> **Why the Gatekeeper warning?** ClearDisk is not notarized with Apple ($99/yr Developer fee). The app is fully open-source -- you can verify every line of code yourself.

Requires macOS 14+ (Apple Silicon). Xcode Command Line Tools needed for building from source (`xcode-select --install`).
Requires macOS 14+ (Apple Silicon and Intel). Release builds are universal (`arm64` + `x86_64`). Xcode Command Line Tools needed for building from source (`xcode-select --install`).

## How It Works

Expand Down Expand Up @@ -193,7 +193,7 @@ CleanMyMac ($40/yr) is a general-purpose Mac cleaner. ClearDisk is free, open-so
<details>
<summary><strong>Does ClearDisk work on Intel Macs?</strong></summary>

Currently ClearDisk requires macOS 14+ (Sonoma) on Apple Silicon. Intel Mac support may be added in a future release.
Yes. ClearDisk requires macOS 14+ (Sonoma) and ships as a universal binary for both Apple Silicon and Intel Macs.
</details>

<details>
Expand Down
2 changes: 1 addition & 1 deletion Sources/ClearDisk/ClearDiskApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct ClearDiskApp {
}

/// The app's identity, read back from the bundle that `scripts/build_app.sh` generates.
/// The version is declared exactly once — in build_app.sh — so the UI can never disagree with the
/// The version is declared exactly once — in CHANGELOG.md — so the UI can never disagree with the
/// bundle. Running via `swift run` has no Info.plist, hence the "dev" fallback.
enum AppInfo {
static let version: String =
Expand Down
2 changes: 1 addition & 1 deletion docs/blog/mac-disk-cleaner-comparison.html
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ <h3>ClearDisk</h3>
<li>Detects 15+ developer cache types (Xcode, npm, Docker, pip, CocoaPods, Cargo, SPM, Homebrew, etc.)</li>
<li>Shows real-time sizes before you clean anything</li>
<li>Install via Homebrew: <code>brew tap bysiber/cleardisk && brew install --cask cleardisk</code></li>
<li>Lightweight (~590 KB)</li>
<li>Lightweight (~6 MB universal)</li>
</ul>

<p><strong class="cons">Cons:</strong></p>
Expand Down
4 changes: 2 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ <h3>Install via Homebrew</h3>

<section class="stats">
<div class="stat">
<div class="number">590 KB</div>
<div class="number">~6 MB</div>
<div class="label">App Size</div>
</div>
<div class="stat">
Expand Down Expand Up @@ -417,7 +417,7 @@ <h2>Why ClearDisk?</h2>
</tr>
<tr>
<td>App Size</td>
<td>590 KB</td>
<td>~6 MB</td>
<td>~100 MB</td>
<td>~25 MB</td>
<td>~5 MB</td>
Expand Down
68 changes: 60 additions & 8 deletions scripts/build_app.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,77 @@
#!/bin/bash
# Build ClearDisk.app bundle
set -e
# Build ClearDisk.app bundle (universal: arm64 + x86_64)
set -euo pipefail

source "$(cd "$(dirname "$0")" && pwd)/_release_lib.sh"

VERSION="$(project_version)"
BUILD_NUMBER="$(git -C "$ROOT_DIR" rev-list --count HEAD)"

# Architectures for the release binary. One DMG runs on Apple Silicon and Intel.
# Override for a faster host-only build: ARCHES=arm64 ./scripts/build_app.sh
ARCHES=(${ARCHES:-arm64 x86_64})

APP_BUNDLE="$ROOT_DIR/$APP_NAME.app"
MACOS_DIR="$APP_BUNDLE/Contents/MacOS"
BINARY_OUT="$MACOS_DIR/$APP_NAME"

triple_for_arch() {
printf '%s-apple-macosx' "$1"
}

binary_path_for_arch() {
local arch="$1"
printf '%s/.build/%s/release/%s' "$ROOT_DIR" "$(triple_for_arch "$arch")" "$APP_NAME"
}

assert_universal() {
local info
info="$(lipo -info "$BINARY_OUT")"
echo "$info"
echo "$info" | grep -q 'arm64' || {
echo "error: fat binary missing arm64 slice: $info" >&2
exit 1
}
echo "$info" | grep -q 'x86_64' || {
echo "error: fat binary missing x86_64 slice: $info" >&2
exit 1
}
}

echo "Building $APP_NAME..."
require_cmd swift
require_cmd lipo
require_cmd codesign
require_cmd file

echo "Building $APP_NAME (${ARCHES[*]})..."
cd "$ROOT_DIR"
swift build -c release 2>&1

BUILT_BINS=()
for arch in "${ARCHES[@]}"; do
triple="$(triple_for_arch "$arch")"
echo " -> swift build -c release --triple $triple"
swift build -c release --triple "$triple" 2>&1
bin="$(binary_path_for_arch "$arch")"
if [ ! -f "$bin" ]; then
echo "error: expected binary missing after $arch build: $bin" >&2
exit 1
fi
BUILT_BINS+=("$bin")
done

echo "Creating app bundle..."
rm -rf "$APP_BUNDLE"
mkdir -p "$APP_BUNDLE/Contents/MacOS"
mkdir -p "$MACOS_DIR"
mkdir -p "$APP_BUNDLE/Contents/Resources"

# Copy binary
cp ".build/release/$APP_NAME" "$APP_BUNDLE/Contents/MacOS/$APP_NAME"
if [ "${#BUILT_BINS[@]}" -eq 1 ]; then
cp "${BUILT_BINS[0]}" "$BINARY_OUT"
else
lipo -create "${BUILT_BINS[@]}" -output "$BINARY_OUT"
assert_universal
fi

file "$BINARY_OUT"

# Copy app icon
if [ -f "Resources/AppIcon.icns" ]; then
Expand Down Expand Up @@ -69,4 +121,4 @@ echo "Code signed (ad-hoc)."

echo "Done! App bundle created at: $APP_BUNDLE"
echo "To run: open $APP_BUNDLE"
ls -la "$APP_BUNDLE/Contents/MacOS/$APP_NAME"
ls -la "$BINARY_OUT"
16 changes: 12 additions & 4 deletions scripts/do_dmg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# Build the release .app and package it as dist/ClearDisk-v<version>.dmg
#
# Usage:
# ./scripts/do_dmg.sh # version comes from scripts/build_app.sh
# ./scripts/do_dmg.sh --version 1.8.0 # only to double-check; must match build_app.sh
# ./scripts/do_dmg.sh # version comes from CHANGELOG.md
# ./scripts/do_dmg.sh --version 1.8.3 # only to double-check; must match CHANGELOG.md
#
# Writes the DMG plus a <dmg>.sha256 sidecar that brew_update.sh picks up automatically.

Expand All @@ -27,16 +27,24 @@ DECLARED="$(project_version)"
if [ -z "$VERSION" ]; then
VERSION="$DECLARED"
elif [ "$VERSION" != "$DECLARED" ]; then
die "--version $VERSION does not match VERSION=\"$DECLARED\" in scripts/build_app.sh.
die "--version $VERSION does not match \"$DECLARED\" in CHANGELOG.md.
Bump it there — that file is the single source of truth."
fi

info "Building $APP_NAME $VERSION (release)"
"$SCRIPTS_DIR/build_app.sh" >/dev/null
# Keep build_app stdout visible — it asserts universal slices and prints lipo/file output.
"$SCRIPTS_DIR/build_app.sh"

APP="$ROOT_DIR/$APP_NAME.app"
[ -d "$APP" ] || die "$APP was not produced by build_app.sh"

BIN="$APP/Contents/MacOS/$APP_NAME"
[ -f "$BIN" ] || die "Missing executable: $BIN"
LIPO_INFO="$(lipo -info "$BIN" 2>/dev/null || true)"
echo "$LIPO_INFO" | grep -q 'arm64' || die "Release binary is not universal (missing arm64): $LIPO_INFO"
echo "$LIPO_INFO" | grep -q 'x86_64' || die "Release binary is not universal (missing x86_64): $LIPO_INFO"
ok "universal binary: $LIPO_INFO"

# The DMG filename is baked into the Homebrew cask URL, so a stale bundle would ship under the
# wrong name and every `brew install` would fetch the wrong build. Catch that here, not later.
BUILT="$(plutil -extract CFBundleShortVersionString raw "$APP/Contents/Info.plist")"
Expand Down