Simple App to help @jaspermayone make it through COMP1050 with a professor who won't use version control.
at main 153 lines 5.4 kB view raw view rendered
1# CLAUDE.md 2 3This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 4 5## Project Overview 6 7ZipMerge is a macOS SwiftUI application that compares a local project directory with a teacher's submitted zip file. It's designed to help students merge changes from assignments when version control isn't used by instructors. 8 9## Building and Running 10 11```bash 12# Build the project 13xcodebuild -project ZipMerge.xcodeproj -scheme ZipMerge build 14 15# Run the app (after building in Xcode) 16open ZipMerge.xcodeproj 17# Then press Cmd+R in Xcode to run 18``` 19 20The project uses Swift 5.0 and requires macOS with SwiftUI support. 21 22## Code Signing and Installation 23 24The project is configured with: 25- **Bundle Identifier**: com.singlefeather.ZipMerge 26- **Development Team**: M67B42LX8D 27- **Code Sign Style**: Automatic 28- **Code Sign Identity**: Currently ad-hoc (for local development) 29 30### Building for Local Development 31 32```bash 33# Build the project 34xcodebuild -project ZipMerge.xcodeproj -scheme ZipMerge -configuration Release clean build 35 36# The built app will be in: 37# ./build/Release/ZipMerge.app 38 39# Copy to Applications folder (optional) 40cp -r build/Release/ZipMerge.app /Applications/ 41``` 42 43### Release Process 44 45**Use the local release script for simplicity:** 46 47```bash 48./release.sh v1.0.0 49``` 50 51This automated script handles everything: 521. Builds with Developer ID signing 532. Notarizes with Apple 543. Creates GitHub release with signed .zip 554. Calculates SHA256 hash 565. Updates Homebrew cask automatically 576. Commits and pushes cask update 58 59**Prerequisites:** 60- `gh` CLI installed and authenticated 61- Developer ID Application certificate in Keychain 62- Apple ID app-specific password (prompted during script) 63 64The script is fully automated and requires no manual steps. See RELEASING.md for details. 65 66### Distributing via Homebrew 67 68The Homebrew cask is located at `/Users/jsp/dev/projects/homebrew-tap/Casks/zipmerge.rb`. 69 70After each release, update the SHA256 hash in the cask file with the value from the release notes. 71 72**Users can install via:** 73```bash 74brew tap jaspermayone/tap 75brew install --cask zipmerge 76``` 77 78### Manual Distribution (Without CI) 79 80If you need to build manually: 81 82```bash 83# Build with Developer ID signing 84xcodebuild -project ZipMerge.xcodeproj -scheme ZipMerge -configuration Release \ 85 CODE_SIGN_IDENTITY="Developer ID Application" clean build 86 87# Notarize 88xcrun notarytool submit build/Release/ZipMerge.app.zip \ 89 --apple-id your-email@example.com \ 90 --team-id M67B42LX8D \ 91 --password app-specific-password \ 92 --wait 93 94# Staple and package 95xcrun stapler staple build/Release/ZipMerge.app 96cd build/Release && zip -r ZipMerge.zip ZipMerge.app 97``` 98 99## Architecture 100 101### Core Components 102 103**Models.swift** - Defines the data model: 104- `FileChangeType`: Enum for tracking file states (added, modified, deleted, unchanged) 105- `MergeDecision`: User decision per file (keepMine, takeTheirs, pending) 106- `ComparedFile`: Represents a single file comparison with diff hunks 107- `DiffHunk` and `DiffLine`: Structures for granular diff display (not yet fully implemented) 108- `ComparisonResult`: Contains all compared files and directories 109 110**FileComparer.swift** - File operations and comparison logic: 111- `extractZip()`: Uses system `unzip` command to extract archives 112- `findRootDirectory()`: Handles zips with wrapper folders 113- `compare()`: Main comparison engine that walks both directory trees and categorizes changes 114- `applyChanges()`: Applies user merge decisions to the local directory 115- `computeHunks()`: Placeholder for future hunk-level merging (currently returns empty array) 116 117**ContentView.swift** - Main UI orchestration: 118- Left panel: Directory picker, zip drop zone, and file list 119- Right panel: Diff view for selected file 120- State management for comparison results and merge decisions 121- Git integration: Detects git repos and offers commit creation after merge 122- File cleanup: Removes temp directories and zip files after successful merge 123 124**DiffView.swift** - File diff visualization: 125- Side-by-side view for modified files 126- Single pane for added/deleted files with color-coded backgrounds 127- Line-by-line display with monospaced font 128 129### Data Flow 130 1311. User selects project directory and drops teacher's zip file 1322. `FileComparer.extractZip()` extracts to temp directory 1333. `FileComparer.compare()` walks both trees and generates `ComparisonResult` 1344. UI displays changed files with color-coded icons 1355. User reviews diffs and makes keepMine/takeTheirs decisions per file 1366. `FileComparer.applyChanges()` applies decisions 1377. If git repo detected, optionally creates commit 1388. Cleanup removes temp files and zip 139 140### Important Implementation Details 141 142- Zip extraction uses system `/usr/bin/unzip` command via Process 143- Comparison is byte-level for binaries, line-level diffs for text (when viewing) 144- Temp directories are created in system temp folder with UUID names 145- Git commits use `/usr/bin/git` directly (not libgit2 or similar) 146- All file operations happen on background queue, UI updates on main thread 147 148## Known Limitations 149 150- Hunk-level merging (`computeHunks()` and `applySelectedHunks()`) is stubbed but not implemented 151- Currently only supports whole-file merge decisions 152- No conflict resolution UI for line-level merging 153- Binary files show as "(binary or unreadable)" in diff view