Skip to content

Add cross-platform comic file associations - #42

Closed
JoshCLWren wants to merge 1 commit into
mainfrom
feature/file-associations
Closed

Add cross-platform comic file associations#42
JoshCLWren wants to merge 1 commit into
mainfrom
feature/file-associations

Conversation

@JoshCLWren

Copy link
Copy Markdown
Owner

Summary

  • Add macOS .app packaging with CBZ/CBR Launch Services associations and the existing cdisplayagain icon.
  • Add Linux desktop/MIME installation for double-clicking CBZ/CBR files.
  • Make uv-managed Python/Tcl/Tk startup work reliably.
  • Fix packaged macOS launches exiting when the working directory is not writable by storing logs under the user log directory.

Validation

  • bash scripts/lint.sh
  • uv run pytest tests/test_main_functions.py --no-cov -q
  • make macos-install
  • Verified the installed bundle launches a CBZ from / and remains running.
  • Verified .cbz and .cbr default handlers with duti.

Full-suite note: the existing macOS Tk context-menu test has a _tkinter.TclError under uv's bundled Tk runtime; the startup regression and targeted tests pass.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@JoshCLWren, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a4ed55d3-4996-433a-a83b-71d27acba2f9

📥 Commits

Reviewing files that changed from the base of the PR and between 1b78d2f and 428b54e.

📒 Files selected for processing (9)
  • Makefile
  • README.md
  • cdisplayagain-macos.spec
  • cdisplayagain.py
  • packaging/linux/cdisplayagain.xml
  • pyproject.toml
  • tests/conftest.py
  • tests/test_main_functions.py
  • tk_bootstrap.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/file-associations

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

JoshCLWren added a commit that referenced this pull request Aug 8, 2026
Fold in the parts of the earlier file-associations branch that are better
than what this branch had.

tk_bootstrap.py replaces scripts/tk-env.sh. Setting TCL_LIBRARY and
TK_LIBRARY at import time fixes uv's python-build-standalone Tk for every
entry point, including plain "python cdisplayagain.py", pytest, and IDE
launches. The shell helper only reached commands routed through the
Makefile and needed an eval anywhere else.

Add packaging/linux/cdisplayagain.xml so install-desktop registers the
cbz/cbr MIME types with shared-mime-info instead of assuming the desktop
already knows them, and install the icon so the desktop entry can
reference it.

Pin uv to managed interpreters, matching the runtime tk_bootstrap targets.
@JoshCLWren

Copy link
Copy Markdown
Owner Author

Superseded by #54, which carries this work forward and is current against main (this branch had gone CONFLICTING).

#54 adopts the two pieces this branch did better: tk_bootstrap.py (import-time Tcl/Tk configuration, which fixes every entry point rather than just Makefile-routed commands) and packaging/linux/cdisplayagain.xml for shared-mime-info registration, plus [tool.uv] python-preference = "managed".

It differs on double-click delivery: instead of argv_emulation=True, it registers a ::tk::mac::OpenDocument Tk handler, which also handles a comic opened while the app is already running and is unit-testable. It also keeps a single spec with a sys.platform branch rather than a separate macOS spec, so the two build inputs cannot drift.

Nice catch on the relative logs/ startup crash here, incidentally: #54 hit and diagnosed the same bug independently.

@JoshCLWren JoshCLWren closed this Aug 8, 2026
JoshCLWren added a commit that referenced this pull request Aug 8, 2026
* Add macOS app bundle with double-click file associations

Package the viewer as cdisplayagain.app so Finder can open .cbz/.cbr on
double-click, matching the Linux desktop-entry workflow.

macOS delivers a double-clicked file through an openDocument Apple Event
rather than argv, so main() registers a ::tk::mac::OpenDocument handler and
waits briefly for it before falling back to the file dialog. The handler is
re-registered against the running viewer, so opening a second comic from
Finder loads it into the open window. All of this is guarded on darwin;
the Linux argv path is unchanged.

Fix two bugs this exposed:

