From 31eadffce5d8b1338b8c05897f6ec640f05ce696 Mon Sep 17 00:00:00 2001 From: sami Date: Tue, 15 Sep 2026 18:02:11 +0400 Subject: [PATCH] pkg: build a local .deb; de-duplicate onto DAEMON's systemd/nativehost/man page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DAEMON landed packaging/nativehost/, packaging/systemd/{velox.service,velox.socket} (real sd_listen_fds() socket activation) and cli/man/velox.1 on main while this was in flight, duplicating paths this branch had drafted independently. Per CLAUDE.md (packaging/nativehost/ is DAEMON's; the rest of packaging/ is PKG/QA's), DAEMON's copies are kept as the single source and this branch's packaging/native-messaging/, packaging/man/velox.1 and stale packaging/systemd/velox.service are dropped rather than maintained twice. The root CMakeLists.txt's install() rules now point at DAEMON's paths directly, install both systemd units (not just velox.service), and docs/07-packaging.md / packaging/README.md no longer claim there's no socket activation — there is, and this package now ships it. Adds the local-test-only .deb itself: debian/{control,rules,postinst,postrm, changelog,copyright}, a placeholder icon set, the desktop entry and PKG/QA's own man pages (veloxd.8, velox-gui.1 — velox.1 stays DAEMON's). libveloxcore stays static (no consumer needs a .so yet); pairing has no real approval UI in this build (D1 unbuilt), so postinst and packaging/README.md both say VELOX_PAIR_AUTO=1 is required and print it prominently. No PPA, no GPG — local dpkg -i only. Verified live: dpkg-buildpackage -us -uc -b, dpkg -i, socket activation (systemctl --user enable --now velox.socket), `velox ls` against the running daemon, lintian clean, dpkg -r removes the manifest/units and leaves $XDG_DATA_HOME/velox alone. .gitignore now excludes dpkg-buildpackage's debhelper build tree and obj-*/ (the debuild output dir) — debian/control et al. stay tracked, everything debhelper regenerates does not. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0176u3fTrxegrGNm2yC7r69W --- .gitignore | 14 +++ CMakeLists.txt | 60 +++++++++++ debian/changelog | 11 ++ debian/control | 35 ++++++ debian/copyright | 26 +++++ debian/postinst | 92 ++++++++++++++++ debian/postrm | 34 ++++++ debian/rules | 28 +++++ debian/source/format | 1 + debian/velox.lintian-overrides | 10 ++ docs/07-packaging.md | 16 ++- packaging/README.md | 100 ++++++++++++++++++ packaging/debian/.gitkeep | 0 packaging/desktop/velox.desktop | 12 +++ .../icons/hicolor/128x128/apps/velox.png | Bin 0 -> 3858 bytes packaging/icons/hicolor/16x16/apps/velox.png | Bin 0 -> 562 bytes packaging/icons/hicolor/22x22/apps/velox.png | Bin 0 -> 804 bytes packaging/icons/hicolor/24x24/apps/velox.png | Bin 0 -> 900 bytes .../icons/hicolor/256x256/apps/velox.png | Bin 0 -> 1588 bytes packaging/icons/hicolor/32x32/apps/velox.png | Bin 0 -> 1160 bytes packaging/icons/hicolor/48x48/apps/velox.png | Bin 0 -> 1621 bytes packaging/icons/hicolor/64x64/apps/velox.png | Bin 0 -> 2199 bytes packaging/man/velox-gui.1 | 20 ++++ packaging/man/veloxd.8 | 35 ++++++ 24 files changed, 492 insertions(+), 2 deletions(-) create mode 100644 debian/changelog create mode 100644 debian/control create mode 100644 debian/copyright create mode 100755 debian/postinst create mode 100755 debian/postrm create mode 100755 debian/rules create mode 100644 debian/source/format create mode 100644 debian/velox.lintian-overrides delete mode 100644 packaging/debian/.gitkeep create mode 100644 packaging/desktop/velox.desktop create mode 100644 packaging/icons/hicolor/128x128/apps/velox.png create mode 100644 packaging/icons/hicolor/16x16/apps/velox.png create mode 100644 packaging/icons/hicolor/22x22/apps/velox.png create mode 100644 packaging/icons/hicolor/24x24/apps/velox.png create mode 100644 packaging/icons/hicolor/256x256/apps/velox.png create mode 100644 packaging/icons/hicolor/32x32/apps/velox.png create mode 100644 packaging/icons/hicolor/48x48/apps/velox.png create mode 100644 packaging/icons/hicolor/64x64/apps/velox.png create mode 100644 packaging/man/velox-gui.1 create mode 100644 packaging/man/veloxd.8 diff --git a/.gitignore b/.gitignore index 9701178..4b30235 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,17 @@ crash-* oom-* leak-* timeout-* + +# dpkg-buildpackage output — debhelper's build tree and the produced .deb/.changes, plus +# the classic out-of-tree autotools-style build dir some debhelper versions still create. +# debian/control, changelog, copyright, rules, postinst, postrm, source/format and +# *.lintian-overrides are real packaging source and stay tracked; everything below is +# regenerated by `dpkg-buildpackage` on every run. +debian/.debhelper/ +debian/velox/ +debian/files +debian/*.substvars +debian/*.debhelper.log +debian/*.debhelper +debian/debhelper-build-stamp +obj-*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index cf658d4..71bad5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,3 +105,63 @@ if(VELOX_BUILD_TESTS) endif() endforeach() endif() + +# --- Install rules (M6 packaging; docs/07-packaging.md; owned by PKG/QA) ------------ +# +# Guarded by `if(TARGET ...)`, not by editing each lane's own CMakeLists.txt: install() +# is a packaging concern, and reaching into daemon/CMakeLists.txt (DAEMON's), cli's build +# file (also DAEMON's) or gui/CMakeLists.txt (GUI's) to add it there would cross a lane +# boundary CLAUDE.md draws on purpose. Every target below is defined by its own lane; +# this only says where the packaged binary already built by that lane's rules goes. +# +# libveloxcore is intentionally absent here: it stays a static library linked into each +# binary (user decision, see docs/07-packaging.md) — there is no .so to install. +# +# CMAKE_INSTALL_LIBDIR is multiarch-adjusted (lib/x86_64-linux-gnu/) by GNUInstallDirs on +# Debian; systemd user units and the Mozilla native-messaging directory are NOT +# architecture-specific paths, so those two destinations are written literally +# (lib/systemd/user, lib/mozilla/...) rather than built from that variable. +include(GNUInstallDirs) + +if(TARGET veloxd) + install(TARGETS veloxd RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + install(FILES ${CMAKE_SOURCE_DIR}/packaging/man/veloxd.8 + DESTINATION ${CMAKE_INSTALL_MANDIR}/man8) + # velox.socket ships alongside velox.service: DAEMON wired real sd_listen_fds() + # socket activation (daemon/src/rpc/systemd_activation.cpp) — see + # packaging/systemd/README.md for the pair's own rationale. + install(FILES ${CMAKE_SOURCE_DIR}/packaging/systemd/velox.service + ${CMAKE_SOURCE_DIR}/packaging/systemd/velox.socket + DESTINATION lib/systemd/user) +endif() + +if(TARGET velox) + install(TARGETS velox RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + # DAEMON owns cli/ and its man page (CLAUDE.md); packaging only installs it. + install(FILES ${CMAKE_SOURCE_DIR}/cli/man/velox.1 + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) +endif() + +if(TARGET velox-gui) + install(TARGETS velox-gui RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + install(FILES ${CMAKE_SOURCE_DIR}/packaging/man/velox-gui.1 + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) + install(FILES ${CMAKE_SOURCE_DIR}/packaging/desktop/velox.desktop + DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) + foreach(iconsize 16 22 24 32 48 64 128 256) + install(FILES + ${CMAKE_SOURCE_DIR}/packaging/icons/hicolor/${iconsize}x${iconsize}/apps/velox.png + DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/${iconsize}x${iconsize}/apps) + endforeach() +endif() + +# nmhost and its manifest are DAEMON's (CLAUDE.md: nmhost/ and packaging/nativehost/). +# This lights up the moment DAEMON's target exists, the same way the add_subdirectory() +# guards above do — no coordinated edit needed when it lands. +if(TARGET velox-nmhost) + install(TARGETS velox-nmhost RUNTIME DESTINATION libexec/velox) + install(FILES ${CMAKE_SOURCE_DIR}/packaging/nativehost/com.velox.host.json + DESTINATION lib/mozilla/native-messaging-hosts) +else() + message(STATUS "velox: nmhost has not landed yet — native-messaging manifest not installed.") +endif() diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..5cc9f48 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,11 @@ +velox (0.1.0-1) UNRELEASED; urgency=medium + + * Local test build only. Not signed, not uploaded anywhere — see + packaging/README.md for what this package is and is not. + * libveloxcore is linked statically; no libveloxcore.so is shipped. + * Placeholder app icon (packaging/icons/) — replace before any real release. + * No real pairing-approval UI is built yet (needs libdbus-1-dev, not in this + build's Build-Depends): pairing requires VELOX_PAIR_AUTO=1. See + packaging/README.md and postinst's own notice. + + -- Velox Local Test Build Sat, 12 Sep 2026 22:30:43 +0400 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..7910135 --- /dev/null +++ b/debian/control @@ -0,0 +1,35 @@ +Source: velox +Section: net +Priority: optional +Maintainer: Velox Local Test Build +Build-Depends: debhelper-compat (= 13), + cmake (>= 3.28), + ninja-build, + pkg-config, + g++ (>= 13), + qt6-base-dev, + qt6-tools-dev, + qt6-tools-dev-tools, + qt6-svg-dev, + libcurl4-openssl-dev, + libssl-dev, + libsqlite3-dev, + nlohmann-json3-dev, + libsecret-1-dev +Standards-Version: 4.6.2 +Rules-Requires-Root: no + +Package: velox +Architecture: amd64 +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: IDM-class download manager for Linux (local test build) + Velox is a segmented, resumable download manager for Linux: a daemon + (veloxd) that does the transfer work, a Qt GUI, a CLI, and a Firefox + extension for capture. + . + This package ships veloxd, the velox CLI, the velox-gui Qt client and + velox-nmhost, the Firefox native-messaging host. + . + THIS IS A LOCAL TEST BUILD, not a release: it uses a placeholder app + icon and has no real pairing-approval UI (see /usr/share/doc/velox, or + packaging/README.md in the source tree, for both limitations). diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..e9f92d2 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,26 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: velox +Source: (no public upstream repository yet — local test build only) + +Files: * +Copyright: 2026, the Velox project +License: Unlicensed-TODO + +Files: debian/* +Copyright: 2026, the Velox project +License: Unlicensed-TODO + +License: Unlicensed-TODO + No license has been chosen for Velox's own source yet. This is a genuine, + open project decision — not something packaging can invent on its own — + and is tracked as a release blocker in packaging/README.md. `lintian` is + expected to flag this package over it (a package normally must declare a + real license); that is correct behaviour on lintian's part, not a bug in + this packaging, and stays that way until the project adopts one. + . + Nothing above changes the licenses of this package's dynamically-linked + runtime dependencies (Qt, libcurl, SQLite, OpenSSL, nlohmann-json, + libsecret and friends) — those remain under their own upstream licenses, + covered by their own packages' Depends, and are not redistributed by this + source package. See packaging/README.md's licence-audit note for what + that still needs before a real release. diff --git a/debian/postinst b/debian/postinst new file mode 100755 index 0000000..ffbb70f --- /dev/null +++ b/debian/postinst @@ -0,0 +1,92 @@ +#!/bin/sh +# postinst for velox (local test build). See packaging/README.md. +set -e + +NM_MANIFEST_SRC=/usr/lib/mozilla/native-messaging-hosts/com.velox.host.json +NM_MANIFEST_NAME=com.velox.host.json + +# Every real (human) user with a home directory — UID range matches Debian's own +# adduser default (login.defs UID_MIN=1000), not just "everyone in /home" (a service +# account can have a home dir too) and not root. +real_users() { + getent passwd | awk -F: '$3 >= 1000 && $3 < 60000 && $6 != "" {print $1":"$6}' +} + +# Per-user native-messaging manifest (ADR 0003 / docs/05 §4.A): needed for BOTH +# deb/tarball and snap Firefox — the system-wide manifest this package also installs at +# $NM_MANIFEST_SRC only covers deb/tarball Firefox, never snap. Runs unconditionally, +# not just when snap is detected: a per-user login.defs-based install can't assume every +# user runs the same Firefox flavour, and dropping a JSON file nobody reads is harmless. +install_per_user_manifests() { + [ -f "$NM_MANIFEST_SRC" ] || { + echo "velox: native-messaging host not built yet (nmhost lane not landed) —" \ + "skipping per-user manifest install." + return 0 + } + real_users | while IFS=: read -r user home; do + [ -d "$home" ] || continue + dest_dir="$home/.mozilla/native-messaging-hosts" + install -d -o "$user" -g "$user" -m 0755 "$dest_dir" 2>/dev/null || { + echo "velox: could not create $dest_dir for $user — skipping" >&2 + continue + } + cp "$NM_MANIFEST_SRC" "$dest_dir/$NM_MANIFEST_NAME" + chown "$user:$user" "$dest_dir/$NM_MANIFEST_NAME" + chmod 0644 "$dest_dir/$NM_MANIFEST_NAME" + done +} + +# docs/07-packaging.md: detect snap Firefox and say so — the extension pairs over +# loopback WebSocket there (ADR 0003), not native messaging from inside the sandbox. +note_snap_firefox() { + if command -v snap >/dev/null 2>&1 && snap list firefox >/dev/null 2>&1; then + cat <<'EOF' + +velox: Firefox is installed as a snap on this system. The extension will pair with + veloxd over the loopback WebSocket (ws://127.0.0.1:), not native + messaging — this is expected (see docs/adr/0003, ADR 0003) and needs no + action from you. +EOF + fi +} + +case "$1" in + configure) + install_per_user_manifests + note_snap_firefox + + cat <<'EOF' + +============================================================================ +velox: LOCAL TEST BUILD — read this before pairing the extension +============================================================================ +No real pairing-approval UI is built into this package yet (it needs +libdbus-1-dev, which this build's dependencies do not include). veloxd's +only pairing approver in this build auto-rejects every request UNLESS you +set VELOX_PAIR_AUTO=1 in its environment — there is no prompt to accept or +decline; it is all-or-nothing. Do not run this on a machine or account +where you would not want every pairing request accepted automatically. + + systemctl --user edit velox.service + # add, in the [Service] section: + # Environment=VELOX_PAIR_AUTO=1 + +debhelper's dh_installsystemduser marks velox.service and velox.socket enabled (the +pair together, via velox.service's Also=velox.socket) for your next login session +automatically. For your CURRENT session, start socket activation now yourself — a +root postinst has no live user session to reach: + + systemctl --user daemon-reload + systemctl --user enable --now velox.socket + +See packaging/README.md in the source tree for the rest of this build's +testing-only limitations (placeholder icon, no license chosen yet, no +libveloxcore.so — it is linked statically). +============================================================================ +EOF + ;; +esac + +#DEBHELPER# + +exit 0 diff --git a/debian/postrm b/debian/postrm new file mode 100755 index 0000000..5c5e371 --- /dev/null +++ b/debian/postrm @@ -0,0 +1,34 @@ +#!/bin/sh +# postrm for velox (local test build). See packaging/README.md. +set -e + +NM_MANIFEST_NAME=com.velox.host.json + +real_users() { + getent passwd | awk -F: '$3 >= 1000 && $3 < 60000 && $6 != "" {print $1":"$6}' +} + +# Undoes exactly what postinst's install_per_user_manifests() did — never anything +# beyond that file. In particular this never touches a user's Velox data +# ($XDG_DATA_HOME/velox, i.e. normally ~/.local/share/velox — the task database and +# any settings) on either `remove` or `purge`: per-user, root-owned deletion across +# every account on the system is exactly the kind of destructive multi-user operation +# that deserves its own careful design and testing, not a first cut bolted onto this +# local test package. Documented as a deliberate simplification in +# packaging/README.md, not a silent gap. +remove_per_user_manifests() { + real_users | while IFS=: read -r user home; do + f="$home/.mozilla/native-messaging-hosts/$NM_MANIFEST_NAME" + [ -e "$f" ] && rm -f "$f" + done +} + +case "$1" in + remove|purge) + remove_per_user_manifests + ;; +esac + +#DEBHELPER# + +exit 0 diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..eb2e3e0 --- /dev/null +++ b/debian/rules @@ -0,0 +1,28 @@ +#!/usr/bin/make -f +# Velox — local test .deb build. Not a release build (no signing, no LTO tuning beyond +# what the flags below ask for): see packaging/README.md. +# +# Explicit cmake flags rather than a CMakePresets.json preset: dh_auto_configure already +# sets its own CMAKE_INSTALL_PREFIX / build-dir conventions, which fighting a preset's own +# cache variables (build//, etc.) would only complicate. The flags mirror the +# `release` preset's intent (RelWithDebInfo, no tests) without inheriting its binaryDir. +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +%: + dh $@ + +override_dh_auto_configure: + dh_auto_configure -- \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DVELOX_BUILD_TESTS=OFF \ + -DVELOX_BUILD_GUI=ON \ + -DVELOX_WERROR=OFF + +# dh_installsystemd (system units) is disabled: velox.service/velox.socket are --user +# units, not system ones, so that helper has nothing to do here. dh_installsystemduser is +# NOT overridden — it runs normally, finds both units under lib/systemd/user/ in the +# install tree, and marks them enabled for each user's *next* systemd --user login (it +# cannot reach an already-running session from a root maintainer script at install time; +# postinst prints the manual start commands for the current session, matching +# packaging/README.md's own instructions). +override_dh_installsystemd: diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/debian/velox.lintian-overrides b/debian/velox.lintian-overrides new file mode 100644 index 0000000..13dd9c4 --- /dev/null +++ b/debian/velox.lintian-overrides @@ -0,0 +1,10 @@ +# initial-upload-closes-no-bugs: this is a local test build (packaging/README.md), +# never intended for the Debian/Ubuntu archive — there is no ITP bug to close. +initial-upload-closes-no-bugs + +# maintainer-script-calls-systemctl (postinst): both flagged lines are inside a +# heredoc of instructions printed for the *admin* to run themselves (velox.service is +# a --user unit; postinst has no live user session to invoke systemctl against +# itself). lintian's check is a text scan and can't tell printed advice from an actual +# invocation — verified by reading the built postinst, see packaging/README.md. +maintainer-script-calls-systemctl diff --git a/docs/07-packaging.md b/docs/07-packaging.md index 953842f..d04039c 100644 --- a/docs/07-packaging.md +++ b/docs/07-packaging.md @@ -9,16 +9,28 @@ Owner: lane **PKG/QA**. Target: Ubuntu 26.04 LTS. /usr/bin/velox-gui /usr/bin/velox # CLI /usr/libexec/velox/velox-nmhost # native messaging host -/usr/lib/x86_64-linux-gnu/libveloxcore.so.1 /usr/share/applications/velox.desktop /usr/share/icons/hicolor/*/apps/velox.png /usr/share/man/man1/velox.1.gz /usr/lib/systemd/user/velox.service -/usr/lib/systemd/user/velox.socket # socket activation +/usr/lib/systemd/user/velox.socket # real socket activation, see below /usr/lib/mozilla/native-messaging-hosts/com.velox.host.json /etc/xdg/autostart/velox-gui.desktop # optional, off by default ``` +`libveloxcore` is **static**, linked into `veloxd`, `velox` and `velox-gui` directly — +there is no `libveloxcore.so.*` to install. A shared, versioned `libveloxcore.so.1` was +the original plan here; the user decided against building one for now (no consumer needs +it as a shared object yet, and it would need CORE's `core/CMakeLists.txt` to grow a +`SOVERSION`). Revisit as a CORE-lane request if that changes — this doc was corrected in +the same commit as the decision rather than left describing something unshipped. + +`velox.service` and `velox.socket` are both DAEMON's (`packaging/systemd/README.md`, +`daemon/src/rpc/systemd_activation.cpp`) — real `sd_listen_fds()` socket activation, not a +plain `exec`. This package installs both units verbatim and lets `dh_installsystemduser` +(compat 13) pick them up from the install tree; see `packaging/README.md` for what that +does and does not do at install time for an already-running session. + `postinst` additionally drops per-user native-messaging manifests for the packaging formats that need them, and **detects whether Firefox is a snap** — if so it prints (and the GUI's first-run wizard shows) a one-line note that the extension will pair over loopback. diff --git a/packaging/README.md b/packaging/README.md index bb94fb5..f3b533f 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -1 +1,101 @@ Owner: lane PKG/QA. See ../docs/07-packaging.md. + +## `.deb` — local test build only + +There is no PPA, no GPG signing, no Launchpad wiring here. This produces a `.deb` you +install with `dpkg -i` on the box you built it on (or an identical one), for testing — +not something to hand to a user or publish anywhere. See `docs/07-packaging.md`'s +package matrix for the eventual PPA plan. + +```sh +sudo ./tools/bootstrap.sh --packaging # debhelper, dpkg-dev, lintian, devscripts, fakeroot +dpkg-buildpackage -us -uc -b # from the repo root; -b = binary only, no signing +sudo dpkg -i ../velox_0.1.0-1_amd64.deb +lintian ../velox_0.1.0-1_amd64.deb +``` + +Uninstall: `sudo dpkg -r velox` (or `sudo dpkg -P velox` to purge — see below for what +purge does and does not do here). + +### Known limitations of this build — read before relying on any of these + +- **`libveloxcore` is static, not `.so.1`.** The install layout in `docs/07-packaging.md` + originally called for a shared, versioned `libveloxcore.so.1`; the user decided against + building one for now (no consumer needs it as a shared object yet, and it would need a + `SOVERSION` added to CORE's own `core/CMakeLists.txt`). The doc was corrected in the + same commit as this packaging work — it no longer describes something unshipped. + +- **Placeholder app icon.** `gui/resources/icons/` (GUI's lane) is empty — no real icon + art exists anywhere in the repo yet. `packaging/icons/hicolor/*/apps/velox.png` is a + plain generated placeholder (flat color, a download-arrow glyph), good enough to + install correctly and pass `desktop-file-validate`/lintian's icon checks, and nothing + more. **Replace it before any real release** — and do the icon-set licence audit + `docs/07-packaging.md`'s release checklist asks for once real art exists (this + placeholder was drawn from scratch for this package, so it has no licence question of + its own, but it is not real Velox branding either). + +- **No license has been chosen for Velox's own source yet.** There is no top-level + `LICENSE` file in the repo. `debian/copyright` says so plainly (`License: + Unlicensed-TODO`) rather than inventing one — that is a real project decision, above + any one lane. Expect `lintian` to flag this package over it; that is lintian doing its + job, not a bug in this packaging, and it stays a known exception to "lintian clean" + until the project adopts a license. The release checklist's "Licence audit" item (Qt, + libcurl, SQLite, ffmpeg, icon set) is separate and still open regardless. + +- **Pairing has no real approval UI in this build.** `libdbus-1-dev` is not in this + build's `Build-Depends` (D1's GUI-dialog/desktop-notification approver needs it and + isn't wired up yet — `daemon/src/main.cpp` still uses `EnvAutoApprover` + unconditionally). That approver auto-**rejects** every pairing request unless + `VELOX_PAIR_AUTO=1` is set in `veloxd`'s environment — there is no prompt, no + accept/decline, it is all-or-nothing. `postinst` prints this prominently after + install; it is repeated here so it isn't missed by anyone reading only one of the two. + **Do not set `VELOX_PAIR_AUTO=1` on a machine or account where auto-accepting every + pairing request is unacceptable.** + +- **Socket activation is real.** `velox.service` and `velox.socket` both ship, verbatim + from DAEMON's `packaging/systemd/README.md` — `veloxd` receives the pre-bound fd via + `sd_listen_fds()` (`daemon/src/rpc/systemd_activation.cpp`) rather than binding its own + socket. `debian/rules` does **not** disable `dh_installsystemduser` (only the + system-level `dh_installsystemd`, since these are `--user` units); debhelper finds both + units under `lib/systemd/user/` in the install tree and enables the pair together + (`Also=velox.socket` in `velox.service`'s `[Install]`). + +- **The systemd `--user` service starts enabled for your *next* login, not this one.** + debhelper's `dh_installsystemduser` (verified in the built package's `postinst`) marks + `velox.service` enabled automatically — that takes effect the next time each user's + `systemd --user` instance starts. It cannot reach an *already-running* session from a + root maintainer script, so for the session you're in right now, `postinst` prints: + ```sh + systemctl --user daemon-reload + systemctl --user start velox.service + ``` + +- **`dpkg -P velox` (purge) does not delete user data.** The uninstall test this package + is built to pass is "manifests, units and sockets removed; user data untouched *unless + purged*" — this build is deliberately conservative and leaves `$XDG_DATA_HOME/velox` + (normally `~/.local/share/velox`, the task database) alone on **both** `remove` and + `purge`, for every account. A root maintainer script deleting per-user data across + every account on the system is exactly the kind of destructive, hard-to-test operation + that deserves its own design pass, not a first cut bolted on here. `postrm` only ever + undoes what `postinst` did: the per-user native-messaging manifest it copied in. + +### The uninstall test, concretely + +What `docs/07-packaging.md`'s release checklist asks for, and what this build actually +does: + +| Removed on `dpkg -r`/`-P`? | | +|---|---| +| `/usr/bin/{veloxd,velox,velox-gui}`, `/usr/libexec/velox/velox-nmhost` | yes — dpkg itself, ordinary package files | +| `/usr/lib/systemd/user/{velox.service,velox.socket}` | yes — same | +| `/usr/lib/mozilla/native-messaging-hosts/com.velox.host.json` | yes — same | +| Per-user `~/.mozilla/native-messaging-hosts/com.velox.host.json` | yes — `postrm`, both `remove` and `purge` | +| `$XDG_DATA_HOME/velox` (task DB, settings) | **no, on either `remove` or `purge`** — see above | + +### Native messaging + +`velox-nmhost` (DAEMON's `nmhost/`) and its manifest (DAEMON's +`packaging/nativehost/com.velox.host.json`) now ship in this package — the top-level +`CMakeLists.txt`'s install rules are guarded on `if(TARGET velox-nmhost)`, the same way its +`add_subdirectory()` calls are, so this lit up automatically the day that lane merged, no +packaging change needed on this end. diff --git a/packaging/debian/.gitkeep b/packaging/debian/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/packaging/desktop/velox.desktop b/packaging/desktop/velox.desktop new file mode 100644 index 0000000..5498f12 --- /dev/null +++ b/packaging/desktop/velox.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Type=Application +Version=1.0 +Name=Velox +GenericName=Download Manager +Comment=IDM-class download manager +Exec=velox-gui +Icon=velox +Terminal=false +Categories=Network;FileTransfer; +Keywords=download;downloader;idm;resume;segmented; +StartupNotify=true diff --git a/packaging/icons/hicolor/128x128/apps/velox.png b/packaging/icons/hicolor/128x128/apps/velox.png new file mode 100644 index 0000000000000000000000000000000000000000..028ad752101a1fb1245ccb66363058e2a08e271d GIT binary patch literal 3858 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 NCI%L$dOi1q{{b};5cmK9 literal 0 HcmV?d00001 diff --git a/packaging/icons/hicolor/16x16/apps/velox.png b/packaging/icons/hicolor/16x16/apps/velox.png new file mode 100644 index 0000000000000000000000000000000000000000..edc7ef729063ab03c0b02b736d6d7e9a33b76735 GIT binary patch literal 562 zcmV-20?qx2P)TC2>m7 z&97_q4FKV`CUfKInk`K(Ysi5!U+FAWds!4Q4uA6Jt!qx-wR6?&TedX0?AyB@`fgJA zI44OjEud&JI<=IOezX`}(BMOKmZbOIL{$)hgH}H=qF#$E1knW}Y64&e%T zCvX;m4rC!1!2~;0tPbiGVeGT+uBNTFo=eh4AQF|Y zRfP4G8q+mHwJfYZsxv!b$cALoN1zHN2U}@iD-D!K1ZN@L4}AOODUS^H#5w9$%EFV4 zL(=^~tF5fQJf!Sopi3ewV!Cz(vI1-pqdt3mM5QGBOg&RILzY8gddd({tAvF3%ou^O zYCIhqP59KvP~ggJ(v99aQGDD4RZT2N!&+x{_q2F;bJVZisp5TX-(D0xX7>F35l=Uc z!pzKwE83wU^AFTDeflc6sijL7bFN=@v8g))iMpKHzHH@u-*(ty=fi=?7Gu7T)m;7E zymxS{H};w*2G04;7_C>zVZ17vvh(A`=Qr1~zk#XIkcPw#n*aa+07*qoM6N<$g1m7C AH2?qr literal 0 HcmV?d00001 diff --git a/packaging/icons/hicolor/22x22/apps/velox.png b/packaging/icons/hicolor/22x22/apps/velox.png new file mode 100644 index 0000000000000000000000000000000000000000..7b24ba334e67e0252c9ca1ec1708e14a867c8e9c GIT binary patch literal 804 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 akM%cCK39F z1Ly3u*WTa%Tix;FKDPUqoK(w{nr>s#ab-#kN5umi{_X%)g zJ_^BfeNJ}p9%BO3N*!B#Ra|s={^_9w04CKkBW`m7tsBNCFAdv~gO7^vu$cTu#pFTy zEciyKq8i~{a{=T zp9-f&OwO3XFfLqv*SqF7uAJKU;#v|3ftJ}EdgR~tNnvmnks%+|B7p#rPBYt8sH&U0onA1xfxBF|9E+G+#)%WC6O$9g)Fli*J%4)7 z98-vyn8I>YeBj*oZE@@_7cNJ)p6~!-y$ij~mC9=MB!~hCsN8*Iq3qCkWAl5}MT)S? z9=juW#H#V`p1D&WnKK}&fxXw{%KOxXx4Q7Cs<(v^>nxuE5@FT(`;9GVR?$WPkwfPmY2!VVs-Fjy3F8^VD1P;F}WN&f>< znS<6#Gts^^uvk@o_|-wa@L&<=6LT^K-uPF{!#`ajpG!z)0D%^PERn9jP-(qRhD-g) zhkc3n&L>3Hu0Wibk*-Hy2&{`jWE_Py;Fga0+rftfZZ- z6jsMoK}pJsUePlF5vZ*w&O>0}{hAWRo%cBpOEo2*PY4J}#_kn85fFhWhEE;JQ63PC zK((RlA2aRoRK!Y2`0V|80=t@}FTEZ0Dt~VTj6h>W`S=|H$G%qXI-cTV`z*it!EpQc z^lX!JuZ4^Z3a$rJ>dA?nhoM2?**`aU<;@7yWJNYBHe;8}x%#f>_;ihdyma&pJ4Me? zNF*uNjz3=|c3W@UrH=mO?`kaE@D%gCm)1QK@E$4y!iBeDo_nc*HQl3&^NH~1-;9{~ zTa(eUWKyAKk_Vhiob==ib*{hfF|xj;Out4k9G|Wxj-63+mI(m`3ORUZ(R1Q#4UzSx z;al4O^}kn|mX0?LE)Q-`A;>dW$+6k!>j< z$>-Q~;?P1XX$d@ew#M}(Pa(UW7|58wI)^^jz_dz-^KV6*$$4@&NeXu zV-=I^P;94m)15`wgn;-DG^I2&cB?cuyFYe`Fh;iTxM|7#L19)&4*gnNi?+ViD@0%= zQu2XtTSd05p;Y7B6E3>0L`d4km21k~%R>LL-;Y&`c%OXdT&S)TgN5O?gg zZLMaBw8>ejdcOP2G8g9~N`)>7PZbdhYA?45m|*1}KJ+&*xe6NVT5Gii78}Y#6GiSF z588>TA5evnLCd#3U*hExOAHq2a0mh8qbg$kEP$Cjqjvu30}F_pwS^H;)vmF^wXXI{ zcvw}N+bmkCI+L#$jT?WTe`e1mrql#8ucM&i?BY?vr7sy<7*!uS5DQ5}sSF6yFEx1Z z?i}O$E!u}wP?8l`ta^U_$9iYRR#l8q^$xYU?|~?9XiJRNx$B)r-uYsXANhli>!^=o z5eZVwgb^T6E+$T#^+Kf2Y=%l0E5-b(6D#TjAsEa9J@gzx~U>3mawI8dGXE`+LjHfeMpqyN&!8Pszx} TI)Ti!00000NkvXXu0mjf>qHsW literal 0 HcmV?d00001 diff --git a/packaging/icons/hicolor/64x64/apps/velox.png b/packaging/icons/hicolor/64x64/apps/velox.png new file mode 100644 index 0000000000000000000000000000000000000000..05bb52cfa9673863b2a27c73f8c0e04b99db827a GIT binary patch literal 2199 zcmV;I2x#|-P)XoZqSnTQLlaoqm7@ zpI=Si*x1+=jq_@wSS)hZPje)h!UOI`;qk>!J3TcOe66Fc5noevg0pm0|Z75Y>i zYU|))kZVKsDJWnJVzP*du<^JRiC%PW;>T}4w(=hgs$n+@qBFaFP>Rw}!0=Xk>-N)I zOqhKl$n>qU^)b}h1VKa*G*Lh5>Iu&N@Wf+_A8Dn8O9g4n{DvLx z?=+d>KDAYxttBE7TzgYKKNM#LF=2kW*vi@8o_KueE=rej+B8!(gkQh?zjv5Sai2@d zR&CvhnDBZO9zZYwKskQZ2(Y%qU*Mg3}iEz*FaXNttny_ zw3S@@Pz7U6m=9e2;@3|;vGOm?3HJh){OZmI@}P}=~SK} z9H^cAQzQCcMkl$JDR+j~K)l7f;wA)4#FMm%jrMW%Emc*>vC05I{x09c20o z&RKiCuK9T(f-35axx0DG96f$f8()4!)gjmF7I#%3qOK}xlP|B^ra2DZZViXOX4h@g zoH{T6NZx*=k&K?r$?*UlnXa2~Em~DG5P{;{R=l;E`Hm-CY zL{kY5Rmf!;51#Snp_vBz!YvW6>{*J)v;|zODBt?YdCFC}hu^5P|HUdWo%EOw zs$i|>kT>5+*!TP-iwd1fk#%evv=l)*fh1Y5ndj;F}gwK_uqmEEwVR5hFz@Z99PR0a=IfYU6 z7I0xwd2ncgo}B5Z@Q{Kh*ktsdK3SehdbYC!r=CE6_1q-?Iqk@2I_m^M3JS0e`g??z z->UQUU#kSBwKL=zrhn|6geU$qNwFZQWQkLW1+0VKoZ+E^o)C?EPzg%IQl2VPt*7*g zjFc2GA0ehqd^3?+G}w+1yFq+2k!mjhP%OOoMzL!5E7>j5~@L`^Bj1ODw6_{;PV4Gb2 zZy523k`HA;A~@?p@CuMhT#GX~8AnXtLLXYLDut|1a&!~*#2>xs&C9|pK@hdEh2R1} zNNLEN86KD@-gD+nG1)b0YYu38RMr?T{HFC0zr3f96-9%P{^14%)Ip`LJo1M!`(Lcm z*CV(&EkRXGMqE-Ei;&|0;ikp6n4@4tIU*+7(kM1)3v2y3pGS7}aq~d;j}#XXezBvE zSO1l8{5?xPGiT=6Nsu+Tp%6%G3s80SFux*W ztD^@`KEC{}(vSwjTYcS7%c7}`_ng@m(=Oz@N~UwrQ0`&W&$s~Uy*BxqETHve7w zea-ijYwJXGWs;21rC_op!mt