|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +# THIS SCRIPT IS TO BE RUN IN OUR DEV SHELL |
| 4 | + |
| 5 | +# The goal of this script is to prepare an `AppDir` (see the spec below) |
| 6 | +# and then to launch the appimagetool to create an AppImage. |
| 7 | +# |
| 8 | +# AppDir spec: https://github.com/AppImage/AppImageSpec/blob/master/draft.md#appdir |
| 9 | +# appimagetool: https://github.com/AppImage/appimagetool |
| 10 | + |
| 11 | +set -euo pipefail |
| 12 | + |
| 13 | +cleanup() { |
| 14 | + echo "Performing cleanup..." |
| 15 | + rm -rf ./squashfs-root |
| 16 | +} |
| 17 | + |
| 18 | +trap cleanup EXIT |
| 19 | + |
| 20 | +ROOT_PATH=$(git rev-parse --show-toplevel) |
| 21 | +export ROOT_PATH |
| 22 | + |
| 23 | +APP_DIR="${ROOT_PATH}/squashfs-root" |
| 24 | +export APP_DIR |
| 25 | + |
| 26 | +if [ -e "${ROOT_PATH}/CodeTracer.AppImage" ]; then |
| 27 | + rm -rf "${ROOT_PATH}/CodeTracer.AppImage" |
| 28 | +fi |
| 29 | + |
| 30 | +rm -rf "${APP_DIR}" |
| 31 | +mkdir -p "${APP_DIR}/"{bin,src,lib,views} |
| 32 | + |
| 33 | +# This environment variable controls where build artifacts and static resources end up. |
| 34 | +export NIX_CODETRACER_EXE_DIR="${APP_DIR}" |
| 35 | + |
| 36 | +CURRENT_NIX_SYSTEM=$(nix eval --impure --raw --expr 'builtins.currentSystem') |
| 37 | +APPIMAGE_DEPS=$(nix build "${ROOT_PATH}#packages.${CURRENT_NIX_SYSTEM}.appimageDeps" --no-link --print-out-paths | tail -n1) |
| 38 | + |
| 39 | +copy_lib_from_derivation() { |
| 40 | + local lib_name=$1 |
| 41 | + local copied=false |
| 42 | + |
| 43 | + if [ -f "${APPIMAGE_DEPS}/lib/${lib_name}" ]; then |
| 44 | + cp -L "${APPIMAGE_DEPS}/lib/${lib_name}" "${APP_DIR}/lib/" |
| 45 | + copied=true |
| 46 | + fi |
| 47 | + |
| 48 | + if [ -f "${APPIMAGE_DEPS}/lib64/${lib_name}" ]; then |
| 49 | + cp -L "${APPIMAGE_DEPS}/lib64/${lib_name}" "${APP_DIR}/lib/" |
| 50 | + copied=true |
| 51 | + fi |
| 52 | + |
| 53 | + if [ "${copied}" = false ]; then |
| 54 | + return 1 |
| 55 | + fi |
| 56 | + |
| 57 | + return 0 |
| 58 | +} |
| 59 | + |
| 60 | +copy_required_lib() { |
| 61 | + local lib_name=$1 |
| 62 | + if ! copy_lib_from_derivation "${lib_name}"; then |
| 63 | + echo "Required library ${lib_name} is missing from ${APPIMAGE_DEPS}" >&2 |
| 64 | + exit 1 |
| 65 | + fi |
| 66 | +} |
| 67 | + |
| 68 | +copy_optional_lib() { |
| 69 | + local lib_name=$1 |
| 70 | + if ! copy_lib_from_derivation "${lib_name}"; then |
| 71 | + echo "Optional library ${lib_name} not found; continuing." >&2 |
| 72 | + fi |
| 73 | +} |
| 74 | + |
| 75 | +copy_binary_from_derivation() { |
| 76 | + local binary_name=$1 |
| 77 | + local destination="${APP_DIR}/bin/${binary_name}" |
| 78 | + |
| 79 | + if [ ! -f "${APPIMAGE_DEPS}/bin/${binary_name}" ]; then |
| 80 | + echo "Required binary ${binary_name} is missing from ${APPIMAGE_DEPS}" >&2 |
| 81 | + exit 1 |
| 82 | + fi |
| 83 | + |
| 84 | + cp -L "${APPIMAGE_DEPS}/bin/${binary_name}" "${destination}" |
| 85 | +} |
| 86 | + |
| 87 | +# Copy shared libraries that were previously fetched via individual nix build/eval calls. |
| 88 | +copy_required_lib "libsqlite3.so.0" |
| 89 | +copy_optional_lib "libsqlite3.so" |
| 90 | +copy_required_lib "libpcre.so.1" |
| 91 | +copy_required_lib "libzip.so.5" |
| 92 | +copy_required_lib "libssl.so.3" |
| 93 | +copy_optional_lib "libssl.so" |
| 94 | +copy_required_lib "libcrypto.so.3" |
| 95 | +copy_optional_lib "libcrypto.so" |
| 96 | +copy_required_lib "libuv.so.1" |
| 97 | + |
| 98 | +# Copy binaries sourced from Nix packages. |
| 99 | +copy_binary_from_derivation "wazero" |
| 100 | +copy_binary_from_derivation "cargo-stylus" |
| 101 | +copy_binary_from_derivation "nargo" |
| 102 | +copy_binary_from_derivation "ctags" |
| 103 | +copy_binary_from_derivation "curl" |
| 104 | +copy_binary_from_derivation "node" |
| 105 | + |
| 106 | +# Install Ruby |
| 107 | +bash "${ROOT_PATH}/appimage-scripts/install_ruby.sh" |
| 108 | + |
| 109 | +cat <<'EOF' >"${APP_DIR}/bin/ruby" |
| 110 | +#!/usr/bin/env bash |
| 111 | +
|
| 112 | +HERE="${HERE:-..}" |
| 113 | +
|
| 114 | +# TODO: This includes references to x86_64. What about aarch64? |
| 115 | +export RUBYLIB="${HERE}/ruby/lib/ruby/3.3.0:${HERE}/ruby/lib/ruby/3.3.0/x86_64-linux:${RUBYLIB}" |
| 116 | +
|
| 117 | +"${HERE}/ruby/bin/ruby" "$@" |
| 118 | +
|
| 119 | +EOF |
| 120 | + |
| 121 | +# ruby recorder |
| 122 | +cp -Lr "${ROOT_PATH}/libs/codetracer-ruby-recorder" "${APP_DIR}/" |
| 123 | + |
| 124 | +# Copy over electron |
| 125 | +# bash "${ROOT_PATH}/appimage-scripts/install_electron_nix.sh" |
| 126 | +bash "${ROOT_PATH}/appimage-scripts/install_electron.sh" |
| 127 | + |
| 128 | +# Setup node deps |
| 129 | +bash "${ROOT_PATH}/appimage-scripts/setup_node_deps.sh" |
| 130 | + |
| 131 | +# Build our css files |
| 132 | +bash "${ROOT_PATH}/appimage-scripts/build_css.sh" |
| 133 | + |
| 134 | +# Build/setup nim-based files |
| 135 | +bash "${ROOT_PATH}/appimage-scripts/build_with_nim.sh" |
| 136 | + |
| 137 | +cat <<'EOF' >"${APP_DIR}/bin/ct" |
| 138 | +#!/usr/bin/env bash |
| 139 | +
|
| 140 | +HERE=${HERE:-$(dirname "$(readlink -f "${0}")")} |
| 141 | +
|
| 142 | +# TODO: This includes references to x86_64. What about aarch64? |
| 143 | +
|
| 144 | +exec "${HERE}/bin/ct_unwrapped" "$@" |
| 145 | +
|
| 146 | +EOF |
| 147 | + |
| 148 | +# Build/setup db-backend |
| 149 | +bash "${ROOT_PATH}/appimage-scripts/build_db_backend.sh" |
| 150 | + |
| 151 | +# Build/setup backend-manager |
| 152 | +bash "${ROOT_PATH}/appimage-scripts/build_backend_manager.sh" |
| 153 | + |
| 154 | +# Ensure copied binaries are executable. |
| 155 | +chmod +x "${APP_DIR}/bin/"{cargo-stylus,ctags,curl,nargo,node,wazero} |
| 156 | + |
| 157 | +# Collect transitive shared library dependencies from Nix store. |
| 158 | +# shellcheck disable=SC2046 |
| 159 | +cp -n $(lddtree -l "${APP_DIR}/bin/ctags" | grep -v glibc | grep /nix) "${APP_DIR}/lib" |
| 160 | + |
| 161 | +# shellcheck disable=SC2046 |
| 162 | +cp -n $(lddtree -l "${APP_DIR}/bin/curl" | grep -v glibc | grep /nix) "${APP_DIR}/lib" |
| 163 | + |
| 164 | +# shellcheck disable=SC2046 |
| 165 | +cp -n $(lddtree -l "${APP_DIR}/bin/node" | grep -v glibc | grep /nix) "${APP_DIR}/lib" |
| 166 | + |
| 167 | +# shellcheck disable=SC2046 |
| 168 | +cp -n $(lddtree -l "${APP_DIR}/bin/cargo-stylus" | grep -v glibc | grep /nix) "${APP_DIR}/lib" |
| 169 | + |
| 170 | +chmod -R +x "${APP_DIR}/bin" |
| 171 | +chmod -R +x "${APP_DIR}/electron" |
| 172 | + |
| 173 | +chmod -R 777 "${APP_DIR}" |
| 174 | + |
| 175 | +cp "${ROOT_PATH}/src/helpers.js" "${APP_DIR}/src/helpers.js" |
| 176 | +cp "${ROOT_PATH}/src/helpers.js" "${APP_DIR}/helpers.js" |
| 177 | + |
| 178 | +cp "${ROOT_PATH}/src/frontend/index.html" "${APP_DIR}/src/index.html" |
| 179 | +cp "${ROOT_PATH}/src/frontend/index.html" "${APP_DIR}/index.html" |
| 180 | + |
| 181 | +cp "${ROOT_PATH}/src/frontend/subwindow.html" "${APP_DIR}/subwindow.html" |
| 182 | +cp "${ROOT_PATH}/src/frontend/subwindow.html" "${APP_DIR}/src/subwindow.html" |
| 183 | + |
| 184 | +cp "${ROOT_PATH}/views/server_index.ejs" "${APP_DIR}/views/server_index.ejs" |
| 185 | + |
| 186 | +rm -rf "${APP_DIR}/config" |
| 187 | +rm -rf "${APP_DIR}/public" |
| 188 | +cp -Lr "${ROOT_PATH}/src/config" "${APP_DIR}/config" |
| 189 | + |
| 190 | +# Enable the installation prompt |
| 191 | +sed -i "s/skipInstall.*/skipInstall: false/g" "${APP_DIR}/config/default_config.yaml" |
| 192 | + |
| 193 | +cp -Lr "${ROOT_PATH}/src/public" "${APP_DIR}/public" |
| 194 | +chmod -R +wr "${APP_DIR}/public" |
| 195 | + |
| 196 | +cp -Lr "${ROOT_PATH}/src/public/dist/frontend_bundle.js" "${APP_DIR}" |
| 197 | + |
| 198 | +# Create AppRun script |
| 199 | +cat <<'EOF' >"${APP_DIR}/AppRun" |
| 200 | +#!/usr/bin/env bash |
| 201 | +
|
| 202 | +export HERE=$(dirname "$(readlink -f "${0}")") |
| 203 | +
|
| 204 | +# TODO: This includes references to x86_64. What about aarch64? |
| 205 | +export LINKS_PATH_DIR=$HERE |
| 206 | +export PATH="${HERE}/bin:${PATH}" |
| 207 | +export CODETRACER_RUBY_RECORDER_PATH="${HERE}/codetracer-ruby-recorder/gems/codetracer-pure-ruby-recorder/bin/codetracer-pure-ruby-recorder" |
| 208 | +
|
| 209 | +exec ${HERE}/bin/ct "$@" |
| 210 | +EOF |
| 211 | + |
| 212 | +chmod +x "${APP_DIR}/AppRun" |
| 213 | + |
| 214 | +# Copy over desktop file |
| 215 | +cp "${ROOT_PATH}/resources/codetracer.desktop" "${APP_DIR}/" |
| 216 | + |
| 217 | +# Copy over resources |
| 218 | +cp -Lr "${ROOT_PATH}/resources" "${APP_DIR}" |
| 219 | + |
| 220 | +SRC_ICONSET_DIR="${ROOT_PATH}/resources/Icon.iconset" |
| 221 | + |
| 222 | +# TODO: discover these dynamically perhaps |
| 223 | +for SIZE in 16 32 128 256 512; do |
| 224 | + XSIZE="${SIZE}x${SIZE}" |
| 225 | + DST_PATH="${APP_DIR}/usr/share/icons/hicolor/${XSIZE}/apps/" |
| 226 | + DOUBLE_SIZE_DST_PATH="${APP_DIR}/usr/share/icons/hicolor/${XSIZE}@2/apps/" |
| 227 | + mkdir -p "${DST_PATH}" "${DOUBLE_SIZE_DST_PATH}" |
| 228 | + cp "${SRC_ICONSET_DIR}/icon_${XSIZE}.png" "${DST_PATH}/codetracer.png" |
| 229 | + cp "${SRC_ICONSET_DIR}/icon_${XSIZE}@2x.png" "${DOUBLE_SIZE_DST_PATH}/codetracer.png" |
| 230 | +done |
| 231 | + |
| 232 | +cp "${ROOT_PATH}/resources/Icon.iconset/icon_256x256.png" "${APP_DIR}/codetracer.png" |
| 233 | + |
| 234 | +CURRENT_ARCH=$(uname -m) |
| 235 | +if [[ "${CURRENT_ARCH}" == "aarch64" ]]; then |
| 236 | + INTERPRETER_PATH=/lib/ld-linux-aarch64.so.1 |
| 237 | +else |
| 238 | + INTERPRETER_PATH=/lib64/ld-linux-x86-64.so.2 |
| 239 | +fi |
| 240 | + |
| 241 | +# Patchelf the executable's interpreter |
| 242 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/bin/ct_unwrapped" |
| 243 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/bin/db-backend" |
| 244 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/bin/db-backend-record" |
| 245 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/bin/backend-manager" |
| 246 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/bin/nargo" |
| 247 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/bin/wazero" |
| 248 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/bin/ctags" |
| 249 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/bin/curl" |
| 250 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/bin/cargo-stylus" |
| 251 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/bin/node" |
| 252 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}/ruby/bin/ruby" |
| 253 | + |
| 254 | +# Clear up the executable's rpath |
| 255 | +patchelf --remove-rpath "${APP_DIR}/bin/ct_unwrapped" |
| 256 | +patchelf --remove-rpath "${APP_DIR}/bin/db-backend" |
| 257 | +patchelf --remove-rpath "${APP_DIR}/bin/db-backend-record" |
| 258 | +patchelf --remove-rpath "${APP_DIR}/bin/backend-manager" |
| 259 | +patchelf --remove-rpath "${APP_DIR}/bin/nargo" |
| 260 | +patchelf --remove-rpath "${APP_DIR}/bin/wazero" |
| 261 | +patchelf --remove-rpath "${APP_DIR}/bin/ctags" |
| 262 | +patchelf --remove-rpath "${APP_DIR}/bin/curl" |
| 263 | +patchelf --remove-rpath "${APP_DIR}/bin/cargo-stylus" |
| 264 | +patchelf --remove-rpath "${APP_DIR}/bin/node" |
| 265 | +patchelf --remove-rpath "${APP_DIR}/ruby/bin/ruby" |
| 266 | + |
| 267 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/bin/node" |
| 268 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/bin/ct_unwrapped" |
| 269 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/bin/db-backend" |
| 270 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/bin/db-backend-record" |
| 271 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/bin/backend-manager" |
| 272 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/bin/nargo" |
| 273 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/bin/wazero" |
| 274 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/bin/ctags" |
| 275 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/bin/curl" |
| 276 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/bin/node" |
| 277 | +patchelf --set-rpath "\$ORIGIN/../lib" "${APP_DIR}/ruby/bin/ruby" |
| 278 | + |
| 279 | +APPIMAGE_ARCH=${CURRENT_ARCH} |
| 280 | +if [[ "${APPIMAGE_ARCH}" == "aarch64" ]]; then |
| 281 | + # The appimagetool has its own convention for specifying the ARM64 arch. |
| 282 | + APPIMAGE_ARCH=arm_aarch64 |
| 283 | +fi |
| 284 | + |
| 285 | +# Use AppImage tool to create AppImage itself |
| 286 | +ARCH=${APPIMAGE_ARCH} appimagetool "${APP_DIR}" CodeTracer.AppImage |
| 287 | + |
| 288 | +patchelf --set-interpreter "${INTERPRETER_PATH}" "${ROOT_PATH}/CodeTracer.AppImage" |
| 289 | +patchelf --remove-rpath "${ROOT_PATH}/CodeTracer.AppImage" |
| 290 | + |
| 291 | +echo "============================" |
| 292 | +echo "AppImage successfully built!" |
| 293 | +echo "============================" |
0 commit comments