From 309c37b94b79400c12e419210db82743b913a537 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 4 Jul 2018 18:37:56 +0000 Subject: [PATCH] Port AppImage improvements from upstream. - Automatically run cert-sync to fix https connections - Include a gtk fallback error dialog using python - Automatically prompt mono-complete install on Ubuntu-like distros --- packaging/linux/buildpackage.sh | 2 ++ packaging/linux/include/AppRun.in | 45 ++++++++++++++++++++++--- packaging/linux/include/gtk-dialog.py | 48 +++++++++++++++++++++++++++ packaging/linux/include/mod.in | 2 ++ 4 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 packaging/linux/include/gtk-dialog.py diff --git a/packaging/linux/buildpackage.sh b/packaging/linux/buildpackage.sh index 57b4674..da5cc32 100755 --- a/packaging/linux/buildpackage.sh +++ b/packaging/linux/buildpackage.sh @@ -132,6 +132,8 @@ install -m 0755 openra-mod.temp "${BUILTDIR}/usr/bin/openra-${MOD_ID}" sed "s/{MODID}/${MOD_ID}/g" include/mod-server.in > openra-mod-server.temp install -m 0755 openra-mod-server.temp "${BUILTDIR}/usr/bin/openra-${MOD_ID}-server" +install -m 0755 include/gtk-dialog.py "${BUILTDIR}/usr/bin/gtk-dialog.py" + # travis-ci doesn't support mounting FUSE filesystems so extract and run the contents manually ./appimagetool-x86_64.AppImage --appimage-extract ARCH=x86_64 ./squashfs-root/AppRun "${BUILTDIR}" "${OUTPUTDIR}/${PACKAGING_INSTALLER_NAME}-${TAG}.AppImage" diff --git a/packaging/linux/include/AppRun.in b/packaging/linux/include/AppRun.in index 353e9de..d2fbc4d 100755 --- a/packaging/linux/include/AppRun.in +++ b/packaging/linux/include/AppRun.in @@ -3,6 +3,16 @@ # Make sure the user has a sufficiently recent version of mono on the PATH MINIMUM_MONO_VERSION="4.2" +prompt_apt_install_mono_complete() { + command -v mono >/dev/null 2>&1 && return 1 + command -v apt-cache > /dev/null || return 1 + command -v xdg-mime > /dev/null || return 1 + command -v xdg-open > /dev/null || return 1 + [ ! "$(xdg-mime query default x-scheme-handler/apt)" ] && return 1 + apt-cache search --names-only mono-complete | cut -d' ' -f1 | grep "^mono-complete$" > /dev/null || return 1 + return 0 +} + make_version() { echo "$1" | tr '.' '\n' | head -n 4 | xargs printf "%03d%03d%03d%03d"; } @@ -14,23 +24,50 @@ mono_missing_or_old() { return 1 } +HERE="$(dirname "$(readlink -f "${0}")")" +export PATH="${HERE}"/usr/bin/:"${PATH}" +export XDG_DATA_DIRS="${HERE}"/usr/share/:"${XDG_DATA_DIRS}" + +# If mono is not installed, and the user has apt-cache, apt-url, +# xdg-open, and either zenity or kdialog, then we can prompt to +# automatically install the mono-complete package +if prompt_apt_install_mono_complete; then + PROMPT_MESSAGE="{MODNAME} requires the Mono runtime.\nWould you like to install it now?" + if command -v zenity > /dev/null; then + zenity --no-wrap --question --title "{MODNAME}" --text "${PROMPT_MESSAGE}" 2> /dev/null && xdg-open apt://mono-complete && exit 0 + elif command -v kdialog > /dev/null; then + kdialog --title "{MODNAME}" --yesno "${PROMPT_MESSAGE}" && xdg-open apt://mono-complete && exit 0 + elif "${HERE}/usr/bin/gtk-dialog.py" test > /dev/null; then + "${HERE}/usr/bin/gtk-dialog.py" question --title "{MODNAME}" --text "${PROMPT_MESSAGE}" 2> /dev/null && xdg-open apt://mono-complete && exit 0 + fi +fi + if mono_missing_or_old; then ERROR_MESSAGE="{MODNAME} requires Mono ${MINIMUM_MONO_VERSION} or greater.\nPlease install Mono using your system package manager." if command -v zenity > /dev/null; then zenity --no-wrap --error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null elif command -v kdialog > /dev/null; then kdialog --title "{MODNAME}" --error "${ERROR_MESSAGE}" + elif "${HERE}/usr/bin/gtk-dialog.py" test > /dev/null; then + "${HERE}/usr/bin/gtk-dialog.py" error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null else printf "${ERROR_MESSAGE}" fi exit 1 fi -# Run the game or server -HERE="$(dirname "$(readlink -f "${0}")")" -export PATH="${HERE}"/usr/bin/:"${PATH}" -export XDG_DATA_DIRS="${HERE}"/usr/share/:"${XDG_DATA_DIRS}" +# Some distros and self-compiled mono installations don't set up +# the SSL required for http web queries. If we detect that these +# are missing we can try and create a local sync as a fallback. +if [ ! -d "/usr/share/.mono/certs" ] && [ ! -d "${HOME}/.config/.mono/certs" ]; then + if [ -f "/etc/pki/tls/certs/ca-bundle.crt" ]; then + cert-sync --quiet --user /etc/pki/tls/certs/ca-bundle.crt + elif [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then + cert-sync --quiet --user /etc/ssl/certs/ca-certificates.crt + fi +fi +# Run the game or server if [ -n "$1" ] && [ "$1" = "--server" ]; then exec "openra-{MODID}-server" "$@" else diff --git a/packaging/linux/include/gtk-dialog.py b/packaging/linux/include/gtk-dialog.py new file mode 100644 index 0000000..2ed1476 --- /dev/null +++ b/packaging/linux/include/gtk-dialog.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +"""A simple GTK3 graphical dialog helper that can be used as a fallback if zenity is not available + Compatible with python 2 or 3 with the gi bindings. + + Three modes are available: + test: accepts no arguments, returns 0 if the python dependencies are available, or 1 if not + error: show a gtk-3 error dialog + accepts arguments --title and --text + error: show a gtk-3 question dialog + accepts arguments --title and --text + returns 0 on Yes, or 1 on No +""" + +import sys + +try: + import argparse + import gi + gi.require_version('Gtk', '3.0') + from gi.repository import Gtk +except ImportError: + sys.exit(1) + +class Error(): + def __init__(self, title, text): + dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, title) + dialog.format_secondary_text(text) + dialog.run() + dialog.destroy() + +class Question(): + def __init__(self, title, text): + dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, title) + dialog.format_secondary_text(text) + response = dialog.run() + dialog.destroy() + sys.exit(0 if response == Gtk.ResponseType.YES else 1) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('type', choices=['error', 'question', 'test']) + parser.add_argument('--title', type=str, required=False, default='') + parser.add_argument('--text', type=str, required=False, default='') + args = parser.parse_args() + if args.type == 'question': + Question(args.title, args.text.replace('\\n', '\n')) + elif args.type == 'error': + Error(args.title, args.text.replace('\\n', '\n')) diff --git a/packaging/linux/include/mod.in b/packaging/linux/include/mod.in index 45bf353..fa424b1 100755 --- a/packaging/linux/include/mod.in +++ b/packaging/linux/include/mod.in @@ -45,6 +45,8 @@ if [ $? != 0 ] && [ $? != 1 ]; then zenity --no-wrap --error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null elif command -v kdialog > /dev/null; then kdialog --title "{MODNAME}" --error "${ERROR_MESSAGE}" + elif "${HERE}/gtk-dialog.py" test > /dev/null; then + "${HERE}/gtk-dialog.py" error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null else printf "${ERROR_MESSAGE}\n" fi