Treat AppImages As Self-Mounting Tarballs

This commit is contained in:
TheBrokenRail 2022-07-04 16:44:00 -04:00
parent ea4c5c77a1
commit b539491713
14 changed files with 95 additions and 261 deletions

View File

@ -96,7 +96,11 @@ endif()
# Specify Default Installation Prefix # Specify Default Installation Prefix
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "" FORCE) set(DEFAULT_PREFIX "/usr")
if(MCPI_IS_APPIMAGE_BUILD)
set(DEFAULT_PREFIX "/")
endif()
set(CMAKE_INSTALL_PREFIX "${DEFAULT_PREFIX}" CACHE PATH "" FORCE)
endif() endif()
# Optimizations # Optimizations

View File

@ -1,19 +1,10 @@
# Symlink Function # Symlink Function
function(install_symlink target link) function(install_symlink target link)
install(CODE "\ get_filename_component(parent "${link}" DIRECTORY)
# Prepare\n \ if(parent STREQUAL "")
set(file \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${link}\")\n \ set(parent ".")
\ endif()
# Create Directory\n \ file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/symlink/${parent}")
get_filename_component(dir \"\${file}\" DIRECTORY)\n \ file(CREATE_LINK "${target}" "${CMAKE_BINARY_DIR}/symlink/${link}" SYMBOLIC)
file(MAKE_DIRECTORY \${dir})\n \ install(FILES "${CMAKE_BINARY_DIR}/symlink/${link}" DESTINATION "${parent}")
\
# Create Symlink\n \
if(NOT EXISTS \"\${file}\")\n \
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink ${target} \"\${file}\")\n \
message(\"-- Installing: \${file}\")\n \
else()\n \
message(\"-- Up-to-date: \${file}\")\n \
endif() \
")
endfunction() endfunction()

View File

@ -10,13 +10,13 @@ else()
# Copy To Binary Directory # Copy To Binary Directory
set(APT_DIR "${CMAKE_CURRENT_BINARY_DIR}/apt") set(APT_DIR "${CMAKE_CURRENT_BINARY_DIR}/apt")
file(REMOVE_RECURSE "${APT_DIR}")
file(MAKE_DIRECTORY "${APT_DIR}") file(MAKE_DIRECTORY "${APT_DIR}")
# Make Directories # Make Directories
file(MAKE_DIRECTORY "${APT_DIR}/apt.conf.d") file(MAKE_DIRECTORY "${APT_DIR}/apt.conf.d")
file(MAKE_DIRECTORY "${APT_DIR}/preferences.d") file(MAKE_DIRECTORY "${APT_DIR}/preferences.d")
file(MAKE_DIRECTORY "${APT_DIR}/keys") file(MAKE_DIRECTORY "${APT_DIR}/keys")
file(MAKE_DIRECTORY "${APT_DIR}/dpkg") file(MAKE_DIRECTORY "${APT_DIR}/dpkg")
file(MAKE_DIRECTORY "${APT_DIR}/archives")
file(TOUCH "${APT_DIR}/dpkg/status") file(TOUCH "${APT_DIR}/dpkg/status")
# Create APT Sources # Create APT Sources
@ -65,7 +65,6 @@ else()
# Create Sysroot Directory # Create Sysroot Directory
set(SYSROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}/sysroot") set(SYSROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}/sysroot")
file(REMOVE_RECURSE "${SYSROOT_DIR}")
file(MAKE_DIRECTORY "${SYSROOT_DIR}") file(MAKE_DIRECTORY "${SYSROOT_DIR}")
# Download # Download
@ -78,6 +77,7 @@ else()
add_custom_command( add_custom_command(
OUTPUT "${APT_DIR}/.download-stamp" OUTPUT "${APT_DIR}/.download-stamp"
DEPENDS "${APT_DIR}/.update-stamp" DEPENDS "${APT_DIR}/.update-stamp"
COMMAND find "${APT_DIR}/archives" -maxdepth 1 -type f -name "*.deb" -delete
COMMAND ${APT_ENV} apt-get install -y --no-install-recommends --download-only ${APT_PACKAGES} COMMAND ${APT_ENV} apt-get install -y --no-install-recommends --download-only ${APT_PACKAGES}
COMMAND "${CMAKE_COMMAND}" -E touch "${APT_DIR}/.download-stamp" COMMAND "${CMAKE_COMMAND}" -E touch "${APT_DIR}/.download-stamp"
VERBATIM VERBATIM
@ -85,7 +85,8 @@ else()
add_custom_command( add_custom_command(
OUTPUT "${APT_DIR}/.extract-stamp" OUTPUT "${APT_DIR}/.extract-stamp"
DEPENDS "${APT_DIR}/.download-stamp" DEPENDS "${APT_DIR}/.download-stamp"
COMMAND ${APT_ENV} find "${APT_DIR}/archives" -maxdepth 1 -type f -name "*.deb" -exec dpkg -x {} "${SYSROOT_DIR}" ";" COMMAND find "${SYSROOT_DIR}" -mindepth 1 -delete
COMMAND find "${APT_DIR}/archives" -maxdepth 1 -type f -name "*.deb" -exec dpkg -x {} "${SYSROOT_DIR}" ";"
COMMAND "${CMAKE_COMMAND}" -E touch "${APT_DIR}/.extract-stamp" COMMAND "${CMAKE_COMMAND}" -E touch "${APT_DIR}/.extract-stamp"
VERBATIM VERBATIM
) )

View File

@ -15,3 +15,9 @@ install(
DESTINATION "share/icons/hicolor/scalable/apps" DESTINATION "share/icons/hicolor/scalable/apps"
RENAME "${MCPI_APP_ID}.png" RENAME "${MCPI_APP_ID}.png"
) )
# AppImage
if(MCPI_IS_APPIMAGE_BUILD)
install_symlink("share/icons/hicolor/scalable/apps/${MCPI_APP_ID}.png" "${MCPI_APP_ID}.png")
install_symlink("${MCPI_APP_ID}.png" ".DirIcon")
endif()

View File

@ -110,3 +110,10 @@ install(
DESTINATION "share/metainfo" DESTINATION "share/metainfo"
RENAME "${MCPI_APP_ID}.appdata.xml" RENAME "${MCPI_APP_ID}.appdata.xml"
) )
# AppImage
if(MCPI_IS_APPIMAGE_BUILD)
install_symlink("bin/${MCPI_VARIANT_NAME}" "AppRun")
install_symlink("share/applications/${MCPI_APP_ID}.desktop" "${MCPI_APP_ID}.desktop")
install_symlink("." "usr")
endif()

View File

@ -37,3 +37,4 @@ TRUE Improved Title Background
TRUE Force Touch GUI Button Behavior TRUE Force Touch GUI Button Behavior
TRUE Improved Button Hover Behavior TRUE Improved Button Hover Behavior
TRUE Implement Create World Dialog TRUE Implement Create World Dialog
TRUE Remove Forced GUI Lag

View File

@ -12,6 +12,9 @@ __attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char
// Run // Run
int ret = execvpe(argv[0], (char *const *) argv, (char *const *) envp); int ret = execvpe(argv[0], (char *const *) argv, (char *const *) envp);
if (ret == -1) { if (ret == -1) {
if (errno == ENOENT && strcmp(argv[0], "qemu-qrm")) {
ERR("Unable to find QEMU! To install on Ubuntu/Debian, run \"sudo apt install qemu-user\". To install on Arch Linux, run \"sudo pacman -Sy qemu-user\".");
}
ERR("Unable To Execute Program: %s: %s", argv[0], strerror(errno)); ERR("Unable To Execute Program: %s: %s", argv[0], strerror(errno));
} else { } else {
IMPOSSIBLE(); IMPOSSIBLE();

View File

@ -129,26 +129,6 @@ void init_compat() {
sigaction(SIGTERM, &act_sigterm, NULL); sigaction(SIGTERM, &act_sigterm, NULL);
} }
// Cleanup Temporary Files
__attribute__((destructor)) static void cleanup_temporary() {
// Cleanup Executable
{
char *exe = realpath("/proc/self/exe", NULL);
// Check If Successful
if (exe != NULL) {
// Check If Executable Is Temporary
if (starts_with(exe, "/tmp")) {
// Cleanup Temporary File
if (unlink(exe) != 0) {
ERR("Unable To Cleanup Temporary File: %s", strerror(errno));
}
}
// Free
free(exe);
}
}
}
// Store Exit Requests // Store Exit Requests
static int exit_requested = 0; static int exit_requested = 0;
int compat_check_exit_requested() { int compat_check_exit_requested() {

View File

@ -205,6 +205,8 @@ static void GameRenderer_render_injection(unsigned char *game_renderer, float pa
} }
// Init // Init
static void nop() {
}
void init_misc() { void init_misc() {
// Remove Invalid Item Background (A Red Background That Appears For Items That Are Not Included In The gui_blocks Atlas) // Remove Invalid Item Background (A Red Background That Appears For Items That Are Not Included In The gui_blocks Atlas)
if (feature_has("Remove Invalid Item Background", server_disabled)) { if (feature_has("Remove Invalid Item Background", server_disabled)) {
@ -255,6 +257,11 @@ void init_misc() {
media_disable_vsync(); media_disable_vsync();
} }
// Remove Forced GUI Lag
if (feature_has("Remove Forced GUI Lag", server_enabled)) {
overwrite_calls((void *) sleepMs, (void *) nop);
}
// Init C++ And Logging // Init C++ And Logging
_init_misc_cpp(); _init_misc_cpp();
_init_misc_logging(); _init_misc_logging();

View File

@ -24,7 +24,7 @@ run() {
git \ git \
cmake \ cmake \
ninja-build \ ninja-build \
nodejs dpkg-dev
# Host Dependencies Needed For Compile # Host Dependencies Needed For Compile
queue_pkg \ queue_pkg \
@ -65,26 +65,30 @@ run() {
architecture_specific_pkg "${arch}" architecture_specific_pkg "${arch}"
done done
# Install appimagetool & appimage-builder Dependencies
queue_pkg \
python3-pip \
python3-setuptools \
python3-wheel \
patchelf \
desktop-file-utils \
libgdk-pixbuf2.0-dev \
fakeroot \
gtk-update-icon-cache \
shared-mime-info \
squashfs-tools \
zsync \
sed
# Install Queue # Install Queue
sudo apt-get install --no-install-recommends -y ${PKG_QUEUE} sudo apt-get install --no-install-recommends -y ${PKG_QUEUE}
# Install appimage-builder # Install appimagetool
sudo pip3 install 'git+https://github.com/AppImageCrafters/appimage-builder.git' sudo rm -rf /opt/squashfs-root /opt/appimagetool.AppDir
sudo rm -f /opt/appimagetool /usr/local/bin/appimagetool
case "$(dpkg-architecture -qDEB_BUILD_ARCH)" in
'armhf') APPIMAGE_ARCH='armhf';;
'arm64') APPIMAGE_ARCH='aarch64';;
'i386') APPIMAGE_ARCH='i686';;
'amd64') APPIMAGE_ARCH='x86_64';;
esac
sudo mkdir -p /opt
sudo wget -O /opt/appimagetool "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-${APPIMAGE_ARCH}.AppImage"
sudo chmod +x /opt/appimagetool
# Workaround AppImage Issues With Docker
cd /opt
sudo sed -i '0,/AI\x02/{s|AI\x02|\x00\x00\x00|}' ./appimagetool
# Extract
sudo ./appimagetool --appimage-extract
sudo rm -f ./appimagetool
# Link
sudo mv ./squashfs-root ./appimagetool.AppDir
sudo ln -s /opt/appimagetool.AppDir/AppRun /usr/local/bin/appimagetool
} }
# Run # Run

View File

@ -2,12 +2,33 @@
set -e set -e
# Generate # Prepare
./scripts/tools/generate-appimage-builder-yaml.js "$1" "$2" NAME='minecraft-pi-reborn'
# Build/Package # Build
appimage-builder --recipe AppImageBuilder.yml ./scripts/setup.sh "$1" "$2" -DMCPI_IS_APPIMAGE_BUILD=ON
./scripts/build.sh "$1" "$2"
# Download Runtime
case "$2" in
'armhf') RUNTIME_ARCH='armhf';;
'arm64') RUNTIME_ARCH='aarch64';;
'i386') RUNTIME_ARCH='i686';;
'amd64') RUNTIME_ARCH='x86_64';;
esac
mkdir -p build/appimage
if [ ! -f "build/appimage/runtime-$2" ]; then
wget -O "build/appimage/runtime-$2" "https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-${RUNTIME_ARCH}"
fi
# Package
ARCH="${RUNTIME_ARCH}" appimagetool \
--updateinformation "zsync|https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/${NAME}-latest-$2.AppImage.zsync" \
--runtime-file "build/appimage/runtime-$2" \
--comp xz \
"./out/$1-$2" \
"./out/${NAME}-$1-$(cat VERSION)-$2.AppImage"
# Move ZSync # Move ZSync
rm -f "./out/minecraft-pi-reborn-$1-latest-$2.AppImage.zsync" rm -f "./out/${NAME}-$1-latest-$2.AppImage.zsync"
mv "./minecraft-pi-reborn-$1-$(cat VERSION)-$2.AppImage.zsync" "./out/minecraft-pi-reborn-$1-latest-$2.AppImage.zsync" mv "./${NAME}-$1-$(cat VERSION)-$2.AppImage.zsync" "./out/${NAME}-$1-latest-$2.AppImage.zsync"

