Skip to content
Merged
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
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
swift build # Debug build
swift build -c release # Release build
swift run MacDirStat # Run the app
./scripts/build-app.sh # Release build packaged as .build/MacDirStat.app (Info.plist, icon, ad-hoc signed)
open Package.swift # Open in Xcode
```

Expand Down
3 changes: 3 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ let package = Package(
.executableTarget(
name: "MacDirStat",
path: "Sources/MacDirStat",
resources: [
.copy("AppIcon.icns")
],
swiftSettings: [
.swiftLanguageMode(.v6)
]
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,20 @@ Requires macOS 15.0+ and Swift 6.

```bash
git clone https://github.com/phalladar/MacDirStat.git
cd macdirstat
cd MacDirStat
swift build -c release
swift run MacDirStat
```

To install it as a regular app in `/Applications`:

```bash
./scripts/build-app.sh
cp -R .build/MacDirStat.app /Applications/
```

To include protected folders (Mail, Messages, other apps' data) in scans, add MacDirStat under **System Settings → Privacy & Security → Full Disk Access**. The script signs the app ad hoc, so macOS treats each rebuild as a new app: after rebuilding, remove MacDirStat from that list and add it again.

Or open in Xcode:

```bash
Expand Down
22 changes: 22 additions & 0 deletions Sources/MacDirStat/App/MacDirStatApp.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
import SwiftUI

final class AppDelegate: NSObject, NSApplicationDelegate {
func applicationWillFinishLaunching(_ notification: Notification) {
NSApp.setActivationPolicy(.regular)
// Set before the Dock tile appears so it never flashes the generic executable icon.
if let icon = Self.appIcon() {
NSApp.applicationIconImage = icon
}
}

func applicationDidFinishLaunching(_ notification: Notification) {
NSApp.activate()
}

// Same lookup as SPM's Bundle.module, which calls fatalError when the resource bundle
// isn't beside the binary (e.g. the binary was copied elsewhere). A missing icon shouldn't crash.
private static func appIcon() -> NSImage? {
[Bundle.main.resourceURL, Bundle.main.bundleURL]
.lazy
.compactMap { $0.flatMap { Bundle(url: $0.appendingPathComponent("MacDirStat_MacDirStat.bundle")) } }
.first?
.image(forResource: "AppIcon")
}

func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
true
}
Expand Down
Binary file added Sources/MacDirStat/AppIcon.icns
Binary file not shown.
58 changes: 58 additions & 0 deletions scripts/build-app.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/bin/bash
# Builds a release MacDirStat.app (with Info.plist and icon) at .build/MacDirStat.app.
# Install with: cp -R .build/MacDirStat.app /Applications/
set -euo pipefail

VERSION="0.1.0"
BUNDLE_ID="io.github.phalladar.MacDirStat"

cd "$(dirname "$0")/.."
swift build -c release
BIN_DIR="$(swift build -c release --show-bin-path)"

APP=".build/MacDirStat.app"
rm -rf "$APP"
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources"

cp "$BIN_DIR/MacDirStat" "$APP/Contents/MacOS/"
cp Sources/MacDirStat/AppIcon.icns "$APP/Contents/Resources/"
# Bundle.module looks in Contents/Resources first, so keep SPM resources working inside the app.
cp -R "$BIN_DIR/MacDirStat_MacDirStat.bundle" "$APP/Contents/Resources/"

cat > "$APP/Contents/Info.plist" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>MacDirStat</string>
<key>CFBundleDisplayName</key>
<string>MacDirStat</string>
<key>CFBundleIdentifier</key>
<string>$BUNDLE_ID</string>
<key>CFBundleExecutable</key>
<string>MacDirStat</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$VERSION</string>
<key>CFBundleVersion</key>
<string>$VERSION</string>
<key>LSMinimumSystemVersion</key>
<string>15.0</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
EOF

# Ad-hoc sign so the bundle's resources are sealed and the signature is valid.
codesign --force --sign - "$APP"

echo "Built $APP"
Loading