Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experiment: Fix building of AppImage version #1069

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ arm_linux_task:
libxss-dev
libasound2-dev
libnss3
wget
xvfb
- gem install dotenv -v '~> 2.8'
- gem install fpm
Expand All @@ -100,6 +101,8 @@ arm_linux_task:
- yarn dist || yarn dist
rename_binary_script:
- node script/rename.js "ARM.Linux"
fix_linux_appimage_script:
- ./script/fix-linux-appimage.sh aarch64
binary_artifacts:
path: ./binaries/*
test_script:
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
steps:
- name: Install build dependencies - Linux
if: ${{ runner.os == 'Linux' }}
run: apt-get update && apt-get install -y git python3 python3-pip make gcc g++ libx11-dev libxkbfile-dev pkg-config libsecret-1-dev rpm xvfb ffmpeg zstd
run: apt-get update && apt-get install -y git python3 python3-pip make gcc g++ libx11-dev libxkbfile-dev pkg-config libsecret-1-dev rpm xvfb ffmpeg zstd wget squashfs-tools

- name: Checkout the latest code
uses: actions/checkout@v4
Expand Down Expand Up @@ -177,6 +177,10 @@ jobs:
if: ${{ runner.os == 'Windows' }}
run: node ./script/rename.js "Windows"

- name: Fix AppImage target - Linux
if: ${{ runner.os == 'Linux' }}
run: ./script/fix-linux-appimage.sh x86_64

- name: Cache Pulsar Binaries - Linux
if: ${{ runner.os == 'Linux' }}
uses: actions/cache/save@v4
Expand Down
126 changes: 126 additions & 0 deletions script/fix-linux-appimage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/usr/bin/env bash

# NOTE: This script is a post-build task for the Linux AppImage version of
# Pulsar. It's meant to run in Pulsar's CI and almost certainly won't do
# anything useful if run on your local machine.

# Usage: Takes a single argument for the architecture — either `x86_64` or
# `ARM_64` — and “fixes” an AppImage file as emitted by `electron-builder` so
# that it points to `pulsar.sh` internally and runs _that_ when invoked instead
# of the direct binary.
#
# This is important for a couple of reasons:
#
# 1. Some command-line arguments, like `--wait`, don't work properly unless
# they rely on `pulsar.sh` to do some work for them.
# 2. `pulsar.sh` can intercept the `-p`/`--package` switch (signaling that the
# user wants to run `ppm`) and call it more quickly than Pulsar can.
#
# This is pretty easy to do with an AppImage, but `electron-builder` isn't
# customizable enough for us to make that change without it affecting other
# things. Luckily, AppImage is straightforward enough as a tool that we can
# do it manually.
#
# The workflow here is as follows:
#
# * Extract the AppImage (every AppImage has the ability to do this by itself).
# * Modify the `AppRun` script whose purpose is to invoke the Electron
# executable; modify it to invoke our `pulsar.sh` script instead.
# * Download and extract `appimagetool`.
# * Use it to package everything back into an AppImage at the original location
# on disk.
#
# If you're unsure if this modification has worked, the best way to find out is
# to run
#
# ./Pulsar.AppImage --wait foo.txt
#
# and keep an eye on the terminal window after Pulsar launches. It should not
# return to a new prompt until you close `foo.txt` for editing. If you don't
# get a new prompt after closing `foo.txt`, or if you see logging statements in
# your terminal after launch, then it's almost certain that the AppImage hasn't
# been fixed.


# Fail on first error. None of these steps is prone to random failure, except
# _possibly_ the part where we download `appimagetool`; if that's ever the
# cause of failures, we could spin that off into a separate step that uses
# the `retry` action. Otherwise this script is quite straightforward.
set -e

# Use `appimagetool`’s names for our two processor architectures.
if [[ "${1:x86_64}" == "x86_64" ]]; then
APPIMAGE_ARCH="x86_64"
APPIMAGETOOL_ARCH="x86_64"
else
APPIMAGE_ARCH="aarch64"
APPIMAGETOOL_ARCH="arm_aarch64"
fi

echo "Architecture is: ${APPIMAGE_ARCH}"

cd binaries
PULSAR_APPIMAGE="$(ls *.AppImage | xargs)"
echo "Existing binary is ${PULSAR_APPIMAGE}."
chmod +x "${PULSAR_APPIMAGE}"

echo "Extracting ${PULSAR_APPIMAGE} to Pulsar.AppDir…"
"./${PULSAR_APPIMAGE}" "--appimage-extract"
# Will extract to `squashfs-root`. Let's rename it just for sanity.
mv "squashfs-root" "Pulsar.AppDir"

# Move the `AppImage` to a new filename because we'll be replacing it soon.
mv "${PULSAR_APPIMAGE}" "${PULSAR_APPIMAGE%.AppImage}.old.AppImage"

# `AppRun` is the entry point of an `AppImage`. Ours is generated by
# `electron-builder`. We need to customize it to launch a script rather than
# our executable.

# First we'll copy the existing `AppRun` file to a temporary path.
cd "Pulsar.AppDir"
echo "Moving AppRun to AppRun.old…"
mv AppRun AppRun.old
rm -f AppRun

# Next we'll use `awk` to replace the reference to BIN in `AppRun` so that it
# points to `pulsar.sh` rather than the `pulsar` executable.
echo "Making new AppRun…"
awk '{sub(/BIN=(.*?)/,"BIN=\"$APPDIR/resources/pulsar.sh\""); print}' AppRun.old > AppRun
chmod a+x AppRun

# For sanity's sake, show the new line so we know that this was done properly
# just by inspecting the CI job output. This will help if we ever upgrade
# `electron-builder` and find that this generated line has changed somehow.
echo "Rewrote BIN to read:"
cat AppRun | grep "BIN="

# We don't need the old `AppRun` anymore.
echo "Removing AppRun.old…"
rm -f AppRun.old

cd ../..

# Now that we've made the change, we can use `appimagetool` to bundle
# everything up with the original file name.
echo "Downloading appimagetool…"
wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-${APPIMAGE_ARCH}.AppImage" -O appimagetool
echo "Making appimagetool executable…"
chmod +x appimagetool

# Docker can't run AppImage apps natively, but we can use the
# `--appimage-extract-and-run` option to extract the app to a location on disk
# instead.
#
# It makes us set an `ARCH` environment variable — no idea why, since these are
# thin binaries, but whatever.
echo "Building new AppImage at: binaries/${PULSAR_APPIMAGE} with ARCH value: ${APPIMAGETOOL_ARCH}…"
ARCH="${APPIMAGETOOL_ARCH}" ./appimagetool --appimage-extract-and-run "binaries/Pulsar.AppDir" "binaries/${PULSAR_APPIMAGE}"
chmod a+x "binaries/${PULSAR_APPIMAGE}"
echo "…done building AppImage."

# Clean up! Remove the old AppImage and the temporary directory.
echo "Removing temporary Pulsar.AppDir and old AppImage…"
rm -rf "binaries/Pulsar.AppDir"
rm -f "binaries/${PULSAR_APPIMAGE%.AppImage}.old.AppImage"

echo "…done! AppImage is fixed!"
Loading