AppImage.sh 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. #! /bin/sh
  2. #
  3. # SPDX-License-Identifier: BSD-2-Clause
  4. #
  5. # Copyright 2019 Adriaan de Groot <groot@kde.org>
  6. #
  7. # Redistribution and use in source and binary forms, with or without
  8. # modification, are permitted provided that the following conditions
  9. # are met:
  10. #
  11. # 1. Redistributions of source code must retain the above copyright
  12. # notice, this list of conditions and the following disclaimer.
  13. # 2. Redistributions in binary form must reproduce the above copyright
  14. # notice, this list of conditions and the following disclaimer in the
  15. # documentation and/or other materials provided with the distribution.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  21. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. # POSSIBILITY OF SUCH DAMAGE.
  28. #
  29. ### END LICENSES
  30. ### USAGE
  31. #
  32. # Shell script to help build an AppImage for Calamares.
  33. #
  34. # Usage:
  35. # AppImage.sh [-T|--tools-dir <dir>]
  36. # [-C|--cmake-args <args>]
  37. # [-c|--config-dir <dir>]
  38. # [-s|--skip-build]
  39. # [-p|--with-python]
  40. #
  41. # Multiple --cmake-args arguments will be collected together and passed to
  42. # CMake before building the application.
  43. #
  44. # Use --tools-dir to indicate where the linuxdeploy tools are located.
  45. #
  46. # Use --config to copy a config-directory (with settings.conf and others)
  47. # into the resulting image,
  48. #
  49. # Option --skip-build assumes that there is an already-built Calamares
  50. # available in the AppImage build directory; use this when you are, e.g.
  51. # re-packaging the image with different configuration. Option --with-python
  52. # adds the Conda Python packaging ecosystem to the AppImage, which will make
  53. # it **more** portable by disconnecting from the system Python libraries.
  54. #
  55. # The build process for AppImage proceeds in a directory build-AppImage
  56. # that is created in the current directory.
  57. #
  58. # The resulting AppImage has XDG_* enabled, and appends the in-image
  59. # directories to the current environment. You can set XDG_* in the
  60. # current environment to use other configurations and data, e.g. the
  61. # data in the current live environment. Or leave it unset, to try
  62. # Calamares with only the configuration contained in the AppImage.
  63. #
  64. ### END USAGE
  65. TOOLS_DIR="."
  66. CMAKE_ARGS=""
  67. DO_REBUILD="true"
  68. DO_CONDA="false"
  69. CONFIG_DIR=""
  70. while test "$#" -gt 0
  71. do
  72. case "x$1" in
  73. x--help|x-h)
  74. sed -e '1,/USAGE/d' -e '/END.USAGE/,$d' < "$0"
  75. return 0
  76. ;;
  77. x--tools-dir|x-T)
  78. TOOLS_DIR="$2"
  79. shift
  80. ;;
  81. x--cmake-args|x-C)
  82. CMAKE_ARGS="$CMAKE_ARGS $2"
  83. shift
  84. ;;
  85. x--config-dir|x-c)
  86. CONFIG_DIR="$2"
  87. shift
  88. ;;
  89. x--skip-build|x-s)
  90. DO_REBUILD="false"
  91. ;;
  92. x--with-python|x-p)
  93. DO_CONDA="true"
  94. ;;
  95. *)
  96. echo "! Unknown argument '$1'."
  97. exit 1
  98. ;;
  99. esac
  100. test "$#" -gt 0 || { echo "! Missing arguments."; exit 1; }
  101. shift
  102. done
  103. ### Check where we're running
  104. #
  105. BIN_DIR=$( cd $( dirname "$0" ) && pwd -P )
  106. test -d "$BIN_DIR" || { echo "! Could not find BIN_DIR"; exit 1; }
  107. test -f "$BIN_DIR/AppImage.sh" || { echo "! $BIN_DIR does not have AppImage.sh"; exit 1; }
  108. SRC_DIR=$( cd "$BIN_DIR/.." && pwd -P )
  109. test -d "$SRC_DIR" || { echo "! Could not find SRC_DIR"; exit 1; }
  110. test -d "$SRC_DIR/ci" || { echo "! $SRC_DIR isn't a top-level Calamares checkout"; exit 1; }
  111. test -f "$SRC_DIR/CMakeLists.txt" || { echo "! SRC_DIR is missing CMakeLists.txt"; exit 1; }
  112. ### Check pre-requisites
  113. #
  114. BUILD_DIR=build-AppImage
  115. test -d "$BUILD_DIR" || mkdir -p "$BUILD_DIR"
  116. test -d "$BUILD_DIR" || { echo "! Could not create $BUILD_DIR"; exit 1; }
  117. TOOLS_LIST="linuxdeploy-x86_64.AppImage linuxdeploy-plugin-qt-x86_64.AppImage"
  118. $DO_CONDA && TOOLS_LIST="$TOOLS_LIST linuxdeploy-plugin-conda.sh"
  119. for tool in $TOOLS_LIST
  120. do
  121. if test -x "$BUILD_DIR/$tool" ; then
  122. # This tool is ok
  123. :
  124. else
  125. if test -f "$TOOLS_DIR/$tool" ; then
  126. cp "$TOOLS_DIR/$tool" "$BUILD_DIR/$tool" || exit 1
  127. else
  128. fetch=$( grep "^# URL .*$tool\$" "$0" | sed 's/# URL *//' )
  129. curl -L -o "$BUILD_DIR/$tool" "$fetch"
  130. fi
  131. chmod +x "$BUILD_DIR/$tool"
  132. test -x "$BUILD_DIR/$tool" || { echo "! Missing tool $tool in tools-dir $TOOLS_DIR"; exit 1; }
  133. fi
  134. done
  135. if test -n "$CONFIG_DIR" ; then
  136. test -f "$CONFIG_DIR/settings.conf" || { echo "! No settings.conf in $CONFIG_DIR"; exit 1; }
  137. fi
  138. ### Clean up build-directory
  139. #
  140. rm -rf "$BUILD_DIR/AppDir"
  141. if $DO_REBUILD ; then
  142. rm -rf "$BUILD_DIR/build"
  143. mkdir "$BUILD_DIR/build" || { echo "! Could not create $BUILD_DIR/build for the cmake-build."; exit 1; }
  144. else
  145. test -d "$BUILD_DIR/build" || { echo "! No build found in $BUILD_DIR, but --skip-build is given."; exit 1; }
  146. test -x "$BUILD_DIR/build/calamares" || { echo "! No complete build found in $BUILD_DIR/build ."; exit 1; }
  147. fi
  148. mkdir "$BUILD_DIR/AppDir" || { echo "! Could not create $BUILD_DIR/AppDir for the AppImage install."; exit 1; }
  149. LOG_FILE="$BUILD_DIR/AppImage.log"
  150. rm -f "$LOG_FILE"
  151. { echo "# Calamares build started" `date` ; echo "# .. build directory $BUILD_DIR"; echo "# .. log file $LOG_FILE"; } > "$LOG_FILE"
  152. cat "$LOG_FILE"
  153. ### Python Support
  154. #
  155. #
  156. if $DO_CONDA ; then
  157. export CONDA_CHANNELS="conda-forge;anaconda"
  158. export CONDA_PACKAGES="gettext;py-boost"
  159. (
  160. cd "$BUILD_DIR" &&
  161. ./linuxdeploy-x86_64.AppImage --appdir=AppDir/ --plugin=conda
  162. )
  163. . "$BUILD_DIR/AppDir/usr/conda/bin/activate"
  164. fi
  165. ### Build Calamares
  166. #
  167. if $DO_REBUILD ; then
  168. echo "# Running cmake ..."
  169. (
  170. cd "$BUILD_DIR/build" &&
  171. cmake "$SRC_DIR" -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib $CMAKE_ARGS
  172. ) >> "$LOG_FILE" 2>&1 || { tail -10 "$LOG_FILE" ; echo "! Could not run CMake"; exit 1; }
  173. echo "# Running make ..."
  174. (
  175. cd "$BUILD_DIR/build" &&
  176. make -j4
  177. ) >> "$LOG_FILE" 2>&1 || { tail -10 "$LOG_FILE" ; echo "! Could not run make"; exit 1; }
  178. fi
  179. echo "# Running make install ..."
  180. (
  181. cd "$BUILD_DIR/build" &&
  182. make install DESTDIR=../AppDir
  183. ) >> "$LOG_FILE" 2>&1 || { tail -10 "$LOG_FILE" ; echo "! Could not run make install"; exit 1; }
  184. ### Modify installation
  185. #
  186. IMAGE_DIR="$BUILD_DIR/AppDir"
  187. # Munge the desktop file to not use absolute paths or pkexec
  188. sed -i \
  189. -e 's+^Exec=.*+Exec=calamares+' \
  190. -e 's+^Name=.*+Name=Calamares+' \
  191. "$IMAGE_DIR"/usr/share/applications/calamares.desktop
  192. # Replace the executable with a shell-proxy
  193. test -x "$IMAGE_DIR/usr/bin/calamares" || { echo "! Does not seem to have installed calamares"; exit 1; }
  194. mv "$IMAGE_DIR/usr/bin/calamares" "$IMAGE_DIR/usr/bin/calamares.bin"
  195. cat > "$IMAGE_DIR/usr/bin/calamares" <<"EOF"
  196. #! /bin/sh
  197. #
  198. # Calamares proxy-script. Runs Calamares with XDG support enabled,
  199. # and in-image XDG dirs set up so that compiled-in configuration can be used.
  200. test -n "${XDG_DATA_DIRS}" && XDG_DATA_DIRS="${XDG_DATA_DIRS}:"
  201. test -n "${XDG_CONFIG_DIRS}" $$ XDG_CONFIG_DIRS="${XDG_CONFIG_DIRS}:"
  202. export XDG_DATA_DIRS="${XDG_DATA_DIRS}${APPDIR}/usr/share/"
  203. export XDG_CONFIG_DIRS="${XDG_CONFIG_DIRS}${APPDIR}/etc/:${APPDIR}/usr/share/"
  204. export PYTHONPATH="${APPDIR}/usr/lib:"
  205. cd "$APPDIR"
  206. exec "$APPDIR"/usr/bin/calamares.bin -X "$@"
  207. EOF
  208. chmod 755 "$IMAGE_DIR/usr/bin/calamares"
  209. test -x "$IMAGE_DIR/usr/bin/calamares" || { echo "! Does not seem to have proxy for calamares"; exit 1; }
  210. ### Install additional files
  211. #
  212. PLUGIN_DIR=$( qmake -query QT_INSTALL_PLUGINS )
  213. for plugin in \
  214. libpmsfdiskbackendplugin.so \
  215. libpmdummybackendplugin.so \
  216. libpmlibpartedbackendplugin.so
  217. do
  218. # Warning, but not fatal: generally you only have two out of three available
  219. # depending on the KPMCore version.
  220. cp "$PLUGIN_DIR/$plugin" "$IMAGE_DIR/usr/lib" 2> /dev/null || { echo "! Could not copy KPMCore plugin $plugin"; }
  221. done
  222. # Install configuration files
  223. ETC_DIR="$IMAGE_DIR"/etc/calamares
  224. mkdir -p "$ETC_DIR"
  225. test -d "$ETC_DIR" || { echo "! Could not create /etc/calamares in image."; exit 1; }
  226. if test -z "$CONFIG_DIR" ; then
  227. echo "# Using basic settings.conf"
  228. cp "$SRC_DIR/settings.conf" "$ETC_DIR"
  229. else
  230. test -f "$CONFIG_DIR/settings.conf" || { echo "! No settings.conf in $CONFIG_DIR"; exit 1; }
  231. mkdir -p "$ETC_DIR/modules"
  232. cp "$CONFIG_DIR/settings.conf" "$ETC_DIR"
  233. test -d "$CONFIG_DIR/modules" && cp -r "$CONFIG_DIR/modules" "$ETC_DIR"
  234. test -d "$CONFIG_DIR/branding" && cp -r "$CONFIG_DIR/branding" "$IMAGE_DIR/usr/share/calamares"
  235. fi
  236. ### Build the AppImage
  237. #
  238. #
  239. echo "# Building AppImage"
  240. (
  241. export QT_SELECT=qt5 # Otherwise might pick Qt4 in image
  242. export LD_LIBRARY_PATH=AppDir/usr/lib # RPATH isn't set in the executable
  243. cd "$BUILD_DIR" &&
  244. ./linuxdeploy-x86_64.AppImage --appdir=AppDir/ --plugin=qt --output=appimage
  245. ) >> "$LOG_FILE" 2>&1 || { tail -10 "$LOG_FILE" ; echo "! Could not create image"; exit 1; }
  246. echo "# Created in $BUILD_DIR/Calamares-x86_64.AppImage"
  247. echo "# .. log file at $LOG_FILE"
  248. exit 0
  249. ### Database for installation
  250. #
  251. # URL https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
  252. # URL https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
  253. # URL https://raw.githubusercontent.com/TheAssassin/linuxdeploy-plugin-conda/master/linuxdeploy-plugin-conda.sh