From 6397e1443ffa83ec1bb9d4b91656fe85f5be453f Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 2 May 2018 18:05:55 +0000 Subject: [PATCH] Add AppImage packaging for Linux. --- .travis.yml | 7 +- packaging/linux/AppRun.in | 35 ++++++ packaging/linux/buildpackage.sh | 136 ++++++++++++++++++++++ packaging/linux/openra-server.appimage.in | 5 + packaging/linux/openra.appimage.in | 48 ++++++++ packaging/package-all.sh | 1 + 6 files changed, 228 insertions(+), 4 deletions(-) create mode 100755 packaging/linux/AppRun.in create mode 100755 packaging/linux/buildpackage.sh create mode 100755 packaging/linux/openra-server.appimage.in create mode 100755 packaging/linux/openra.appimage.in diff --git a/.travis.yml b/.travis.yml index a07de2ae65..af100e2f79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,7 @@ addons: - cmake - genisoimage - fakeroot + - zsync # Environment variables env: @@ -75,10 +76,8 @@ deploy: provider: releases api_key: secure: "g/LU11f+mjqv+lj0sR1UliHwogXL4ofJUwoG5Dbqlvdf5UTLWytw/OWSCv8RGyuh10miyWeaoqHh1cn2C1IFhUEqN1sSeKKKOWOTvJ2FR5mzi9uH3d/MOBzG5icQ7Qh0fZ1YPz5RaJJhYu6bmfvA/1gD49GoaX2kxQL4J5cEBgg=" - file: - - build/OpenRA-${TRAVIS_TAG}.exe - - build/OpenRA-${TRAVIS_TAG}.dmg - - build/OpenRA-${TRAVIS_TAG}-source.tar.bz2 + file_glob: true + file: build/* skip_cleanup: true on: all_branches: true diff --git a/packaging/linux/AppRun.in b/packaging/linux/AppRun.in new file mode 100755 index 0000000000..bf168bb31f --- /dev/null +++ b/packaging/linux/AppRun.in @@ -0,0 +1,35 @@ +#!/bin/sh + +# Make sure the user has a sufficiently recent version of mono on the PATH +MINIMUM_MONO_VERSION="4.2" + +make_version() { + echo "$1" | tr '.' '\n' | head -n 4 | xargs printf "%03d%03d%03d%03d"; +} + +mono_missing_or_old() { + command -v mono >/dev/null 2>&1 || return 0 + MONO_VERSION=$(mono --version | head -n1 | cut -d' ' -f5) + [ "$(make_version "${MONO_VERSION}")" -lt "$(make_version "${MINIMUM_MONO_VERSION}")" ] && return 0 + return 1 +} + +if mono_missing_or_old; then + if command -v zenity > /dev/null; then + zenity --no-wrap --error --title "{MODNAME}" --text "{MODNAME} requires Mono ${MINIMUM_MONO_VERSION} or greater.\nPlease install Mono using your system package manager." + else + printf "{MODNAME} requires Mono %s or greater.\nPlease install Mono using your system package manager.\n" "${MINIMUM_MONO_VERSION}" + 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}" + +if [ -n "$1" ] && [ "$1" = "--server" ]; then + exec "openra-{MODID}-server" "$@" +else + exec "openra-{MODID}" "$@" +fi diff --git a/packaging/linux/buildpackage.sh b/packaging/linux/buildpackage.sh new file mode 100755 index 0000000000..6a5ef158c3 --- /dev/null +++ b/packaging/linux/buildpackage.sh @@ -0,0 +1,136 @@ +#!/bin/bash +# OpenRA packaging script for Linux (AppImage) +set -e + +command -v make >/dev/null 2>&1 || { echo >&2 "Linux packaging requires make."; exit 1; } +command -v python >/dev/null 2>&1 || { echo >&2 "Linux packaging requires python."; exit 1; } +command -v tar >/dev/null 2>&1 || { echo >&2 "Linux packaging requires tar."; exit 1; } +command -v curl >/dev/null 2>&1 || { echo >&2 "Linux packaging requires curl."; exit 1; } + +DEPENDENCIES_TAG="20180410" + +if [ $# -eq "0" ]; then + echo "Usage: `basename $0` version [outputdir]" + exit 1 +fi + +# Set the working dir to the location of this script +cd $(dirname $0) + +TAG="$1" +OUTPUTDIR="$2" +SRCDIR="$(pwd)/../.." +BUILTDIR="$(pwd)/build" + +UPDATE_CHANNEL="" +SUFFIX="-devel" +if [[ ${TAG} == release* ]]; then + UPDATE_CHANNEL="release" + SUFFIX="" +elif [[ ${TAG} == playtest* ]]; then + UPDATE_CHANNEL="playtest" + SUFFIX="-playtest" +elif [[ ${TAG} == pkgtest* ]]; then + UPDATE_CHANNEL="pkgtest" + SUFFIX="-pkgtest" +fi + +pushd "${TEMPLATE_ROOT}" > /dev/null + +if [ ! -d "${OUTPUTDIR}" ]; then + echo "Output directory '${OUTPUTDIR}' does not exist."; + exit 1 +fi + +echo "Building core files" + +pushd ${SRCDIR} > /dev/null +make linux-dependencies +make core SDK="-sdk:4.5" +make version VERSION="${TAG}" +make install-engine prefix="usr" DESTDIR="${BUILTDIR}/" +make install-common-mod-files prefix="usr" DESTDIR="${BUILTDIR}/" + +popd > /dev/null + +# Add native libraries +echo "Downloading dependencies" +curl -s -L -O https://github.com/OpenRA/AppImageSupport/releases/download/${DEPENDENCIES_TAG}/libs.tar.bz2 || exit 3 +curl -s -L -O https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage || exit 3 +chmod a+x appimagetool-x86_64.AppImage + +echo "Building AppImage" +tar xf libs.tar.bz2 +install -Dm 0755 libSDL2.so "${BUILTDIR}/usr/lib/openra/" +install -Dm 0644 SDL2-CS.dll.config "${BUILTDIR}/usr/lib/openra/" +install -Dm 0755 libopenal.so "${BUILTDIR}/usr/lib/openra/" +install -Dm 0644 OpenAL-CS.dll.config "${BUILTDIR}/usr/lib/openra/" +install -Dm 0755 liblua.so "${BUILTDIR}/usr/lib/openra/" +install -Dm 0644 Eluant.dll.config "${BUILTDIR}/usr/lib/openra/" +rm libs.tar.bz2 libSDL2.so SDL2-CS.dll.config libopenal.so OpenAL-CS.dll.config liblua.so Eluant.dll.config + +build_appimage() { + MOD_ID=${1} + DISPLAY_NAME=${2} + APPDIR="$(pwd)/${MOD_ID}.appdir" + APPIMAGE="OpenRA-$(echo ${DISPLAY_NAME} | sed 's/ /-/g')${SUFFIX}-x86_64.AppImage" + + cp -r "${BUILTDIR}" "${APPDIR}" + + # Add mod files + pushd "${SRCDIR}" > /dev/null + cp -r "mods/${MOD_ID}" mods/modcontent "${APPDIR}/usr/lib/openra/mods" + popd > /dev/null + + # Add launcher and icons + sed "s/{MODID}/${MOD_ID}/g" AppRun.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" > AppRun.temp + install -m 0755 AppRun.temp "${APPDIR}/AppRun" + + sed "s/{MODID}/${MOD_ID}/g" openra.desktop.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" | sed "s/{TAG}/${TAG}/g" > temp.desktop + echo "StartupWMClass=openra-${MOD_ID}-${TAG}" >> temp.desktop + + install -Dm 0755 temp.desktop "${APPDIR}/usr/share/applications/openra-${MOD_ID}.desktop" + install -m 0755 temp.desktop "${APPDIR}/openra-${MOD_ID}.desktop" + + sed "s/{MODID}/${MOD_ID}/g" openra-mimeinfo.xml.in | sed "s/{TAG}/${TAG}/g" > temp.xml + install -Dm 0755 temp.xml "${APPDIR}/usr/share/mime/packages/openra-${MOD_ID}.xml" + + if [ -f "icons/${MOD_ID}_scalable.svg" ]; then + install -Dm644 "icons/${MOD_ID}_scalable.svg" "${APPDIR}/usr/share/icons/hicolor/scalable/apps/openra-${MOD_ID}.svg" + fi + + for i in 16x16 32x32 48x48 64x64 128x128 256x256 512x512 1024x1024; do + if [ -f "icons/${MOD_ID}_${i}.png" ]; then + install -Dm644 "icons/${MOD_ID}_${i}.png" "${APPDIR}/usr/share/icons/hicolor/${i}/apps/openra-${MOD_ID}.png" + install -m644 "icons/${MOD_ID}_${i}.png" "${APPDIR}/openra-${MOD_ID}.png" + fi + done + + install -d "${APPDIR}/usr/bin" + + sed "s/{MODID}/${MOD_ID}/g" openra.appimage.in | sed "s/{TAG}/${TAG}/g" | sed "s/{MODNAME}/${DISPLAY_NAME}/g" > openra-mod.temp + install -m 0755 openra-mod.temp "${APPDIR}/usr/bin/openra-${MOD_ID}" + + sed "s/{MODID}/${MOD_ID}/g" openra-server.appimage.in > openra-mod-server.temp + install -m 0755 openra-mod-server.temp "${APPDIR}/usr/bin/openra-${MOD_ID}-server" + + # travis-ci doesn't support mounting FUSE filesystems so extract and run the contents manually + ./appimagetool-x86_64.AppImage --appimage-extract + + # Embed update metadata if (and only if) compiled on travis + if [ ! -z "${TRAVIS_REPO_SLUG}" ]; then + ARCH=x86_64 ./squashfs-root/AppRun --no-appstream -u "zsync|https://master.openra.net/appimagecheck?mod=${MOD_ID}&channel=${UPDATE_CHANNEL}" "${APPDIR}" "${OUTPUTDIR}/${APPIMAGE}" + zsyncmake -u "https://github.com/${TRAVIS_REPO_SLUG}/releases/download/${TAG}/${APPIMAGE}" -o "${OUTPUTDIR}/${APPIMAGE}.zsync" "${OUTPUTDIR}/${APPIMAGE}" + else + ARCH=x86_64 ./squashfs-root/AppRun --no-appstream "${APPDIR}" "${OUTPUTDIR}/${APPIMAGE}" + fi + + rm -rf "${APPDIR}" +} + +build_appimage "ra" "Red Alert" +build_appimage "cnc" "Tiberian Dawn" +build_appimage "d2k" "Dune 2000" + +# Clean up +rm -rf openra-mod.temp openra-mod-server.temp temp.desktop temp.xml AppRun.temp appimagetool-x86_64.AppImage squashfs-root "${BUILTDIR}" \ No newline at end of file diff --git a/packaging/linux/openra-server.appimage.in b/packaging/linux/openra-server.appimage.in new file mode 100755 index 0000000000..d53260e094 --- /dev/null +++ b/packaging/linux/openra-server.appimage.in @@ -0,0 +1,5 @@ +#!/bin/sh +HERE="$(dirname "$(readlink -f "${0}")")" +cd "${HERE}/../lib/openra" || exit 1 + +mono --debug OpenRA.Server.exe Game.Mod={MODID} "$@" diff --git a/packaging/linux/openra.appimage.in b/packaging/linux/openra.appimage.in new file mode 100755 index 0000000000..f13445202f --- /dev/null +++ b/packaging/linux/openra.appimage.in @@ -0,0 +1,48 @@ +#!/bin/sh +LAUNCHER=$(readlink -f "${0}") +HERE="$(dirname "${LAUNCHER}")" +cd "${HERE}/../lib/openra" || exit 1 + +# APPIMAGE is an environment variable set by the runtime +# defining the absolute path to the .AppImage file +if [ ! -z "${APPIMAGE}" ]; then + LAUNCHER=${APPIMAGE} + + # appimaged doesn't update the mime or icon caches when registering AppImages. + # Run update-desktop-database and gtk-update-icon-cache ourselves if we detect + # that the desktop file has been installed but the handler is not cached + if command -v update-desktop-database > /dev/null; then + APPIMAGEID=$(printf "file://%s" "${APPIMAGE}" | md5sum | cut -d' ' -f1) + LAUNCHER_NAME="appimagekit_${APPIMAGEID}-openra-{MODID}.desktop" + LAUNCHER_PATH="${HOME}/.local/share/applications/${LAUNCHER_NAME}" + MIMECACHE_PATH="${HOME}/.local/share/applications/mimeinfo.cache" + SCHEME="x-scheme-handler/openra-{MODID}-{TAG}" + if [ -f "${LAUNCHER_PATH}" ] && ! grep -qs "${SCHEME}=" "${MIMECACHE_PATH}"; then + update-desktop-database "${HOME}/.local/share/applications" + if command -v gtk-update-icon-cache > /dev/null; then + gtk-update-icon-cache ~/.local/share/icons/hicolor/ -t + fi + fi + fi +fi + +# Search for server connection +PROTOCOL_PREFIX="openra-{MODID}-{TAG}://" +JOIN_SERVER="" +if [ "${1#${PROTOCOL_PREFIX}}" != "${1}" ]; then + JOIN_SERVER="Launch.Connect=${1#${PROTOCOL_PREFIX}}" +fi + +# Run the game +export SDL_VIDEO_X11_WMCLASS="openra-{MODID}-{TAG}" +mono --debug OpenRA.Game.exe Game.Mod={MODID} Engine.LaunchPath="${LAUNCHER}" "${JOIN_SERVER}" "$@" + +# Show a crash dialog if something went wrong +if [ $? != 0 ] && [ $? != 1 ]; then + if command -v zenity > /dev/null; then + zenity --no-wrap --question --title "{MODNAME}" --text "{MODNAME} has encountered a fatal error.\nLog Files are available in ~/.openra." --ok-label "Quit" --cancel-label "View FAQ" || xdg-open https://github.com/OpenRA/OpenRA/wiki/FAQ + else + printf "{MODNAME} has encountered a fatal error.\n -> Log Files are available in ~/.openra\n -> FAQ is available at https://github.com/OpenRA/OpenRA/wiki/FAQ\n" + fi + exit 1 +fi diff --git a/packaging/package-all.sh b/packaging/package-all.sh index 8842e59e70..d9d10b3dee 100755 --- a/packaging/package-all.sh +++ b/packaging/package-all.sh @@ -29,6 +29,7 @@ function build_package() ( set -e build_package windows build_package osx +build_package linux build_package source echo "Package build done."