diff --git a/nixos/vnc-desktop/Dockerfile b/nixos/vnc-desktop/Dockerfile index 5060336..e28791d 100644 --- a/nixos/vnc-desktop/Dockerfile +++ b/nixos/vnc-desktop/Dockerfile @@ -22,6 +22,21 @@ RUN apt-get purge -y --auto-remove bluez bluez-obexd 2>/dev/null || true; \ rm -f /usr/share/dbus-1/services/org.bluez.obex.service \ /usr/share/dbus-1/system-services/org.bluez.service +# Firefox via Mozilla apt repo (Ubuntu 24.04 ships Firefox as snap by default) +RUN apt-get install -y --no-install-recommends wget ca-certificates gnupg \ + && wget -qO- https://packages.mozilla.org/apt/repo-signing-key.gpg \ + | gpg --dearmor > /usr/share/keyrings/packages.mozilla.org.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/packages.mozilla.org.gpg] https://packages.mozilla.org/apt mozilla main" \ + > /etc/apt/sources.list.d/mozilla.list \ + && printf 'Package: *\nPin: origin packages.mozilla.org\nPin-Priority: 1000\n' \ + > /etc/apt/preferences.d/mozilla \ + && apt-get update \ + && apt-get install -y --no-install-recommends firefox \ + && rm -rf /var/lib/apt/lists/* + +COPY discover-logging/ /discover-logging/ +RUN chmod +x /discover-logging/build.sh && /discover-logging/build.sh + COPY start.sh /start.sh RUN chmod +x /start.sh diff --git a/nixos/vnc-desktop/discover-logging/build.sh b/nixos/vnc-desktop/discover-logging/build.sh new file mode 100644 index 0000000..6e0249a --- /dev/null +++ b/nixos/vnc-desktop/discover-logging/build.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Enable deb-src so apt-get source works +sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources + +apt-get update -qq + +apt-get install -y --no-install-recommends \ + dpkg-dev \ + build-essential \ + devscripts \ + python3 + +apt-get build-dep -y plasma-discover + +cd /tmp +apt-get source plasma-discover + +SRC_DIR=$(ls -d /tmp/plasma-discover-*/) + +# Apply logging patch +python3 /discover-logging/patch.py "$SRC_DIR/libdiscover/backends/PackageKitBackend/PKTransaction.cpp" + +cd "$SRC_DIR" +DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage -b -uc -us -j"$(nproc)" + +# Install the rebuilt packages (packagekit-backend.so lives in plasma-discover_*.deb) +dpkg -i /tmp/plasma-discover_*.deb + +# Clean up to keep image lean +rm -rf /tmp/plasma-discover-* /tmp/*.deb /tmp/*.dsc /tmp/*.tar.* diff --git a/nixos/vnc-desktop/discover-logging/patch.py b/nixos/vnc-desktop/discover-logging/patch.py new file mode 100644 index 0000000..9a05367 --- /dev/null +++ b/nixos/vnc-desktop/discover-logging/patch.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +""" +Patch PKTransaction.cpp to add verbose logging so we can diagnose +why installs hang on "Installing..." status. +""" +import sys + +def replace_once(src, old, new, label): + count = src.count(old) + if count != 1: + print(f"ERROR: '{label}' matched {count} times (expected 1)", file=sys.stderr) + sys.exit(1) + return src.replace(old, new) + +path = sys.argv[1] +with open(path) as f: + src = f.read() + +# 1. trigger(): log what phase we're entering and with what flags +src = replace_once(src, + 'void PKTransaction::trigger(PackageKit::Transaction::TransactionFlags flags)\n{', + 'void PKTransaction::trigger(PackageKit::Transaction::TransactionFlags flags)\n{\n' + ' qWarning() << "[DISCOVER] trigger(): flags=" << flags << "role=" << role();', + 'trigger() header' +) + +# 2. statusChanged(): log the raw PK status instead of the collapsed UI status +src = replace_once(src, + 'void PKTransaction::statusChanged()\n{' + '\n setStatus(m_trans->status() == PackageKit::Transaction::StatusDownload ? Transaction::DownloadingStatus : Transaction::CommittingStatus);', + 'void PKTransaction::statusChanged()\n{' + '\n qWarning() << "[DISCOVER] statusChanged(): pk_status=" << m_trans->status()' + ' << "percentage=" << m_trans->percentage()' + ' << "lastPackage=" << m_trans->lastPackage();' + '\n setStatus(m_trans->status() == PackageKit::Transaction::StatusDownload ? Transaction::DownloadingStatus : Transaction::CommittingStatus);', + 'statusChanged() body' +) + +# 3. progressChanged(): log when percentage updates (or fails to) +src = replace_once(src, + ' auto percent = m_trans->percentage();\n if (percent == 101) {\n qWarning() << "percentage cannot be calculated";', + ' auto percent = m_trans->percentage();\n' + ' qWarning() << "[DISCOVER] progressChanged(): raw_pct=" << percent << "pk_status=" << m_trans->status();\n' + ' if (percent == 101) {\n qWarning() << "percentage cannot be calculated";', + 'progressChanged() body' +) + +# 4. cleanup(): log the exit/cancel/failed/simulate flags +src = replace_once(src, + 'void PKTransaction::cleanup(PackageKit::Transaction::Exit exit, uint runtime)\n{', + 'void PKTransaction::cleanup(PackageKit::Transaction::Exit exit, uint runtime)\n{\n' + ' const bool _simulate_flag = m_trans && (m_trans->transactionFlags() & PackageKit::Transaction::TransactionFlagSimulate);\n' + ' qWarning() << "[DISCOVER] cleanup(): exit=" << exit << "runtime=" << runtime' + ' << "simulate=" << _simulate_flag' + ' << "proceedFunctions=" << m_proceedFunctions.size();', + 'cleanup() header' +) + +# 5. errorFound(): log every error, including ones currently silently swallowed +src = replace_once(src, + 'void PKTransaction::errorFound(PackageKit::Transaction::Error err, const QString &error)\n{' + '\n if (err == PackageKit::Transaction::ErrorNoLicenseAgreement || err == PackageKit::Transaction::ErrorTransactionCancelled' + '\n || err == PackageKit::Transaction::ErrorNotAuthorized) {' + '\n return;\n }', + 'void PKTransaction::errorFound(PackageKit::Transaction::Error err, const QString &error)\n{' + '\n qWarning() << "[DISCOVER] errorFound(): err=" << err << "detail=" << error;' + '\n if (err == PackageKit::Transaction::ErrorNoLicenseAgreement || err == PackageKit::Transaction::ErrorTransactionCancelled' + '\n || err == PackageKit::Transaction::ErrorNotAuthorized) {' + '\n return;\n }', + 'errorFound() body' +) + +# 6. LocalFilePKResource path: log the .deb path being installed +src = replace_once(src, + ' m_trans = PackageKit::Daemon::installFile(QUrl(app->packageName()).toLocalFile(), flags);', + ' qWarning() << "[DISCOVER] installFile():" << QUrl(app->packageName()).toLocalFile() << "flags=" << flags;\n' + ' m_trans = PackageKit::Daemon::installFile(QUrl(app->packageName()).toLocalFile(), flags);', + 'installFile() call' +) + +with open(path, 'w') as f: + f.write(src) + +print(f"Patched {path}")