Build an AppImage and a disk image, and publish them

Installing meant cloning the repository and running a shell script, which
is a fair ask of somebody who already has a terminal open and no ask at
all of anybody else. The releases page now carries an AppImage and a disk
image per Mac architecture: a push to master rebuilds a rolling "latest",
a v* tag publishes a version and leaves it there, and the Run button in
the Actions tab raises the number by running scripts/release.sh, which is
the same script and not a second copy of what it does.

Two things in the application had to give for that. A build has no
__main__.py on disk, and an AppImage is mounted somewhere new every run,
so the command a shortcut is registered with cannot go on being this
interpreter and this file; ipc.launcher() answers with the AppImage or
the bundle instead. And a build carries its own libstdc++, which every
process it starts inherits through LD_LIBRARY_PATH and none of them can
live with: ffmpeg, ydotool and wl-copy are the distribution's binaries
built against the distribution's libraries, and AppImageLauncher, which
is what starting the AppImage again goes through, refuses outright.
integrate.py puts that variable back before anything else runs.

Nothing installs itself over an installation that is already there.
install.sh's menu entry, install-mac.sh's login item and the desktop file
AppImageLauncher writes are each recognised and left alone, so trying a
download once does not quietly move the machine onto it. `dikte
integrate` is how you ask for it outright, and --remove takes it back.

The disk image carries an ffmpeg, pinned and checksummed, because macOS
records through one and ships nothing like it. It is signed ad-hoc and
not with an Apple certificate, so a first launch is refused until Open
Anyway and the permissions are asked for again after each update; both
READMEs and the release notes say so.
This commit is contained in:
2026-08-16 15:03:44 +03:00
parent 061dc5451b
commit 7e510f8b35
17 changed files with 1508 additions and 8 deletions
+14 -2
View File
@@ -24,6 +24,16 @@ newer, and PyQt6.
## Install
The [releases page](../../releases) has an AppImage and a disk image per Mac
architecture. Both write their own menu entry, login item and `dikte` command
the first time they run, and stand aside for an installation already on the
machine; `dikte integrate --remove` takes them back. The AppImage still wants
the system packages below, for the sound server, the clipboard and the
keyboard. The disk image is signed with no Apple certificate, so the first
launch is refused until you press **Open Anyway** under System Settings →
Privacy & Security, and macOS asks for the microphone and Accessibility again
after each update; installing from a checkout is what avoids that.
```sh
sudo pacman -S --needed pipewire-audio wl-clipboard ydotool ffmpeg python-pyqt6
systemctl --user enable --now ydotool # needed for auto-paste
@@ -204,8 +214,9 @@ keys.
Everything below is in the `dikte` package, which is what `python3 -m dikte`
runs and what the `__main__.py` in it hands to every launcher and shortcut.
`scripts/` holds install-mac.sh, update.sh and uninstall.sh; install.sh stays at
the top, and `tests/` has a file per module.
`scripts/` holds install-mac.sh, update.sh, uninstall.sh and release.sh;
`packaging/` builds the AppImage and the disk image that release.sh's tag
publishes; install.sh stays at the top, and `tests/` has a file per module.
```
app.py entry point, tray icon, state machine
@@ -226,6 +237,7 @@ settings_ui.py settings window
hotkey.py the desktop's shortcut registry, the evdev listener, Carbon on a Mac
paste.py wl-clipboard and ydotool wrappers, pbcopy and CoreGraphics
trayicon.py the tray icons, drawn where there is no icon theme
integrate.py what a downloaded build writes into the desktop it landed on
i18n.py the string table
```