Skip to content

velopack#546

Open
azfoo wants to merge 13 commits into
TimeLineAnnotator:devfrom
azfoo:feat/velopack
Open

velopack#546
azfoo wants to merge 13 commits into
TimeLineAnnotator:devfrom
azfoo:feat/velopack

Conversation

@azfoo

@azfoo azfoo commented May 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Replaces the bare Nuitka standalone zip with Velopack-packaged installers: Setup.pkg (macOS Silicon + Intel), Setup.exe (Windows), AppImage (Linux), plus per-channel full/delta .nupkg packages for incremental updates.
  • Adds in-app update checking (background thread) with a dialog to download and restart, or pull from git on source installs. Accessible via Help → Check for Updates.
  • Wires Velopack lifecycle hooks at startup (tilia/lifecycle.py) for install/uninstall and OS file-association registration (.tla files).

Changes

scripts/deploy.py — removed sdist-based build path: previously the script created an sdist, extracted it to a temp lib directory, and built from there; now builds directly from the editable install, dropping the build package from the build dependency group. Added _build_velopack(): runs vpk pack after Nuitka, downloads the previous release nupkg for
delta generation, writes vpk-outdir and pack-version to GITHUB_OUTPUT; --noPortable on macOS/Windows only (not supported on Linux); strict semver validation; _patch_macos_plist() adds .tla associations and returns CFBundleExecutable; Nuitka entry point changed from tilia/__main__.py to tilia/ (package mode).

.github/workflows/build.yml — .NET 10 via brew on macOS (setup-dotnet fails on Intel runners); vpk CLI via dotnet tool; CI tests run the actual Setup installers instead of extracting zip archives; upload path filters by pack-version to exclude old nupkgs from delta generation; release check verifies one full.nupkg per channel rather than a fixed count; GH_TOKEN added to build env for gh release download.

tilia/lifecycle.py (new) — handles Velopack install/uninstall hooks and OS file-association wiring (Windows registry, macOS Info.plist, Linux MIME/desktop). Called from boot.py inside __compiled__ guard.

tilia/updates.py (new) — background thread polls for updates via Velopack on compiled builds or git fetch on source runs; posts APP_UPDATE_AVAILABLE with manager + info payload.

tilia/ui/dialogs/update.py (new) — update dialog dispatches to Velopack (download + restart) or git (pull + os.execv) path.

To verify

  1. Checkout commit <4cc369d> and run the app. A pop-up window should appear to prompt a pull of the branch updates. The app should restart and update to v0.0.2.
  2. Download the installer from this release and install. Similarly, a pop-up window should appear to prompt the download of the next version, and restart and update to v0.0.2. TiLiA should also appear as an "Open with..." option. Uninstalling should clean up all tilia files.

n.b. I have not tested on Linux and Mac.
failing tests should be fixed by #544

azfoo added 8 commits May 23, 2026 23:06
Replace the sdist-based build with a direct editable-install build.
Previously the script created an sdist and extracted it to a temp lib
directory; now deploy.py builds directly against the installed package,
passing the Nuitka package-config YAML as an absolute path.

Also fix macOS app bundle handling: read the binary name from
CFBundleExecutable (avoids assumptions about casing) and glob for the
.app bundle directory at zip time instead of hardcoding tilia.app.

Removes the "build" package from the build dependency group and the
now-unnecessary nuitka-package.config.yml entry from package-data
(which was only present for the sdist extraction path).
Without --repo the gh CLI falls back to the remote inferred from the
working directory, which may not be set in the deploy job environment.
Explicitly pass github.repository so the asset-count check always
targets the correct repository.
- lifecycle.py: platform.init() handles Velopack install/uninstall hooks
  and OS file-association wiring (Windows registry, macOS Info.plist,
  Linux MIME/desktop); guarded by __compiled__ in boot.py
- boot.py: call platform.init() before QApplication inside __compiled__ block
- updates.py: background thread checks Velopack (compiled builds) or
  git fetch (source runs); posts APP_UPDATE_AVAILABLE with manager+info
- dialogs/update.py: show_update_dialog() dispatches to Velopack
  (download + restart) or git (pull + os.execv) path
- qtui.py: listens on APP_UPDATE_AVAILABLE, marshals to main thread via
  QTimer.singleShot before showing dialog
