CI: ship the tray GUI — in the archives and as tsunagi-gui deb/zst
Release / tsunagi-linux-aarch64 (push) Failing after 2m40s
Release / tsunagi-linux-x86_64 (push) Failing after 2m40s
Release / tsunagi-macos-aarch64 (push) Canceled after 0s
Release / tsunagi-windows-x86_64 (push) Canceled after 0s
Release / Publish release (push) Canceled after 0s
Release / tsunagi-linux-aarch64 (push) Failing after 2m40s
Release / tsunagi-linux-x86_64 (push) Failing after 2m40s
Release / tsunagi-macos-aarch64 (push) Canceled after 0s
Release / tsunagi-windows-x86_64 (push) Canceled after 0s
Release / Publish release (push) Canceled after 0s
Adds the tray application to the release: - Every target's archive now also contains the tsunagi-tray binary. On Linux it is built against an old glibc baseline (via cargo-zigbuild) rather than static musl, because a GUI must dlopen libGL/X11/Wayland at runtime and a static musl binary cannot; the agent stays static musl. macOS and Windows build the tray natively. - New GUI package variants for Linux: `tsunagi-gui` .deb and .pkg.tar.zst, built by the existing scripts with an extra tray argument. They install the agent (service, polkit, user — same as the headless packages) plus the tray binary, a desktop launcher (dist/linux/tsunagi-tray.desktop) and an icon (dist/linux/tsunagi.svg), so the GUI appears in the applications menu. The GUI package conflicts/replaces/provides the headless tsunagi so the two do not coexist. - The tray finds the system service with no configuration: the library's default control-socket path now prefers /run/tsunagi/agent.sock when present (both the tray and CLI use this), falling back to the per-user path. No control-protocol change. Builds, fmt and clippy clean on macOS; the Linux GUI cross-build and the packages are exercised only by a real CI run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
d13bb00623
commit
f63343a6a0
7 files changed
+194
-28
No files matched your search
@@ -36,6 +36,7 @@ jobs:
|
||||
deb: true
|
||||
deb_arch: amd64
|
||||
pkg_arch: x86_64
|
||||
gnu_target: x86_64-unknown-linux-gnu
|
||||
- os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-musl
|
||||
asset: tsunagi-linux-aarch64
|
||||
@@ -44,6 +45,7 @@ jobs:
|
||||
deb: true
|
||||
deb_arch: arm64
|
||||
pkg_arch: aarch64
|
||||
gnu_target: aarch64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
asset: tsunagi-macos-aarch64
|
||||
@@ -102,6 +104,22 @@ jobs:
|
||||
cargo build --release --locked --target "${{ matrix.target }}" --bin tsunagi
|
||||
fi
|
||||
|
||||
# The tray GUI. On Linux it is built against glibc (an old baseline for
|
||||
# portability), not musl: a GUI must dlopen libGL/X11/Wayland at runtime,
|
||||
# which a static musl binary cannot. macOS and Windows build it natively.
|
||||
- name: Build the tray GUI
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
export RUSTFLAGS="${RUSTFLAGS:-} -A linker_messages"
|
||||
if [[ "${{ runner.os }}" == "Linux" ]]; then
|
||||
rustup target add "${{ matrix.gnu_target }}"
|
||||
cargo zigbuild --release --locked \
|
||||
--target "${{ matrix.gnu_target }}.2.28" --bin tsunagi-tray
|
||||
else
|
||||
cargo build --release --locked --target "${{ matrix.target }}" --bin tsunagi-tray
|
||||
fi
|
||||
|
||||
- name: Package
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -115,6 +133,15 @@ jobs:
|
||||
[[ "${{ runner.os }}" == "Windows" ]] && bin="tsunagi.exe"
|
||||
cp "target/${{ matrix.target }}/release/${bin}" "$stage/"
|
||||
|
||||
# The tray GUI alongside it: glibc build on Linux, native elsewhere.
|
||||
tray="tsunagi-tray"
|
||||
[[ "${{ runner.os }}" == "Windows" ]] && tray="tsunagi-tray.exe"
|
||||
if [[ "${{ runner.os }}" == "Linux" ]]; then
|
||||
cp "target/${{ matrix.gnu_target }}/release/${tray}" "$stage/"
|
||||
else
|
||||
cp "target/${{ matrix.target }}/release/${tray}" "$stage/"
|
||||
fi
|
||||
|
||||
# The top-level README, plus the per-OS install notes and integration
|
||||
# files, so the archive carries what the platform needs to set up.
|
||||
cp README.md "$stage/"
|
||||
@@ -171,6 +198,25 @@ jobs:
|
||||
"$version" \
|
||||
"tsunagi-${pkgver}-1-${{ matrix.pkg_arch }}.pkg.tar.zst"
|
||||
|
||||
# The GUI variants: the same agent plus the tray binary and a desktop
|
||||
# launcher, named tsunagi-gui (conflicting with the headless packages).
|
||||
- name: Build the GUI packages
|
||||
if: matrix.deb
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
version="${GITHUB_REF_NAME#v}"
|
||||
pkgver="${version//-/_}"
|
||||
tray="target/${{ matrix.gnu_target }}/release/tsunagi-tray"
|
||||
bash dist/deb/build-deb.sh \
|
||||
"target/${{ matrix.target }}/release/tsunagi" \
|
||||
"${{ matrix.deb_arch }}" "$version" \
|
||||
"tsunagi-gui_${version}_${{ matrix.deb_arch }}.deb" "$tray"
|
||||
bash dist/arch/build-pkg.sh \
|
||||
"target/${{ matrix.target }}/release/tsunagi" \
|
||||
"${{ matrix.pkg_arch }}" "$version" \
|
||||
"tsunagi-gui-${pkgver}-1-${{ matrix.pkg_arch }}.pkg.tar.zst" "$tray"
|
||||
|
||||
# @v3 on purpose: Gitea does not support the v4 artifact backend. This is
|
||||
# what makes the archive (and the .deb, where built) show up under the run
|
||||
# and hands it to `publish`.
|
||||
|
||||
@@ -38,6 +38,7 @@ jobs:
|
||||
deb: true
|
||||
deb_arch: amd64
|
||||
pkg_arch: x86_64
|
||||
gnu_target: x86_64-unknown-linux-gnu
|
||||
- os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-musl
|
||||
asset: tsunagi-linux-aarch64
|
||||
@@ -46,6 +47,7 @@ jobs:
|
||||
deb: true
|
||||
deb_arch: arm64
|
||||
pkg_arch: aarch64
|
||||
gnu_target: aarch64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
asset: tsunagi-macos-aarch64
|
||||
@@ -104,6 +106,22 @@ jobs:
|
||||
cargo build --release --locked --target "${{ matrix.target }}" --bin tsunagi
|
||||
fi
|
||||
|
||||
# The tray GUI. On Linux it is built against glibc (an old baseline for
|
||||
# portability), not musl: a GUI must dlopen libGL/X11/Wayland at runtime,
|
||||
# which a static musl binary cannot. macOS and Windows build it natively.
|
||||
- name: Build the tray GUI
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
export RUSTFLAGS="${RUSTFLAGS:-} -A linker_messages"
|
||||
if [[ "${{ runner.os }}" == "Linux" ]]; then
|
||||
rustup target add "${{ matrix.gnu_target }}"
|
||||
cargo zigbuild --release --locked \
|
||||
--target "${{ matrix.gnu_target }}.2.28" --bin tsunagi-tray
|
||||
else
|
||||
cargo build --release --locked --target "${{ matrix.target }}" --bin tsunagi-tray
|
||||
fi
|
||||
|
||||
- name: Package
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -117,6 +135,15 @@ jobs:
|
||||
[[ "${{ runner.os }}" == "Windows" ]] && bin="tsunagi.exe"
|
||||
cp "target/${{ matrix.target }}/release/${bin}" "$stage/"
|
||||
|
||||
# The tray GUI alongside it: glibc build on Linux, native elsewhere.
|
||||
tray="tsunagi-tray"
|
||||
[[ "${{ runner.os }}" == "Windows" ]] && tray="tsunagi-tray.exe"
|
||||
if [[ "${{ runner.os }}" == "Linux" ]]; then
|
||||
cp "target/${{ matrix.gnu_target }}/release/${tray}" "$stage/"
|
||||
else
|
||||
cp "target/${{ matrix.target }}/release/${tray}" "$stage/"
|
||||
fi
|
||||
|
||||
# The top-level README, plus the per-OS install notes and integration
|
||||
# files, so the archive carries what the platform needs to set up.
|
||||
cp README.md "$stage/"
|
||||
@@ -173,6 +200,25 @@ jobs:
|
||||
"$version" \
|
||||
"tsunagi-${pkgver}-1-${{ matrix.pkg_arch }}.pkg.tar.zst"
|
||||
|
||||
# The GUI variants: the same agent plus the tray binary and a desktop
|
||||
# launcher, named tsunagi-gui (conflicting with the headless packages).
|
||||
- name: Build the GUI packages
|
||||
if: matrix.deb
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
version="${GITHUB_REF_NAME#v}"
|
||||
pkgver="${version//-/_}"
|
||||
tray="target/${{ matrix.gnu_target }}/release/tsunagi-tray"
|
||||
bash dist/deb/build-deb.sh \
|
||||
"target/${{ matrix.target }}/release/tsunagi" \
|
||||
"${{ matrix.deb_arch }}" "$version" \
|
||||
"tsunagi-gui_${version}_${{ matrix.deb_arch }}.deb" "$tray"
|
||||
bash dist/arch/build-pkg.sh \
|
||||
"target/${{ matrix.target }}/release/tsunagi" \
|
||||
"${{ matrix.pkg_arch }}" "$version" \
|
||||
"tsunagi-gui-${pkgver}-1-${{ matrix.pkg_arch }}.pkg.tar.zst" "$tray"
|
||||
|
||||
- name: Upload the build outputs as run artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
|
||||
@@ -148,10 +148,17 @@ pub fn default_control_socket_path() -> PathBuf {
|
||||
}
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
{
|
||||
// Prefer a running system service's socket when it is present, so a
|
||||
// GUI or CLI reaches the packaged daemon with no configuration; fall
|
||||
// back to the per-user location otherwise.
|
||||
let system = PathBuf::from("/run/tsunagi/agent.sock");
|
||||
if system.exists() {
|
||||
return system;
|
||||
}
|
||||
if let Ok(paths) = crate::config::StoragePaths::user_default() {
|
||||
control_socket_path(&paths.state_dir)
|
||||
} else {
|
||||
PathBuf::from("/run/tsunagi/agent.sock")
|
||||
system
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+34
-14
@@ -1,13 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Assemble an Arch Linux package (.pkg.tar.zst) from a prebuilt static tsunagi
|
||||
# binary, using only bsdtar + zstd on a non-Arch host — no makepkg, no Arch
|
||||
# container. The binary is static, so the package has no dependencies.
|
||||
# Assemble an Arch Linux package (.pkg.tar.zst) from prebuilt tsunagi binaries,
|
||||
# using only bsdtar + zstd on a non-Arch host — no makepkg, no Arch container.
|
||||
#
|
||||
# Usage: build-pkg.sh <binary> <arch> <version> <output.pkg.tar.zst>
|
||||
# <binary> path to the built tsunagi executable
|
||||
# <arch> pacman architecture: x86_64 or aarch64
|
||||
# <version> package version (the tag without its leading v)
|
||||
# <output> path to write the package to
|
||||
# Usage: build-pkg.sh <binary> <arch> <version> <output.pkg.tar.zst> [tray_binary]
|
||||
# <binary> path to the built tsunagi (agent/CLI) executable
|
||||
# <arch> pacman architecture: x86_64 or aarch64
|
||||
# <version> package version (the tag without its leading v)
|
||||
# <output> path to write the package to
|
||||
# [tray_binary] optional tsunagi-tray GUI executable; when given, the package
|
||||
# also installs the tray and a desktop launcher and is named
|
||||
# tsunagi-gui (conflicting with the headless tsunagi).
|
||||
#
|
||||
# Needs bsdtar (libarchive-tools) and zstd on the builder.
|
||||
set -euo pipefail
|
||||
@@ -16,6 +18,7 @@ binary="$1"
|
||||
arch="$2"
|
||||
version="$3"
|
||||
output="$4"
|
||||
tray="${5:-}"
|
||||
|
||||
here="$(cd "$(dirname "$0")" && pwd)"
|
||||
root="$(mktemp -d)"
|
||||
@@ -40,31 +43,48 @@ install -D -m 0644 "$here/../linux/50-tsunagi-resolved.rules" \
|
||||
install -D -m 0644 "$here/../../README.md" "$root/usr/share/doc/tsunagi/README.md"
|
||||
install -D -m 0644 "$here/../linux/README.md" "$root/usr/share/doc/tsunagi/INSTALL.md"
|
||||
|
||||
pkgname=tsunagi
|
||||
pkgdesc="Serverless private mesh networking agent"
|
||||
relations=""
|
||||
if [ -n "$tray" ]; then
|
||||
pkgname=tsunagi-gui
|
||||
pkgdesc="Serverless private mesh networking agent, with the tray GUI"
|
||||
relations=$'conflict = tsunagi\nprovides = tsunagi\nreplaces = tsunagi\n'
|
||||
install -D -m 0755 "$tray" "$root/usr/bin/tsunagi-tray"
|
||||
install -D -m 0644 "$here/../linux/tsunagi-tray.desktop" \
|
||||
"$root/usr/share/applications/tsunagi-tray.desktop"
|
||||
install -D -m 0644 "$here/../linux/tsunagi.svg" \
|
||||
"$root/usr/share/icons/hicolor/scalable/apps/tsunagi.svg"
|
||||
fi
|
||||
|
||||
# Installed size (payload only), before the metadata files are written.
|
||||
size="$(du -sb "$root" | cut -f1)"
|
||||
|
||||
cat > "$root/.PKGINFO" <<PKGINFO
|
||||
pkgname = tsunagi
|
||||
pkgname = ${pkgname}
|
||||
pkgver = ${pkgver}-${pkgrel}
|
||||
pkgdesc = Serverless private mesh networking agent
|
||||
pkgdesc = ${pkgdesc}
|
||||
url = https://github.com/Ultradesu/tsunagi
|
||||
builddate = $(date +%s)
|
||||
packager = AB <ab@hexor.cy>
|
||||
size = ${size}
|
||||
arch = ${arch}
|
||||
license = MIT
|
||||
${relations}license = MIT
|
||||
license = Apache
|
||||
PKGINFO
|
||||
|
||||
# Scriptlet: create the dedicated system user the service runs as, and keep
|
||||
# systemd in step. The "tsunagi" user is in the "tsunagi" group, which the
|
||||
# polkit rule grants the resolver actions.
|
||||
# Scriptlet: create the dedicated system user the service runs as, keep systemd
|
||||
# in step, and refresh the desktop/icon caches (a no-op without a GUI payload).
|
||||
cat > "$root/.INSTALL" <<'INSTALL'
|
||||
post_install() {
|
||||
getent group tsunagi >/dev/null 2>&1 || groupadd -r tsunagi
|
||||
getent passwd tsunagi >/dev/null 2>&1 || \
|
||||
useradd -r -g tsunagi -d /var/lib/tsunagi -s /usr/bin/nologin -c "tsunagi agent" tsunagi
|
||||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||
command -v update-desktop-database >/dev/null 2>&1 && \
|
||||
update-desktop-database -q /usr/share/applications >/dev/null 2>&1 || true
|
||||
command -v gtk-update-icon-cache >/dev/null 2>&1 && \
|
||||
gtk-update-icon-cache -q -t /usr/share/icons/hicolor >/dev/null 2>&1 || true
|
||||
}
|
||||
post_upgrade() {
|
||||
post_install
|
||||
|
||||
Vendored
+43
-13
@@ -1,19 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# Assemble a dependency-free Debian package from a prebuilt static tsunagi
|
||||
# binary, using only dpkg-deb (no cargo-deb, no nfpm). The binary is statically
|
||||
# linked, so the package declares no Depends and runs on any Debian/Ubuntu.
|
||||
# Assemble a dependency-free Debian package from prebuilt tsunagi binaries,
|
||||
# using only dpkg-deb (no cargo-deb, no nfpm).
|
||||
#
|
||||
# Usage: build-deb.sh <binary> <deb_arch> <version> <output.deb>
|
||||
# <binary> path to the built tsunagi executable
|
||||
# <deb_arch> Debian architecture: amd64 or arm64
|
||||
# <version> package version (the tag without its leading v)
|
||||
# <output> path to write the .deb to
|
||||
# Usage: build-deb.sh <binary> <deb_arch> <version> <output.deb> [tray_binary]
|
||||
# <binary> path to the built tsunagi (agent/CLI) executable
|
||||
# <deb_arch> Debian architecture: amd64 or arm64
|
||||
# <version> package version (the tag without its leading v)
|
||||
# <output> path to write the .deb to
|
||||
# [tray_binary] optional path to the tsunagi-tray GUI executable; when given,
|
||||
# the package also installs the tray and a desktop launcher and
|
||||
# is named tsunagi-gui (conflicting with the headless tsunagi).
|
||||
set -euo pipefail
|
||||
|
||||
binary="$1"
|
||||
arch="$2"
|
||||
version="$3"
|
||||
output="$4"
|
||||
tray="${5:-}"
|
||||
|
||||
here="$(cd "$(dirname "$0")" && pwd)"
|
||||
root="$(mktemp -d)"
|
||||
@@ -34,22 +37,38 @@ install -D -m 0644 "$here/../linux/50-tsunagi-resolved.rules" \
|
||||
install -D -m 0644 "$here/../../README.md" "$root/usr/share/doc/tsunagi/README.md"
|
||||
install -D -m 0644 "$here/../linux/README.md" "$root/usr/share/doc/tsunagi/INSTALL.md"
|
||||
|
||||
pkgname=tsunagi
|
||||
extra_control=""
|
||||
desc_gui=""
|
||||
if [ -n "$tray" ]; then
|
||||
pkgname=tsunagi-gui
|
||||
# The GUI package is a superset of the headless one and must not coexist
|
||||
# with it (both ship /usr/bin/tsunagi).
|
||||
extra_control=$'Conflicts: tsunagi\nReplaces: tsunagi\nProvides: tsunagi\n'
|
||||
desc_gui=" It also installs the tray GUI (tsunagi-tray) and a desktop launcher so it can be started from the applications menu."
|
||||
install -D -m 0755 "$tray" "$root/usr/bin/tsunagi-tray"
|
||||
install -D -m 0644 "$here/../linux/tsunagi-tray.desktop" \
|
||||
"$root/usr/share/applications/tsunagi-tray.desktop"
|
||||
install -D -m 0644 "$here/../linux/tsunagi.svg" \
|
||||
"$root/usr/share/icons/hicolor/scalable/apps/tsunagi.svg"
|
||||
fi
|
||||
|
||||
mkdir -p "$root/DEBIAN"
|
||||
|
||||
cat > "$root/DEBIAN/control" <<CTRL
|
||||
Package: tsunagi
|
||||
Package: ${pkgname}
|
||||
Version: ${version}
|
||||
Architecture: ${arch}
|
||||
Maintainer: AB <ab@hexor.cy>
|
||||
Section: net
|
||||
Priority: optional
|
||||
Homepage: https://github.com/Ultradesu/tsunagi
|
||||
Description: Serverless private mesh networking agent
|
||||
${extra_control}Description: Serverless private mesh networking agent
|
||||
tsunagi forms small private mesh IP networks between peers, with NAT
|
||||
traversal and no central server. This package installs a static,
|
||||
dependency-free binary, a systemd service that runs the agent as a dedicated
|
||||
dependency-free agent, a systemd service that runs it as a dedicated
|
||||
unprivileged "tsunagi" user with only CAP_NET_ADMIN and CAP_NET_BIND_SERVICE,
|
||||
and a polkit rule for the local DNS resolver.
|
||||
and a polkit rule for the local DNS resolver.${desc_gui}
|
||||
CTRL
|
||||
|
||||
# The dedicated system user the service runs as. It is in the "tsunagi" group,
|
||||
@@ -68,9 +87,20 @@ fi
|
||||
if [ -d /run/systemd/system ]; then
|
||||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||
fi
|
||||
exit 0
|
||||
POSTINST
|
||||
|
||||
if [ -n "$tray" ]; then
|
||||
cat >> "$root/DEBIAN/postinst" <<'POSTINST_GUI'
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
update-desktop-database -q /usr/share/applications >/dev/null 2>&1 || true
|
||||
fi
|
||||
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
|
||||
gtk-update-icon-cache -q -t /usr/share/icons/hicolor >/dev/null 2>&1 || true
|
||||
fi
|
||||
POSTINST_GUI
|
||||
fi
|
||||
echo "exit 0" >> "$root/DEBIAN/postinst"
|
||||
|
||||
cat > "$root/DEBIAN/prerm" <<'PRERM'
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=tsunagi
|
||||
GenericName=Mesh network manager
|
||||
Comment=Manage tsunagi networks from the tray
|
||||
Exec=tsunagi-tray
|
||||
Icon=tsunagi
|
||||
Terminal=false
|
||||
Categories=Network;Utility;
|
||||
Keywords=mesh;vpn;overlay;network;
|
||||
StartupNotify=false
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
|
||||
<circle cx="64" cy="64" r="56" fill="#2f80d8"/>
|
||||
<circle cx="64" cy="64" r="30" fill="none" stroke="#ffffff" stroke-width="7" opacity="0.9"/>
|
||||
<circle cx="64" cy="64" r="9" fill="#ffffff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 328 B |
Reference in new issue
Block a user