View File

@ -3,8 +3,9 @@
set -e set -e
# Build Test # Build Test
./scripts/setup.sh server "$(dpkg-architecture -qDEB_BUILD_ARCH)" ARCH="$(dpkg-architecture -qDEB_BUILD_ARCH)"
./scripts/build.sh server "$(dpkg-architecture -qDEB_BUILD_ARCH)" ./scripts/setup.sh server "${ARCH}"
./scripts/build.sh server "${ARCH}"
# Add minecraft-pi-reborn-server To PATH # Add minecraft-pi-reborn-server To PATH
export PATH="$(pwd)/out/server-$(dpkg-architecture -qDEB_BUILD_ARCH)/usr/bin:${PATH}" export PATH="$(pwd)/out/server-$(dpkg-architecture -qDEB_BUILD_ARCH)/usr/bin:${PATH}"

View File

@ -1,195 +0,0 @@
#!/usr/bin/env node
// Child Process
const child_process = require('child_process');
// Arguments
if (process.argv.length < 4) {
throw new Error('Invalid Arguments');
}
const mode = process.argv[2];
const arch = process.argv[3];
// Data
const id = `com.thebrokenrail.MCPIReborn${mode === 'server' ? 'Server' : 'Client'}`;
const name = `minecraft-pi-reborn-${mode}`;
const updateURL = `https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/${name}-latest-${arch}.AppImage.zsync`;
// APT Sources
const apt_sources = child_process.execFileSync('./scripts/tools/get-apt-sources.sh', [], {encoding: 'utf-8'}).trim().split('\n');
const apt_sources_formatted = [];
for (const apt_source of apt_sources) {
apt_sources_formatted.push({sourceline: apt_source});
}
// Version
const fs = require('fs');
const version = fs.readFileSync('VERSION', 'utf8').trim();
// Packages/Dependencies
const packages = [
'libc6',
'libstdc++6',
'patchelf'
];
if (mode === 'client') {
// GLFW's Dependencies Aren't Included As They Should Be Provided By The Host System
packages.push(
'libgtk-3-0',
'libglib2.0-0',
'libgdk-pixbuf2.0-0',
'librsvg2-common',
'shared-mime-info',
'libopenal1'
);
}
if (arch !== 'armhf' && arch !== 'arm64') {
packages.push('qemu-user');
}
// Package Exclusions
const packageExclusions = [
// Exclude Unneeded Packages
'humanity-icon-theme',
'adwaita-icon-theme',
'libxml2',
'*systemd*',
'dconf-service',
'dconf-gsettings-backend',
'librest-*',
'libcups2',
'libcolord2',
'libmount1',
'libwayland-*'
];
// APT
const apt = {
arch: arch,
sources: apt_sources_formatted,
allow_unauthenticated: true,
include: packages,
exclude: packageExclusions
};
// Get Architecture Triplet
const triplet = {
'amd64': 'x86_64-linux-gnu',
'i386': 'i386-linux-gnu',
'arm64': 'aarch64-linux-gnu',
'armhf': 'arm-linux-gnueabihf'
}[arch];
if (!triplet) {
throw new Error();
}
// Files
const files = {
exclude: [
// Exclude Unused Files
`usr/lib/${triplet}/gconv`,
'usr/share/man',
'usr/share/doc/*/README.*',
'usr/share/doc/*/changelog.*',
'usr/share/doc/*/NEWS.*',
'usr/share/doc/*/TODO.*',
'usr/include',
'usr/share/lintian',
'usr/share/gcc',
'usr/share/gdb',
'usr/share/locale',
'usr/share/help',
'usr/bin/update-mime-database'
]
};
// Script After Bundling Dependencies
const afterBundle = [
// Remove Unused QEMU Binaries
'find ./AppDir/usr/bin -maxdepth 1 -name \'qemu-*\' -a ! -name \'qemu-arm\' -delete'
];
// Environment
const env = {
APPDIR_MODULE_DIR: '/tmp/.minecraft-pi-patched'
};
if (mode === 'client') {
// Make GTK Work (Zenity Uses GTK)
env.GTK_EXE_PREFIX = '${APPDIR}/usr';
env.GTK_PATH = `\${APPDIR}/usr/lib/${triplet}/gtk-3.0`;
env.GTK_DATA_PREFIX = '${APPDIR}';
env.GTK_THEME = 'Default';
env.XDG_DATA_DIRS = '${APPDIR}/share:${APPDIR}/usr/share:/share:/usr/share';
env.APPDIR_LIBRARY_PATH = `\${APPDIR}/usr/lib/${triplet}:\${APPDIR}/usr/${triplet}/lib:\${APPDIR}/lib/${triplet}:\${APPDIR}/usr/lib:\${APPDIR}/usr/lib/${triplet}/gdk-pixbuf-2.0/2.10.0/loaders`;
}
// Runtime
const runtime = {
env: env,
preserve: arch !== 'armhf' ? [
// On non-ARM32 systems, an ARM32 linker is embedded, this
// prevents AppImage-Builder from modifying ARM32 binaries
// to use a (usually non-existent) system linker.
`usr/lib/${name}/minecraft-pi`,
`usr/lib/${name}/**/*.so`,
`usr/lib/${name}/sysroot`
] : [
// MCPI's license prohibits distributing a modified
// minecraft-pi binary.
`usr/lib/${name}/minecraft-pi`
]
};
// AppDir
const appDir = {
path: `./AppDir`,
app_info: {
id: id,
name: `${name}`,
icon: id,
version: version,
exec: `usr/bin/${name}`,
exec_args: '$@'
},
apt: apt,
files: files,
after_bundle: afterBundle,
runtime: runtime
};
// Build Script
const script = [
`rm -rf ./build/${mode}-${arch}`,
`./scripts/setup.sh ${mode} ${arch} -DMCPI_IS_APPIMAGE_BUILD=ON`,
`rm -rf ./out/${mode}-${arch}`,
`./scripts/build.sh ${mode} ${arch}`,
'rm -rf ./AppDir',
`cp -ar ./out/${mode}-${arch} ./AppDir`
];
// AppImage
const appImageArch = {
'amd64': 'x86_64',
'i386': 'i686',
'arm64': 'aarch64',
'armhf': 'armhf'
}[arch];
if (!appImageArch) {
throw new Error();
}
const appImage = {
arch: appImageArch,
file_name: `./out/${name}-${version}-${arch}.AppImage`,
'update-information': `zsync|${updateURL}`
};
// Root
const root = {
version: 1,
AppDir: appDir,
script: script,
AppImage: appImage
};
// Write
fs.writeFileSync(`AppImageBuilder.yml`, JSON.stringify(root, null, 4));

View File

@ -15,6 +15,9 @@ typedef unsigned char bool;
typedef void (*renderCursor_t)(float x, float y, unsigned char *minecraft); typedef void (*renderCursor_t)(float x, float y, unsigned char *minecraft);
static renderCursor_t renderCursor = (renderCursor_t) 0x480c4; static renderCursor_t renderCursor = (renderCursor_t) 0x480c4;
typedef void (*sleepMs_t)(int32_t x);
static sleepMs_t sleepMs = (sleepMs_t) 0x13cf4;
static char **default_path = (char **) 0xe264; // /.minecraft/ static char **default_path = (char **) 0xe264; // /.minecraft/
static char **default_username = (char **) 0x18fd4; // StevePi static char **default_username = (char **) 0x18fd4; // StevePi
static char **minecraft_pi_version = (char **) 0x39d94; // v0.1.1 alpha static char **minecraft_pi_version = (char **) 0x39d94; // v0.1.1 alpha