1#!/usr/bin/env bash
2
3((${BASH_VERSION%%.*} >= 4)) || { echo >&2 "$0: Error: Please upgrade Bash."; exit 1; }
4
5set -euxo pipefail
6
7readonly appdir="$1" # input path (Audacity install directory)
8readonly appimage="$2" # output path to use for created AppImage
9
10#============================================================================
11# Helper functions
12#============================================================================
13
14function download_github_release()
15{
16    local -r repo_slug="$1" release_tag="$2" file="$3"
17    wget -q --show-progress "https://github.com/${repo_slug}/releases/download/${release_tag}/${file}"
18    chmod +x "${file}"
19}
20
21function extract_appimage()
22{
23    # Extract AppImage so we can run it without having to install FUSE
24    local -r image="$1" binary_name="$2"
25    local -r dir="${image%.AppImage}.AppDir"
26    "./${image}" --appimage-extract >/dev/null # dest folder "squashfs-root"
27    mv squashfs-root "${dir}" # rename folder to avoid collisions
28    ln -s "${dir}/AppRun" "${binary_name}" # symlink for convenience
29    rm -f "${image}"
30}
31
32function download_appimage_release()
33{
34    local -r github_repo_slug="$1" binary_name="$2" tag="$3"
35    local -r image="${binary_name}-x86_64.AppImage"
36    download_github_release "${github_repo_slug}" "${tag}" "${image}"
37    extract_appimage "${image}" "${binary_name}"
38}
39
40function download_linuxdeploy_component()
41{
42    local -r component="$1" tag="$2"
43    download_appimage_release "linuxdeploy/$1" "$1" "$2"
44}
45
46function create_path()
47{
48    local -r path="$1"
49    if [[ -d "${path}" ]]; then
50        return 1 # already exists
51    fi
52    mkdir -p "${path}"
53}
54
55#============================================================================
56# Fetch AppImage packaging tools
57#============================================================================
58
59if create_path "appimagetool"; then
60(
61    cd "appimagetool"
62    download_appimage_release AppImage/AppImageKit appimagetool continuous
63)
64fi
65export PATH="${PWD%/}/appimagetool:${PATH}"
66appimagetool --version
67
68if create_path "linuxdeploy"; then
69(
70    cd "linuxdeploy"
71    download_linuxdeploy_component linuxdeploy continuous
72)
73fi
74
75export PATH="${PWD%/}/linuxdeploy:${PATH}"
76linuxdeploy --list-plugins
77
78#============================================================================
79# Create symlinks
80#============================================================================
81
82ln -sf --no-dereference . "${appdir}/usr"
83ln -sf share/applications/audacity.desktop "${appdir}/audacity.desktop"
84ln -sf share/icons/hicolor/scalable/apps/audacity.svg "${appdir}/audacity.svg"
85ln -sf share/icons/hicolor/scalable/apps/audacity.svg "${appdir}/.DirIcon"
86
87#============================================================================
88# Bundle dependencies
89#============================================================================
90
91# HACK: Some wxWidget libraries depend on themselves. Add
92# them to LD_LIBRARY_PATH so that linuxdeploy can find them.
93export LD_LIBRARY_PATH="${appdir}/usr/lib:${appdir}/usr/lib/audacity:${LD_LIBRARY_PATH-}"
94
95# Prevent linuxdeploy setting RUNPATH in binaries that shouldn't have it
96mv "${appdir}/bin/findlib" "${appdir}/../findlib"
97
98linuxdeploy --appdir "${appdir}" # add all shared library dependencies
99rm -R "${appdir}/lib/audacity"
100
101# Put the non-RUNPATH binaries back
102mv "${appdir}/../findlib" "${appdir}/bin/findlib"
103
104##########################################################################
105# BUNDLE REMAINING DEPENDENCIES MANUALLY
106##########################################################################
107
108function find_library()
109{
110  # Print full path to a library or return exit status 1 if not found
111  "${appdir}/bin/findlib" "$@"
112}
113
114function fallback_library()
115{
116  # Copy a library into a special fallback directory inside the AppDir.
117  # Fallback libraries are not loaded at runtime by default, but they can
118  # be loaded if it is found that the application would crash otherwise.
119  local library="$1"
120  local full_path="$(find_library "$1")"
121  local new_path="${appdir}/fallback/${library}"
122  mkdir -p "${new_path}" # directory has the same name as the library
123  cp -L "${full_path}" "${new_path}/${library}"
124  rm -f "${appdir}/lib/${library}"
125  # Use the AppRun script to check at runtime whether the user has a copy of
126  # this library. If not then add our copy's directory to $LD_LIBRARY_PATH.
127}
128
129unwanted_files=(
130  lib/libQt5Core.so.5
131  lib/libQt5Gui.so.5
132  lib/libQt5Widgets.so.5
133)
134
135fallback_libraries=(
136  libatk-1.0.so.0 # This will possibly prevent browser from opening
137  libatk-bridge-2.0.so.0
138  libcairo.so.2 # This breaks FFmpeg support
139  libcairo-gobject.so.2
140  libjack.so.0 # https://github.com/LMMS/lmms/pull/3958
141  libportaudio.so # This is required to enable system PortAudio (so Jack is enabled!)
142  libgmodule-2.0.so.0 # Otherwise - Manjaro/Arch will crash, because of libgio mismatch
143  # But if gmodule is present - glib2 is too
144  # Some ot the GTK libraries are balcklisted from being included
145  # libgio-2.0.so.0
146  # libglib-2.0.so.0
147  # libgobject-2.0.so.0
148  libgthread-2.0.so.0
149)
150
151for file in "${unwanted_files[@]}"; do
152  rm -f "${appdir}/${file}"
153done
154
155for fb_lib in "${fallback_libraries[@]}"; do
156  fallback_library "${fb_lib}"
157done
158
159#============================================================================
160# Build AppImage
161#============================================================================
162
163appimagetool_args=(
164    # none
165)
166
167if [[ "${AUDACITY_UPDATE_INFO-}" ]]; then
168    # Enable updates. See https://github.com/AppImage/AppImageSpec/blob/master/draft.md#update-information
169    appimagetool_args+=( --updateinformation="${AUDACITY_UPDATE_INFO}" )
170else
171    echo >&2 "$0: Automatic updates disabled"
172fi
173
174# Create AppImage
175cd "$(dirname "${appimage}")" # otherwise zsync created in wrong directory
176appimagetool "${appimagetool_args[@]}" "${appdir}" "${appimage}"
177