Add Snap packaging - #32
Merged
Merged
Conversation
Strict-confinement Snap built with `snapcraft pack --use-lxd`. Uses the gnome extension for the Qt6 desktop runtime and reuses the .desktop entry and icon already produced for the AppImage. Plugs home and removable-media cover opening .npy/.npz files the user picks. Manual build only for now; auto-publish (Store name, CI upload, version single-sourcing via adopt-info) is a follow-up. Known limitation: double-click file association does not work — snapd does not register a snap's custom MIME types (application/x-npy/-npz) with the host, so the launcher cannot route .npy files in. Launch via the menu icon and use File > Open instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The launcher could not resolve the bundled icon because the reused AppImage
desktop entry references a themed icon name, which snapd does not map to an
in-snap icon. Switch to the native snap/gui/ convention: a snap-specific
npyquick.desktop with Icon=${SNAP}/meta/gui/npyquick.png (an absolute in-snap
path) and the icon copied to snap/gui/npyquick.png. snapd auto-detects these
from meta/gui, so the apps.desktop key and the dump part are no longer needed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LiukDiihMieu
commented
Jun 23, 2026
| # ${SNAP}/meta/gui/npyquick.png — an absolute in-snap path, which is what | ||
| # the launcher needs to resolve a bundled icon. | ||
| plugs: | ||
| # npyquick opens .npy files the user picks from anywhere on disk. |
Owner
Author
There was a problem hiding this comment.
comment not correct.
Suggested change
| # npyquick opens .npy files the user picks from anywhere on disk. | |
| # Allow opening user data from the home directory. | |
| # Files under /mnt, /media, or /run/media require the removable-media | |
| # interface to be connected manually. |
LiukDiihMieu
commented
Jun 23, 2026
Comment on lines
+35
to
+36
| # Qt6's xcb platform plugin hard-requires libxcb-cursor; it's a frequent | ||
| # "works in dev, blank window in the snap" gotcha. Revisit after a build. |
Owner
Author
There was a problem hiding this comment.
Suggested change
| # Qt6's xcb platform plugin hard-requires libxcb-cursor; it's a frequent | |
| # "works in dev, blank window in the snap" gotcha. Revisit after a build. | |
| # The gnome extension provides common desktop integration pieces | |
| # such as fonts, themes, icons, Wayland/X11, and related runtime setup. | |
| # PySide6/Qt itself still comes from the Python dependencies. |
Address review feedback: the home plug comment claimed files could be opened from "anywhere on disk", which is wrong under strict confinement — clarify it covers the home directory and that /mnt, /media, /run/media need the removable-media interface connected. Also reword the gnome extension comment: it provides desktop integration pieces (fonts, themes, icons, Wayland/X11), while PySide6/Qt itself comes from the Python dependencies. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Owner
Author
|
Uploaded to snapcraft and installed on another machine. ❯ npyquick
qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vkkhrdisplay, vnc, wayland-brcm, wayland-egl, wayland, xcb.
Aborted (core dumped)However, we already have Debug: snap run --shell npyquickand then in that shell $ QXCB="$(find "$SNAP" -name libqxcb.so | head -n 1)"
echo "$QXCB"
ldd "$QXCB" | grep "not found"
/snap/npyquick/1/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/libqxcb.so
libxkbcommon-x11.so.0 => not found
libxcb-icccm.so.4 => not found
libxcb-keysyms.so.1 => not found
libxcb-shape.so.0 => not found
libxcb-xkb.so.1 => not found
libxcb-icccm.so.4 => not found
libxcb-keysyms.so.1 => not found
libxcb-shape.so.0 => not found
libxcb-xkb.so.1 => not found
libxkbcommon-x11.so.0 => not found |
The snap ran on Wayland but crashed on X11 with "Could not load the Qt platform plugin xcb". Qt's message blames libxcb-cursor0, but that lib was already present and resolvable; `ldd` on libqxcb.so inside the snap showed the real gaps were libxkbcommon-x11, libxcb-icccm, libxcb-keysyms, libxcb-shape and libxcb-xkb — needed by libQt6XcbQpa and not supplied by the gnome platform. Add the corresponding packages to stage-packages. Verified on an X11 host: the window opens and ldd reports no missing libraries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the hand-written version/summary/description from snapcraft.yaml and adopt them via adopt-info + parse-info from the AppStream metainfo already maintained for the AppImage, so the two stay in one place. A new `metadata` part ships that file at usr/share/metainfo/ inside the snap. Keep the explicit icon (AppStream has no <icon>) and the contact/issues/source-code links (AppStream URLs are not adopted). Recompress the store/launcher icon from ~1 MB to ~13 KB to stay well under the store's 256 KB limit. Store listing note: `snapcraft upload` only bumps the revision; the public page's summary/description/icon are updated with `snapcraft upload-metadata <snap> --force`, while links and screenshots are dashboard-only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When running confined as a Snap, opening a file outside the sandbox's reach (strict confinement only grants the home folder and removable media) failed with a bare "No such file or directory", which is confusing — the file plainly exists and the pip/AppImage build opens it fine. The common trigger is a symlink in home pointing to another mount (e.g. ~/Lab -> /data on another drive): confinement resolves the symlink to its real path, which the home interface doesn't cover. load_file now detects this case ($SNAP set + the resolved path outside $SNAP_REAL_HOME and the removable-media roots) and shows a short explanation: move the file under home / use the pip or AppImage build, or — for external drives — connect the removable-media interface. The hint is gated on $SNAP so the pip and AppImage builds are unaffected. Covered by tests in test_app_workflow.py. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The hint previously fired for any failure on a path that resolved outside home/removable-media, which could mask the real error of a reachable file. Only return the hint when the path is genuinely unreachable from inside the Snap (os.path.exists is false); a visible-but-failing file keeps its real error. Also refine the wording: add sudo to the removable-media connect command (a normal user needs it), and say the package "can only access files in your home folder and connected removable-media locations" so it doesn't imply removable media is reachable without connecting the interface. Add tests for a home symlink that resolves onto another drive and for a visible external path not overriding the real error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve SNAP_REAL_HOME with realpath before the prefix check so a home directory that is itself a symlink (or on another mount) still matches. Shorten the out-of-reach message. Parametrize the removable-media test over the /media, /run/media and /mnt roots. Verified on a real Snap install: a file on another drive shows the hint, a corrupt file under home keeps its real error, home files open normally. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a Linux (Snap) install section after the AppImage one, a Snap Store version badge, and note the two ways the Snap differs from the AppImage/pip builds: sandboxed file access (home + connected removable media) and no double-click file association. Also picks up the AppImage filename fix (npyquick-<version>-x86_64.AppImage). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A manual Linux Snap section (built on an Ubuntu 22.04 host with LXD, not the tag CI): build, dangerous-install smoke test across views, menu icon, X11 and Wayland sessions, sandbox-hint check, edge upload, promotion to stable, and store metadata. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A separate snap.yml (workflow_dispatch + v* tags) builds the snap, smoke-tests it, and uploads to the Snap Store edge channel behind a manually-approved snap-store environment. Promotion edge -> stable stays manual. Also switches the snap base to core24. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Adds Snap packaging for npyquick, alongside the existing PyPI / AppImage / Windows artifacts: a recipe, store metadata, a sandbox-aware error message, and a gated CI workflow that publishes to the Snap Store's edge channel.
What's here
Recipe —
snap/snapcraft.yamlbase: core24, built with LXD (snapcraft pack --use-lxdlocally,canonical/action-buildin CI).gnomeextension for the Qt6 desktop runtime;home+removable-mediaplugs.stage-packagesfor the xcb/xkb libs Qt's X11 plugin needs, so it runs on X11, not just Wayland.adopt-info+parse-info) — one source, shared with the AppImage.Desktop integration —
snap/gui/Icon=${SNAP}/meta/gui/npyquick.png), so the launcher icon resolves.App —
src/npyquick/app.py$SNAP, so the pip and AppImage builds are unaffected. Covered by tests.CI —
.github/workflows/snap.ymlworkflow_dispatchor av*tag it builds + smoke-tests, then publishes to the edge channel behind a manually-approvedsnap-storeenvironment. Promotion edge → stable stays manual.Docs —
snap/README.md, a README install section + Snap Store badge, and a Snap section indocs/RELEASE_CHECKLIST.md.Store
The name
npyquickis registered and the snap is live on the edge channel (https://snapcraft.io/npyquick). Listing text/icon are pushed withsnapcraft upload-metadata; links and screenshots are set in the web dashboard.Verified (real installs)
--dangerousand from the store (--edge)..npy(image / table / cross-section / histogram) and.npz(key picker) views work.core24snap installs and runs on a 22.04 host.Known limitation
Double-click file association doesn't work:
.npy/.npzhave no MIME type registered on the host, and snapd doesn't register a snap's custom MIME types (not a confinement issue — classic has the same gap). Open via the menu icon, then drag-and-drop or File > Open. Upstreaming a.npytype to shared-mime-info would be the real fix (separate, long-horizon).Before merge
snap-storeenvironment +SNAPCRAFT_STORE_CREDENTIALSsecret, and dispatch the workflow once to verify end-to-end.snap install npyquickpoint there).🤖 Generated with Claude Code