- menus.py: "Check for Updates..." item in Help menu
- errors.py: VELOPACK_MANIFEST_NOT_FOUND, VELOPACK_UPDATE_FAILED, GIT_PULL_FAILED
- deploy.py: add _build_velopack() — runs vpk pack after Nuitka, downloads previous release nupkg for delta generation, writes vpk-outdir and pack-version to GITHUB_OUTPUT; --noPortable applied only for non-Linux (vpk on Linux does not support the flag); standalone mode per-platform (app on macOS, standalone on Windows/Linux); _semver_version() validates strict MAJOR.MINOR.PATCH (Velopack runtime requires exactly 3 parts; 4-part versions cause a semver parse error at install time); _patch_macos_plist() adds .tla file associations and returns CFBundleExecutable; Nuitka entry point changed from tilia/__main__.py to tilia/ (package mode)
- build.yml: installs .NET 10 via brew with continue-on-error (setup-dotnet fails on Intel macOS runners); installs vpk CLI via dotnet tool; test steps run Setup.pkg/Setup.exe installers; release asset check verifies one full.nupkg per channel rather than a fixed total count; GH_TOKEN added to build env for gh release download
- pyproject.toml: velopack in build group; remove onefile-tempdir-spec and mode="app" (now set per-platform in deploy.py)
Temporary — revert before merging to main:
- GIT_BRANCH: "main" -> "feat/velopack"
- Repository URL -> https://github.com/azfoo/TiLiA
- version: "0.6.2" -> "0.0.1"
Temporary — revert before merging to main:
- version: "0.6.2" -> "0.0.2"
@azfoo azfoo marked this pull request as ready for review May 25, 2026 22:31
@azfoo azfoo requested a review from FelipeDefensor May 25, 2026 22:31
@FelipeDefensor FelipeDefensor added this to the 0.7.0 milestone May 27, 2026
Compiled builds resolved version to 0.0.0 because Nuitka dropped the bundled distribution metadata. Two causes, both fixed: (1) find_namespace_packages swept a stray top-level htmlcov/ into tilia.egg-info top_level.txt, so Nuitka treated htmlcov as the metadata owner and skipped embedding -- constrained discovery with include = [tilia*]; (2) added --include-distribution-metadata so the embed uses reason 'user requested', which bypasses Nuitka's hasDoneModule gate and fails loudly instead of silently degrading.
Velopack Setup/Update pass --veloapp-install/-updated/-obsolete/-uninstall/-firstrun, not --velopack-*. The misspelled prefix meant the file-association hook never fired and .tla files were never registered on install. Fixed the prefix in the dispatch table and the _hook_mode gate.
Published releases were un-updatable: clients found the GitHub release but check_for_updates() returned None because no releases.<channel>.json was present. vpk pack emits releases.<channel>.json / assets.<channel>.json / RELEASES-<channel>, but the upload-artifact glob matched only *.nupkg / *-Setup.* / *.AppImage, dropping the manifests before the deploy job's release upload (files: build/velopack/**). Without releases.<channel>.json Velopack's GitHub source enumerates zero releases, so no update is ever offered. Add the manifest globs. (The Check output step stayed green because it validates only full.nupkg + user-downloads, not the update manifest.)
@FelipeDefensor

Copy link
Copy Markdown
Collaborator

Pushed 3 commits to this branch implementing the fixes below (bbd1012, 8bc7957, b3da5da):

Built + installed the Windows Velopack package locally and exercised the install, file-association, and update flows. Three defects:

1. Distribution metadata not embedded → app reports version 0.0.0, empty repo URL
setuptools find_namespace_packages pulled a stray top-level htmlcov/ (coverage output) into tilia.egg-info/top_level.txt. Nuitka then treated htmlcov as the owner of the TiLiA metadata and skipped embedding it, so importlib.metadata resolves nothing at runtime (version → 0.0.0, GITHUB_URL"").
Fix: include = ["tilia*"] under [tool.setuptools.packages.find], plus --include-distribution-metadata=TiLiA in deploy.py (reason "user requested" → Nuitka fails loudly instead of silently dropping the metadata).

2. .tla file associations never registered on install
The Velopack lifecycle hook matched --velopack-* argv flags, but Velopack passes --veloapp-*. The hook never fired, so no association keys were written.
Fix: correct the prefix to --veloapp-install/-updated/-obsolete/-uninstall/-firstrun in both the dispatch table and the _hook_mode gate.

3. Updates never offered — every published release is un-updatable (main issue)
"Check for Updates" always reports "up to date", even from an older install. The GitHub releases carry the nupkgs + Setup.exe but no releases.<channel>.json — the manifest Velopack's GitHub source needs to enumerate versions. Without it, check_for_updates() returns None.
vpk pack does emit releases.<channel>.json / assets.<channel>.json / RELEASES-<channel>, but the upload-artifact step in build.yml globs only *.nupkg / *-Setup.* / *.AppImage, dropping the manifests before the release upload (files: build/velopack/**).
Fix: add to the artifact path:

build/*/velopack/releases.*.json
build/*/velopack/assets.*.json
build/*/velopack/RELEASES-*

Also: the "Check output" step validates only *-full.nupkg + the 4 user-downloads, so CI went green while shipping broken releases — recommend asserting releases.<channel>.json per channel there too.

Verified the full path (detect → download → apply → restart) locally by packing a 0.0.3 release and pointing the updater at it; post-update sq.version = 0.0.3.

@FelipeDefensor

Copy link
Copy Markdown
Collaborator

The 0.0.1 release works on Mac with the same bugs it had on Windows. I imagine the last commits fix it. I will let a local build running and test tomorrow.

@FelipeDefensor

FelipeDefensor commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

@azfoo, could you fix CI too?

On macOS the locator was Windows-shaped (Update.exe, <root>/packages, wrong
root), so UpdateManager raised "not properly installed" and the Check for
Updates dialog showed the misleading "TiLiA is running from source" message.
Branch _make_locator by OS: use Contents/MacOS/UpdateMac and stage packages
under ~/Library/Caches, since the .pkg-installed bundle is read-only.

Also rework _run_check error handling. Previously a failed UpdateManager
construction was swallowed into "running from source", and a failed
check_for_updates masqueraded as "up to date". Split these into distinct,
surfaced messages (build / install / network), tighten the bare
`except Exception` to RuntimeError (everything Velopack raises), and add a
thread-boundary backstop so an unexpected error can never kill the daemon
thread silently.
Cover _make_locator OS-specific paths (UpdateMac vs Update.exe, the
Library/Caches packages dir, non-fatal mkdir on read-only homes) and
_run_check routing of every outcome: git fallback in dev, import/locator/
construct/network failures each producing their own surfaced message,
up-to-date posting, update-available, silent-check gating, and the
daemon-thread backstop. The velopack extension is a build-only dependency,
so it is faked to keep these runnable in the source test environment.

@FelipeDefensor FelipeDefensor left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Mac build worked, after applying the changes I commited. I wasn' t able to run it on Linux. Could you do that after you review my code?

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.

2 participants