Use sharun to bundle AppImage (#4515)
This commit is contained in:
24
.github/actions/package/linux/action.yml
vendored
24
.github/actions/package/linux/action.yml
vendored
@@ -58,9 +58,7 @@ runs:
|
||||
|
||||
GPG_PRIVATE_KEY: ${{ inputs.gpg-private-key }}
|
||||
run: |
|
||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
|
||||
|
||||
cp ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.prismlauncher.PrismLauncher.{metainfo,appdata}.xml
|
||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}
|
||||
|
||||
if [ '${{ inputs.gpg-private-key-id }}' != '' ]; then
|
||||
echo "$GPG_PRIVATE_KEY" > privkey.asc
|
||||
@@ -70,11 +68,23 @@ runs:
|
||||
echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
appimagetool -s deploy "$INSTALL_APPIMAGE_DIR"/usr/share/applications/*.desktop
|
||||
cp ~/bin/AppImageUpdate.AppImage "$INSTALL_APPIMAGE_DIR"/usr/bin/
|
||||
# FIXME(@getchoo): Validate AppStream information when https://github.com/probonopd/go-appimage/pull/379 is merged
|
||||
sharun lib4bin \
|
||||
--hard-links \
|
||||
--with-hooks \
|
||||
--dst-dir "$INSTALL_APPIMAGE_DIR" \
|
||||
"$INSTALL_APPIMAGE_DIR"/bin/* "$QT_PLUGIN_PATH"/*/*.so
|
||||
|
||||
cp ~/bin/AppImageUpdate.AppImage "$INSTALL_APPIMAGE_DIR"/bin/
|
||||
# FIXME(@getchoo): gamemode doesn't seem to be very portable with DBus. Find a way to make it work!
|
||||
find "$INSTALL_APPIMAGE_DIR" -name '*gamemode*' -exec rm {} +
|
||||
|
||||
ln -s org.prismlauncher.PrismLauncher.metainfo.xml "$INSTALL_APPIMAGE_DIR"/share/metainfo/org.prismlauncher.PrismLauncher.appdata.xml
|
||||
ln -s share/applications/org.prismlauncher.PrismLauncher.desktop "$INSTALL_APPIMAGE_DIR"
|
||||
ln -s share/icons/hicolor/256x256/apps/org.prismlauncher.PrismLauncher.png "$INSTALL_APPIMAGE_DIR"
|
||||
mv "$INSTALL_APPIMAGE_DIR"/{sharun,AppRun}
|
||||
ls -la "$INSTALL_APPIMAGE_DIR"
|
||||
|
||||
mkappimage \
|
||||
--no-appstream \
|
||||
--updateinformation "gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|PrismLauncher-Linux-$APPIMAGE_ARCH.AppImage.zsync" \
|
||||
"$INSTALL_APPIMAGE_DIR" \
|
||||
"PrismLauncher-Linux-$VERSION-${{ inputs.build-type }}-$APPIMAGE_ARCH.AppImage"
|
||||
|
||||
@@ -56,19 +56,19 @@ runs:
|
||||
;;
|
||||
esac
|
||||
|
||||
gh release download continuous \
|
||||
--repo probonopd/go-appimage \
|
||||
--pattern "appimagetool-*-$APPIMAGE_ARCH.AppImage" \
|
||||
--output ~/bin/appimagetool
|
||||
gh release download \
|
||||
--repo VHSgunzo/sharun \
|
||||
--pattern "sharun-$APPIMAGE_ARCH-aio" \
|
||||
--output ~/bin/sharun
|
||||
|
||||
gh release download continuous \
|
||||
--repo probonopd/go-appimage \
|
||||
--pattern "mkappimage-*-$APPIMAGE_ARCH.AppImage" \
|
||||
--output ~/bin/mkappimage
|
||||
chmod +x ~/bin/appimagetool ~/bin/mkappimage
|
||||
echo "$HOME/bin" >> "$GITHUB_PATH"
|
||||
|
||||
gh release download \
|
||||
--repo AppImageCommunity/AppImageUpdate \
|
||||
--pattern "AppImageUpdate-$APPIMAGE_ARCH.AppImage" \
|
||||
--output ~/bin/AppImageUpdate.AppImage
|
||||
chmod +x ~/bin/AppImageUpdate.AppImage
|
||||
chmod +x ~/bin/*
|
||||
echo "$HOME/bin" >> "$GITHUB_PATH"
|
||||
|
||||
@@ -371,25 +371,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||
}
|
||||
|
||||
QString origcwdPath = QDir::currentPath();
|
||||
#if defined(Q_OS_LINUX)
|
||||
const QString binFilePath = applicationFilePath();
|
||||
const bool isAppImage = binFilePath.startsWith("/tmp/.mount_");
|
||||
// Yes, this can technically trigger the logic below if someone makes an AppImage with an actual launcher exe named "ld-linux"
|
||||
// Please don't :)
|
||||
const bool executedFromLinker = QFileInfo(binFilePath).fileName().startsWith("ld-linux");
|
||||
|
||||
// NOTE(@getchoo): In order for `go-appimage` to generate self-contained AppImages, it executes apps from a bundled linker at
|
||||
// <root>/lib64
|
||||
// This is not the path to our actual binary, which we want
|
||||
QString binPath;
|
||||
if (isAppImage && executedFromLinker) {
|
||||
binPath = FS::PathCombine(applicationDirPath(), "../usr/bin");
|
||||
} else {
|
||||
binPath = applicationDirPath();
|
||||
}
|
||||
#else
|
||||
QString binPath = applicationDirPath();
|
||||
#endif
|
||||
|
||||
{
|
||||
// Root path is used for updates and portable data
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 dada513 <dada513@protonmail.com>
|
||||
* Copyright (C) 2025 Seth Flynn <getchoo@tuta.io>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -76,15 +75,6 @@ bool isFlatpak()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isSelfContained()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
return QFileInfo(QCoreApplication::applicationFilePath()).fileName().startsWith("ld-linux");
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isSnap()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
|
||||
@@ -37,11 +37,6 @@ bool openUrl(const QUrl& url);
|
||||
*/
|
||||
bool isFlatpak();
|
||||
|
||||
/**
|
||||
* Determine whether the launcher is running in a self-contained Linux bundle
|
||||
*/
|
||||
bool isSelfContained();
|
||||
|
||||
/**
|
||||
* Determine whether the launcher is running in a Snap environment
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
* Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
||||
* Copyright (C) 2025 Seth Flynn <getchoo@tuta.io>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -773,34 +772,6 @@ QString ResolveExecutable(QString path)
|
||||
return pathInfo.absoluteFilePath();
|
||||
}
|
||||
|
||||
std::unique_ptr<QProcess> createProcess(const QString& program, const QStringList& arguments)
|
||||
{
|
||||
qDebug() << "Creating process for" << program;
|
||||
auto proc = std::unique_ptr<QProcess>(new QProcess());
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
if (DesktopServices::isSelfContained()) {
|
||||
const auto linkerPath = QCoreApplication::applicationFilePath();
|
||||
qDebug() << "Wrapping" << program << "with self-contained linker at" << linkerPath;
|
||||
|
||||
QStringList wrappedArguments;
|
||||
wrappedArguments << "--inhibit-cache" << program;
|
||||
wrappedArguments += arguments;
|
||||
|
||||
proc->setProgram(linkerPath);
|
||||
proc->setArguments(wrappedArguments);
|
||||
} else {
|
||||
proc->setProgram(program);
|
||||
proc->setArguments(arguments);
|
||||
}
|
||||
#else
|
||||
proc->setProgram(program);
|
||||
proc->setArguments(arguments);
|
||||
#endif
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize path
|
||||
*
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
* Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
||||
* Copyright (C) 2025 Seth Flynn <getchoo@tuta.io>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -43,13 +42,11 @@
|
||||
|
||||
#include <system_error>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QFlags>
|
||||
#include <QLocalServer>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QProcess>
|
||||
#include <QThread>
|
||||
|
||||
namespace FS {
|
||||
@@ -336,14 +333,6 @@ QString pathTruncate(const QString& path, int depth);
|
||||
*/
|
||||
QString ResolveExecutable(QString path);
|
||||
|
||||
/**
|
||||
* Create a QProcess instance
|
||||
*
|
||||
* This wrapper is currently only required for wrapping binaries called in
|
||||
* self-contained AppImages (like those created by `go-appimage`)
|
||||
*/
|
||||
std::unique_ptr<QProcess> createProcess(const QString& program, const QStringList& arguments);
|
||||
|
||||
/**
|
||||
* Normalize path
|
||||
*
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QProcess>
|
||||
#include <QProgressDialog>
|
||||
#include <QSettings>
|
||||
#include <QTimer>
|
||||
@@ -34,7 +35,6 @@
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include "BuildConfig.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
#include "ui/dialogs/UpdateAvailableDialog.h"
|
||||
|
||||
@@ -97,9 +97,14 @@ void PrismExternalUpdater::checkForUpdates(bool triggeredByUser)
|
||||
progress.show();
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
QProcess proc;
|
||||
auto exe_name = QStringLiteral("%1_updater").arg(BuildConfig.LAUNCHER_APP_BINARY_NAME);
|
||||
#if defined Q_OS_WIN32
|
||||
exe_name.append(".exe");
|
||||
|
||||
auto env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("__COMPAT_LAYER", "RUNASINVOKER");
|
||||
proc.setProcessEnvironment(env);
|
||||
#else
|
||||
exe_name = QString("bin/%1").arg(exe_name);
|
||||
#endif
|
||||
@@ -108,21 +113,15 @@ void PrismExternalUpdater::checkForUpdates(bool triggeredByUser)
|
||||
if (priv->allowBeta)
|
||||
args.append("--pre-release");
|
||||
|
||||
auto proc = FS::createProcess(priv->appDir.absoluteFilePath(exe_name), args);
|
||||
#if defined Q_OS_WIN32
|
||||
auto env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("__COMPAT_LAYER", "RUNASINVOKER");
|
||||
proc->setProcessEnvironment(env);
|
||||
#endif
|
||||
proc->start(proc->program(), proc->arguments());
|
||||
auto result_start = proc->waitForStarted(5000);
|
||||
proc.start(priv->appDir.absoluteFilePath(exe_name), args);
|
||||
auto result_start = proc.waitForStarted(5000);
|
||||
if (!result_start) {
|
||||
auto err = proc->error();
|
||||
auto err = proc.error();
|
||||
qDebug() << "Failed to start updater after 5 seconds."
|
||||
<< "reason:" << err << proc->errorString();
|
||||
<< "reason:" << err << proc.errorString();
|
||||
auto msgBox =
|
||||
QMessageBox(QMessageBox::Information, tr("Update Check Failed"),
|
||||
tr("Failed to start after 5 seconds\nReason: %1.").arg(proc->errorString()), QMessageBox::Ok, priv->parent);
|
||||
tr("Failed to start after 5 seconds\nReason: %1.").arg(proc.errorString()), QMessageBox::Ok, priv->parent);
|
||||
msgBox.setMinimumWidth(460);
|
||||
msgBox.adjustSize();
|
||||
msgBox.exec();
|
||||
@@ -134,16 +133,16 @@ void PrismExternalUpdater::checkForUpdates(bool triggeredByUser)
|
||||
}
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
auto result_finished = proc->waitForFinished(60000);
|
||||
auto result_finished = proc.waitForFinished(60000);
|
||||
if (!result_finished) {
|
||||
proc->kill();
|
||||
auto err = proc->error();
|
||||
auto output = proc->readAll();
|
||||
proc.kill();
|
||||
auto err = proc.error();
|
||||
auto output = proc.readAll();
|
||||
qDebug() << "Updater failed to close after 60 seconds."
|
||||
<< "reason:" << err << proc->errorString();
|
||||
<< "reason:" << err << proc.errorString();
|
||||
auto msgBox =
|
||||
QMessageBox(QMessageBox::Information, tr("Update Check Failed"),
|
||||
tr("Updater failed to close 60 seconds\nReason: %1.").arg(proc->errorString()), QMessageBox::Ok, priv->parent);
|
||||
tr("Updater failed to close 60 seconds\nReason: %1.").arg(proc.errorString()), QMessageBox::Ok, priv->parent);
|
||||
msgBox.setDetailedText(output);
|
||||
msgBox.setMinimumWidth(460);
|
||||
msgBox.adjustSize();
|
||||
@@ -155,10 +154,10 @@ void PrismExternalUpdater::checkForUpdates(bool triggeredByUser)
|
||||
return;
|
||||
}
|
||||
|
||||
auto exit_code = proc->exitCode();
|
||||
auto exit_code = proc.exitCode();
|
||||
|
||||
auto std_output = proc->readAllStandardOutput();
|
||||
auto std_error = proc->readAllStandardError();
|
||||
auto std_output = proc.readAllStandardOutput();
|
||||
auto std_error = proc.readAllStandardError();
|
||||
|
||||
progress.hide();
|
||||
QCoreApplication::processEvents();
|
||||
@@ -336,9 +335,14 @@ void PrismExternalUpdater::offerUpdate(const QString& version_name, const QStrin
|
||||
|
||||
void PrismExternalUpdater::performUpdate(const QString& version_tag)
|
||||
{
|
||||
QProcess proc;
|
||||
auto exe_name = QStringLiteral("%1_updater").arg(BuildConfig.LAUNCHER_APP_BINARY_NAME);
|
||||
#if defined Q_OS_WIN32
|
||||
exe_name.append(".exe");
|
||||
|
||||
auto env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("__COMPAT_LAYER", "RUNASINVOKER");
|
||||
proc.setProcessEnvironment(env);
|
||||
#else
|
||||
exe_name = QString("bin/%1").arg(exe_name);
|
||||
#endif
|
||||
@@ -347,16 +351,9 @@ void PrismExternalUpdater::performUpdate(const QString& version_tag)
|
||||
if (priv->allowBeta)
|
||||
args.append("--pre-release");
|
||||
|
||||
auto proc = FS::createProcess(exe_name, args);
|
||||
#if defined Q_OS_WIN32
|
||||
auto env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("__COMPAT_LAYER", "RUNASINVOKER");
|
||||
proc->setProcessEnvironment(env);
|
||||
#endif
|
||||
|
||||
auto result = proc->startDetached(priv->appDir.absoluteFilePath(exe_name), args);
|
||||
auto result = proc.startDetached(priv->appDir.absoluteFilePath(exe_name), args);
|
||||
if (!result) {
|
||||
qDebug() << "Failed to start updater:" << proc->error() << proc->errorString();
|
||||
qDebug() << "Failed to start updater:" << proc.error() << proc.errorString();
|
||||
}
|
||||
QCoreApplication::exit();
|
||||
}
|
||||
|
||||
@@ -124,19 +124,7 @@ PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, ar
|
||||
logToConsole = parser.isSet("debug");
|
||||
|
||||
QString origCwdPath = QDir::currentPath();
|
||||
#if defined(Q_OS_LINUX)
|
||||
// NOTE(@getchoo): In order for `go-appimage` to generate self-contained AppImages, it executes apps from a bundled linker at
|
||||
// <root>/lib64
|
||||
// This is not the path to our actual binary, which we want
|
||||
QString binPath;
|
||||
if (DesktopServices::isSelfContained()) {
|
||||
binPath = FS::PathCombine(applicationDirPath(), "../usr/bin");
|
||||
} else {
|
||||
binPath = applicationDirPath();
|
||||
}
|
||||
#else
|
||||
QString binPath = applicationDirPath();
|
||||
#endif
|
||||
|
||||
{ // find data director
|
||||
// Root path is used for updates and portable data
|
||||
@@ -819,16 +807,13 @@ QFileInfo PrismUpdaterApp::downloadAsset(const GitHubReleaseAsset& asset)
|
||||
bool PrismUpdaterApp::callAppImageUpdate()
|
||||
{
|
||||
auto appimage_path = QProcessEnvironment::systemEnvironment().value(QStringLiteral("APPIMAGE"));
|
||||
QProcess proc = QProcess();
|
||||
qDebug() << "Calling: AppImageUpdate" << appimage_path;
|
||||
const auto program = FS::PathCombine(m_rootPath, "bin", "AppImageUpdate.AppImage");
|
||||
auto proc = FS::createProcess(program, { appimage_path });
|
||||
if (!proc) {
|
||||
qCritical() << "Unable to create process:" << program;
|
||||
return false;
|
||||
}
|
||||
auto result = proc->startDetached();
|
||||
proc.setProgram(FS::PathCombine(m_rootPath, "bin", "AppImageUpdate.AppImage"));
|
||||
proc.setArguments({ appimage_path });
|
||||
auto result = proc.startDetached();
|
||||
if (!result)
|
||||
qDebug() << "Failed to start AppImageUpdate reason:" << proc->errorString();
|
||||
qDebug() << "Failed to start AppImageUpdate reason:" << proc.errorString();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user