mirror of
https://github.com/yusufipk/dikte.git
synced 2026-09-11 19:06:11 +00:00
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.
108 lines
4.5 KiB
RPMSpec
108 lines
4.5 KiB
RPMSpec
# PyInstaller's description of the build, shared by the AppImage and the disk
|
|
# image. Run it through build-appimage.sh or build-dmg.sh rather than by hand:
|
|
# each of those has a few steps of its own on either side of this.
|
|
#
|
|
# A directory rather than a single file, on both platforms. Onefile unpacks
|
|
# itself into /tmp on every start, which for something a global shortcut is
|
|
# meant to bring up is a second of nothing happening, and for the AppImage it
|
|
# would be an unpacking inside an unpacking. The single file people download is
|
|
# the AppImage and the .dmg; this only has to be tidy inside them.
|
|
|
|
import os
|
|
import pathlib
|
|
import re
|
|
import sys
|
|
|
|
ROOT = pathlib.Path(SPECPATH).parent # noqa: F821 (PyInstaller's)
|
|
|
|
# Read rather than imported. Putting the checkout on sys.path to import dikte
|
|
# would put this directory there under the name `packaging`, which is a real
|
|
# library that PyInstaller itself uses, and a spec file is no place to find out
|
|
# whether that matters.
|
|
__version__ = re.search(r'^__version__ = "(.*)"$',
|
|
(ROOT / "dikte" / "__init__.py").read_text(),
|
|
re.M).group(1)
|
|
|
|
MACOS = sys.platform == "darwin"
|
|
BUNDLE_ID = "io.github.yusufipk.dikte"
|
|
|
|
# PyQt6's wheel is most of the build, and most of the wheel is modules nothing
|
|
# here imports: Qt ships a browser engine, three declarative UI stacks and a
|
|
# 3D renderer. Naming them keeps the download to something a person on a slow
|
|
# connection will actually finish. Only the four in dikte's imports are left.
|
|
UNUSED_QT = [
|
|
"PyQt6." + name for name in (
|
|
"Qt3DAnimation", "Qt3DCore", "Qt3DExtras", "Qt3DInput", "Qt3DLogic",
|
|
"Qt3DRender", "QtBluetooth", "QtCharts", "QtDataVisualization",
|
|
"QtDesigner", "QtHelp", "QtLocation", "QtMultimedia",
|
|
"QtMultimediaWidgets", "QtNfc", "QtPdf", "QtPdfWidgets",
|
|
"QtPositioning", "QtQml", "QtQuick", "QtQuick3D", "QtQuickWidgets",
|
|
"QtRemoteObjects", "QtSensors", "QtSerialPort", "QtSpatialAudio",
|
|
"QtSql", "QtTest", "QtTextToSpeech", "QtWebChannel", "QtWebEngineCore",
|
|
"QtWebEngineQuick", "QtWebEngineWidgets", "QtWebSockets",
|
|
)
|
|
]
|
|
|
|
analysis = Analysis( # noqa: F821
|
|
[str(ROOT / "packaging" / "entry.py")],
|
|
pathex=[str(ROOT)],
|
|
hiddenimports=["PyQt6.QtNetwork"],
|
|
# tkinter is the other GUI toolkit CPython ships and would be dead weight;
|
|
# dikte's own tests have no business in a build at all.
|
|
excludes=UNUSED_QT + ["tkinter", "tests"],
|
|
noarchive=False,
|
|
)
|
|
|
|
archive = PYZ(analysis.pure) # noqa: F821
|
|
|
|
executable = EXE( # noqa: F821
|
|
archive,
|
|
analysis.scripts,
|
|
[],
|
|
exclude_binaries=True,
|
|
name="Dikte" if MACOS else "dikte",
|
|
console=False,
|
|
# Both platforms use whatever the machine is, because neither build is
|
|
# cross-compiled: the workflow runs one job per architecture.
|
|
target_arch=None,
|
|
# Ad-hoc, and only on a Mac, where an arm64 binary that carries no
|
|
# signature at all is refused by the kernel rather than merely warned
|
|
# about. build-dmg.sh signs the finished bundle over the top of this.
|
|
codesign_identity="-" if MACOS else None,
|
|
)
|
|
|
|
collection = COLLECT( # noqa: F821
|
|
executable,
|
|
analysis.binaries,
|
|
analysis.datas,
|
|
name="dikte",
|
|
)
|
|
|
|
if MACOS:
|
|
# LSUIElement is the line that makes this a menu bar application: no Dock
|
|
# icon, no menu of its own, nothing in the app switcher. The usage strings
|
|
# are not decoration either, they are what the permission dialogs read out,
|
|
# and a bundle that asks for the microphone without one is killed rather
|
|
# than asked about.
|
|
app = BUNDLE( # noqa: F821
|
|
collection,
|
|
name="Dikte.app",
|
|
icon=os.environ.get("DIKTE_ICNS") or None,
|
|
bundle_identifier=BUNDLE_ID,
|
|
version=__version__,
|
|
info_plist={
|
|
"CFBundleName": "Dikte",
|
|
"CFBundleDisplayName": "Dikte",
|
|
"CFBundleShortVersionString": __version__,
|
|
"CFBundleVersion": __version__,
|
|
"LSMinimumSystemVersion": "11.0",
|
|
"LSUIElement": True,
|
|
"NSHighResolutionCapable": True,
|
|
"NSMicrophoneUsageDescription":
|
|
"Dikte records what you dictate so that it can be transcribed.",
|
|
"NSAppleEventsUsageDescription":
|
|
"Dikte puts the transcript on the clipboard and pastes it into "
|
|
"the window you were typing in.",
|
|
},
|
|
)
|