Linux packaging (AppImage + deb) and self-update - #169
Merged
Merged
Conversation
fylorn
force-pushed
the
linux/packaging-update
branch
from
September 24, 2026 10:42
15fd0dc to
86db61a
Compare
- tauri.linux.conf.json: AppImage + deb targets, Linux icon sizes
(256/512 rendered by icons/render.py), category/publisher/homepage.
The bundler already writes the deb Depends (webkit2gtk-4.1, gtk3,
ayatana-appindicator) and the thinkwatch:// MimeType.
- linux/main.desktop: the bundler's template with `Exec=... %u` (without
a field code GLib appends %f, which drops non-file URLs, so sign-in
callbacks never reached the app) and a terminated MimeType list.
- fetch-core.sh: x86_64/aarch64-unknown-linux-gnu twcore assets, with an
ELF-specific architecture check.
- bundled_core(): on Linux, an installed build (bundle_type() is set by
the bundler's binary patch) only runs <exe>/../lib/<product>/twcore and
never falls through to the dev candidates. Derived from the executable,
not resource_dir(), which consults $APPDIR.
- update::kind(): Linux reads bundle_type(). AppImage (with $APPIMAGE) is
Standalone and is replaced in place by the updater plugin; a new
Install::Deb downloads + verifies via the plugin and installs with
`pkexec apt-get install -y` -- never the plugin's install(), which falls
back to asking for the password via zenity/kdialog and feeding sudo.
Failures say where to download; the gateway is resumed through the
shared resume_after_failed_update (now Windows + Linux).
- Update window: deb copy states that installing needs administrator
authorization.
- release.yml: Linux matrix (ubuntu-22.04 / ubuntu-22.04-arm) builds
AppImage + deb, renames the deb package from the bundler's
`think-watch-lite` to `thinkwatch-lite`, looks inside both (twcore
arch/version, bundle-type marker, glibc <= 2.35, desktop entry, deb
fields and Depends) and signs both.
- manifest.py: linux-{x86_64,aarch64}-{appimage,deb} keys, all required;
rejects a file with the wrong extension for a key.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fylorn
force-pushed
the
linux/packaging-update
branch
from
September 24, 2026 10:47
86db61a to
f74c15f
Compare
A deb build started from inside an AppImage (a terminal or launcher packaged that way) inherits that AppImage's APPIMAGE and APPDIR. Tauri's Env::default reads both without checking: restart() relaunches $APPIMAGE, resource_dir() falls back to $APPDIR, and twcore inherits them. Unless bundle_type() says this is an AppImage, remove both first thing in run(), while the process is still single-threaded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Sep 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linux distribution: AppImage + deb for x86_64 and aarch64, and self-update for both.
Packaging
src-tauri/tauri.linux.conf.json:appimage+debtargets; Linux icons 32/128/256/512 (256 and 512 newly rendered byicons/render.py; existing icons are byte-identical after re-rendering).Depends: libayatana-appindicator3-1, libwebkit2gtk-4.1-0, libgtk-3-0(tauri-cliinterface/rust.rs, from thetray-iconfeature) and thex-scheme-handler/thinkwatchMimeType from the deep-link config.dpkg-shlibdepson the built app + twcore lists only libraries those three pull in transitively.src-tauri/linux/main.desktop(debdesktopTemplate, also used for the AppImage): the bundler's default hasExec=thinkwatch-litewith no field code, so GLib appends%fand drops non-file URLs (gdesktopappinfo.cexpand_application_parameters/expand_macro 'f'). The template usesExec=thinkwatch-lite %uand terminates the MimeType list. Desktop file name staysThinkWatch Lite.desktop.think-watch-lite(kebab-case of the product name, no config key). release.yml repacks it asthinkwatch-litebefore signing (control file only; payload untouched)./usr/bin/xdg-mimewhen deep links are configured, so CI installsxdg-utils.fetch-core.sh: the two*-unknown-linux-gnutwcore assets. Core has not published them yet, so a Linuxtauri buildfails at the fetch step until the next core release includes them.Finding the bundled core
bundled_core()gets a Linux branch: whentauri::utils::platform::bundle_type()is set (the bundler binary-patches it per package type), the only candidate is<exe>/../lib/<productName>/twcore(deb:/usr/lib/ThinkWatch Lite/, AppImage: same path under the mount). Missing → the existing "bundle is missing twcore" error; no dev/env/PATH fallback. Derived from the executable rather thanresource_dir(), which falls back to$APPDIRfrom the environment.Self-update
update::kind()on Linux readsbundle_type(): AppImage (and$APPIMAGEset) →Standalone; deb → newInstall::Deb; anything else (cargo run, extracted AppImage, rpm) →Dev.$APPIMAGEin place;app.restart()relaunches$APPIMAGE(tauriprocess::current_binary). An unwritable location gets a specific message with the releases link.download()(verifies the signature before returning bytes), thenpkexec /usr/bin/apt-get install -y <file>from a fresh 0700 dir. The plugin'sinstall()is deliberately not used: it falls back to prompting for the password via zenity/kdialog and piping it tosudo. Core is stopped before installing; on failure (126 cancelled, 127 not authorized, apt error) the gateway is resumed via the sharedresume_after_failed_update(nowcfg(any(windows, linux))).Release pipeline
linuxmatrix job onubuntu-22.04/ubuntu-22.04-arm(label listed for public repos in GitHub's hosted-runner reference), so the glibc floor is 2.35.GLIBC_≤ 2.35, twcore--version,desktop-file-validate, MimeType and%u; deb Package/Version/Architecture/Depends.manifest.pyrequireslinux-{x86_64,aarch64}-{appimage,deb}(the plugin looks up<os>-<arch>-<installer>first) and rejects a file with the wrong extension for a key.Verified in an Ubuntu 22.04 aarch64 container
tauri build→ AppImage + deb; the "Name the packages" and "Look inside" steps extracted from this release.yml pass on them.apt-get installpulls nothing unexpected; twcore runs from/usr/lib/ThinkWatch Lite/twcore;gio open thinkwatch://…reaches the running instance with the URL in argv; WM_CLASS isthinkwatch-lite=StartupWMClass; with twcore removed the app logs the missing-bundle error and does not run atwcorefromTHINKWATCH_CORE_BINor PATH;apt-get removecleans up.latest.json: auto-check finds the update, the update window installs it, the plugin rewrites$APPIMAGE, core stops, the app relaunches from$APPIMAGEas the new version (new file hash, new PID,.updated-fromconsumed).Needs a
rehearse/**run before the next tag, after core publishes the Linux twcore assets.🤖 Generated with Claude Code