- _init_logging created a relative "logs" directory. Finder launches apps
  with the working directory set to "/", so a packaged build died with
  "Errno 30: Read-only file system" before showing a window. A frozen build
  now logs under ~/Library/Logs on macOS and $XDG_STATE_HOME on Linux, and
  an unwritable log root degrades to console logging instead of aborting.
  CDISPLAYAGAIN_LOG_DIR still overrides everything, as the CI and
  compatibility scripts rely on it.
- A file:// argument was truncated to a single character by raw[7]
  instead of raw[7:].

The spec grows a BUNDLE step behind a sys.platform check, declaring
CFBundleDocumentTypes for cbz/cbr/cbt/cba at LSHandlerRank Owner plus
exported UTIs, and builds windowed so Finder does not open a Terminal
alongside the viewer. The Linux build path is untouched.

make install now builds first, so a stale dist/ cannot be installed, and
install-macos.sh removes prior installs before copying. With no explicit
MACOS_APPDIR it sweeps /Applications and ~/Applications; with one set it
stays scoped to that directory and leaves system default handlers alone.

scripts/tk-env.sh points Tk at the Tcl/Tk that uv's python-build-standalone
keeps outside the virtualenv, which otherwise breaks every Tk() call in a
source run on macOS.

* Adopt tk_bootstrap and Linux MIME package from #42

Fold in the parts of the earlier file-associations branch that are better
than what this branch had.

tk_bootstrap.py replaces scripts/tk-env.sh. Setting TCL_LIBRARY and
TK_LIBRARY at import time fixes uv's python-build-standalone Tk for every
entry point, including plain "python cdisplayagain.py", pytest, and IDE
launches. The shell helper only reached commands routed through the
Makefile and needed an eval anywhere else.

Add packaging/linux/cdisplayagain.xml so install-desktop registers the
cbz/cbr MIME types with shared-mime-info instead of assuming the desktop
already knows them, and install the icon so the desktop entry can
reference it.

Pin uv to managed interpreters, matching the runtime tk_bootstrap targets.

* Reject uv.lock resolved against a private index

A developer with UV_INDEX_URL or a pip.conf mirror set has every uv command
silently rewrite the registry of all 25 entries in uv.lock. Committing that
breaks CI and any clone that cannot reach the mirror, and nothing announces
the change, so it is easy to stage by accident.

The pre-commit hook now fails when a staged uv.lock references any registry
other than pypi.org, naming the offending URLs.

* Build and publish macOS release assets

Add a macOS job to the release workflow, on macos-14 for arm64 and macos-13
for Intel, so a tag produces downloadable app bundles alongside the Linux
archive. The job does not reuse the shared setup action: that action is
Linux-only and rebuilds pyvips from source, while macOS needs the
pyvips-binary wheel that carries libvips inside the bundle.

Two checks guard the regressions this platform actually hit. The bundle is
run from "/" to catch anything that assumes a writable working directory,
the way the relative log path did, and Info.plist is checked for its cbz and
cbr declarations so a spec change cannot silently drop file associations.

publish and attest now collect every artifact and regenerate SHA256SUMS
across the full published set.

scripts/update-cask.sh generates a Homebrew cask from a published release,
reading the checksums the workflow published so the cask cannot disagree
with the assets people download.

Drop --sequesterRsrc from the packaging step; it only added __MACOSX noise,
and the ad-hoc signature lives in the bundle rather than in xattrs.

* Document the Homebrew install path

Point macOS users at the tap first, and state plainly why the cask clears
the quarantine flag: the bundle is ad-hoc signed rather than notarized,
which needs a paid Apple Developer account.

* Write the classic PkgInfo marker into the app bundle

PyInstaller does not emit Contents/PkgInfo, and Finder falls back to a
generic icon for bundles without it even though Info.plist already carries
CFBundlePackageType. Verified the ad-hoc signature still passes
'codesign --verify --deep --strict' with the file present.

* Refresh Finder's icon cache during install

Finder caches an app icon against the bundle path and its modification
time, so installing over a previous copy kept showing the stale icon and
needed a manual lsregister plus killall Finder afterwards. The installer
now bumps the timestamp and relaunches Finder itself.

Both are skipped when MACOS_APPDIR points somewhere non-standard, matching
how default handlers are already left alone for scratch installs.

---------

Co-authored-by: Josh Wren <josh.wren@youversion.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant