Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

build.sh 10 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. #!/bin/bash -e
  2. # shellcheck disable=SC2119
  3. run_sub_stage()
  4. {
  5. log "Begin ${SUB_STAGE_DIR}"
  6. pushd "${SUB_STAGE_DIR}" > /dev/null
  7. for i in {00..99}; do
  8. if [ -f "${i}-debconf" ]; then
  9. log "Begin ${SUB_STAGE_DIR}/${i}-debconf"
  10. on_chroot << EOF
  11. debconf-set-selections <<SELEOF
  12. $(cat "${i}-debconf")
  13. SELEOF
  14. EOF
  15. log "End ${SUB_STAGE_DIR}/${i}-debconf"
  16. fi
  17. if [ -f "${i}-packages-nr" ]; then
  18. log "Begin ${SUB_STAGE_DIR}/${i}-packages-nr"
  19. PACKAGES="$(sed -f "${SCRIPT_DIR}/remove-comments.sed" < "${i}-packages-nr")"
  20. if [ -n "$PACKAGES" ]; then
  21. on_chroot << EOF
  22. n=0
  23. until [ "$n" -ge 5 ]
  24. do
  25. apt-get --ignore-missing --fix-missing install --no-install-recommends -y $PACKAGES && break
  26. n=$((n+1))
  27. sleep 15
  28. done
  29. EOF
  30. if [ "${USE_QCOW2}" = "1" ]; then
  31. on_chroot << EOF
  32. apt-get clean
  33. EOF
  34. fi
  35. fi
  36. log "End ${SUB_STAGE_DIR}/${i}-packages-nr"
  37. fi
  38. if [ -f "${i}-packages" ]; then
  39. log "Begin ${SUB_STAGE_DIR}/${i}-packages"
  40. PACKAGES="$(sed -f "${SCRIPT_DIR}/remove-comments.sed" < "${i}-packages")"
  41. if [ -n "$PACKAGES" ]; then
  42. on_chroot << EOF
  43. n=0
  44. until [ "$n" -ge 5 ]
  45. do
  46. apt-get --ignore-missing --fix-missing install -y $PACKAGES && break
  47. n=$((n+1))
  48. sleep 15
  49. done
  50. EOF
  51. if [ "${USE_QCOW2}" = "1" ]; then
  52. on_chroot << EOF
  53. apt-get clean
  54. EOF
  55. fi
  56. fi
  57. log "End ${SUB_STAGE_DIR}/${i}-packages"
  58. fi
  59. if [ -d "${i}-patches" ]; then
  60. log "Begin ${SUB_STAGE_DIR}/${i}-patches"
  61. pushd "${STAGE_WORK_DIR}" > /dev/null
  62. if [ "${CLEAN}" = "1" ]; then
  63. rm -rf .pc
  64. rm -rf ./*-pc
  65. fi
  66. QUILT_PATCHES="${SUB_STAGE_DIR}/${i}-patches"
  67. SUB_STAGE_QUILT_PATCH_DIR="$(basename "$SUB_STAGE_DIR")-pc"
  68. mkdir -p "$SUB_STAGE_QUILT_PATCH_DIR"
  69. ln -snf "$SUB_STAGE_QUILT_PATCH_DIR" .pc
  70. quilt upgrade
  71. if [ -e "${SUB_STAGE_DIR}/${i}-patches/EDIT" ]; then
  72. echo "Dropping into bash to edit patches..."
  73. bash
  74. fi
  75. RC=0
  76. quilt push -a || RC=$?
  77. case "$RC" in
  78. 0|2)
  79. ;;
  80. *)
  81. false
  82. ;;
  83. esac
  84. popd > /dev/null
  85. log "End ${SUB_STAGE_DIR}/${i}-patches"
  86. fi
  87. if [ -x ${i}-run.sh ]; then
  88. log "Begin ${SUB_STAGE_DIR}/${i}-run.sh"
  89. ./${i}-run.sh
  90. log "End ${SUB_STAGE_DIR}/${i}-run.sh"
  91. fi
  92. if [ -f ${i}-run-chroot.sh ]; then
  93. log "Begin ${SUB_STAGE_DIR}/${i}-run-chroot.sh"
  94. on_chroot < ${i}-run-chroot.sh
  95. log "End ${SUB_STAGE_DIR}/${i}-run-chroot.sh"
  96. fi
  97. done
  98. popd > /dev/null
  99. log "End ${SUB_STAGE_DIR}"
  100. }
  101. run_stage(){
  102. log "Begin ${STAGE_DIR}"
  103. STAGE="$(basename "${STAGE_DIR}")"
  104. pushd "${STAGE_DIR}" > /dev/null
  105. STAGE_WORK_DIR="${WORK_DIR}/${STAGE}"
  106. ROOTFS_DIR="${STAGE_WORK_DIR}"/rootfs
  107. if [ "${USE_QCOW2}" = "1" ]; then
  108. if [ ! -f SKIP ]; then
  109. load_qimage
  110. fi
  111. else
  112. # make sure we are not umounting during export-image stage
  113. if [ "${USE_QCOW2}" = "0" ] && [ "${NO_PRERUN_QCOW2}" = "0" ]; then
  114. unmount "${WORK_DIR}/${STAGE}"
  115. fi
  116. fi
  117. if [ ! -f SKIP_IMAGES ]; then
  118. if [ -f "${STAGE_DIR}/EXPORT_IMAGE" ]; then
  119. EXPORT_DIRS="${EXPORT_DIRS} ${STAGE_DIR}"
  120. fi
  121. fi
  122. if [ ! -f SKIP ]; then
  123. if [ "${CLEAN}" = "1" ] && [ "${USE_QCOW2}" = "0" ] ; then
  124. if [ -d "${ROOTFS_DIR}" ]; then
  125. rm -rf "${ROOTFS_DIR}"
  126. fi
  127. fi
  128. if [ -x prerun.sh ]; then
  129. log "Begin ${STAGE_DIR}/prerun.sh"
  130. ./prerun.sh
  131. log "End ${STAGE_DIR}/prerun.sh"
  132. fi
  133. for SUB_STAGE_DIR in "${STAGE_DIR}"/*; do
  134. if [ -d "${SUB_STAGE_DIR}" ] && [ ! -f "${SUB_STAGE_DIR}/SKIP" ]; then
  135. run_sub_stage
  136. fi
  137. done
  138. fi
  139. if [ "${USE_QCOW2}" = "1" ]; then
  140. unload_qimage
  141. else
  142. # make sure we are not umounting during export-image stage
  143. if [ "${USE_QCOW2}" = "0" ] && [ "${NO_PRERUN_QCOW2}" = "0" ]; then
  144. unmount "${WORK_DIR}/${STAGE}"
  145. fi
  146. fi
  147. PREV_STAGE="${STAGE}"
  148. PREV_STAGE_DIR="${STAGE_DIR}"
  149. PREV_ROOTFS_DIR="${ROOTFS_DIR}"
  150. popd > /dev/null
  151. log "End ${STAGE_DIR}"
  152. }
  153. if [ "$(id -u)" != "0" ]; then
  154. echo "Please run as root" 1>&2
  155. exit 1
  156. fi
  157. BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  158. export BASE_DIR
  159. if [ -f config ]; then
  160. # shellcheck disable=SC1091
  161. source config
  162. fi
  163. while getopts "c:" flag
  164. do
  165. case "$flag" in
  166. c)
  167. EXTRA_CONFIG="$OPTARG"
  168. # shellcheck disable=SC1090
  169. source "$EXTRA_CONFIG"
  170. ;;
  171. *)
  172. ;;
  173. esac
  174. done
  175. term() {
  176. if [ "${USE_QCOW2}" = "1" ]; then
  177. log "Unloading image"
  178. unload_qimage
  179. fi
  180. }
  181. trap term EXIT INT TERM
  182. export PI_GEN=${PI_GEN:-pi-gen}
  183. export PI_GEN_REPO=${PI_GEN_REPO:-https://github.com/RPi-Distro/pi-gen}
  184. if [ -z "${IMG_NAME}" ]; then
  185. echo "IMG_NAME not set" 1>&2
  186. exit 1
  187. fi
  188. export USE_QEMU="${USE_QEMU:-0}"
  189. export IMG_DATE="${IMG_DATE:-"$(date +%Y-%m-%d)"}"
  190. export IMG_FILENAME="${IMG_FILENAME:-"${IMG_DATE}-${IMG_NAME}"}"
  191. export ZIP_FILENAME="${ZIP_FILENAME:-"${IMG_DATE}-${IMG_NAME}"}"
  192. export SCRIPT_DIR="${BASE_DIR}/scripts"
  193. export WORK_DIR="${WORK_DIR:-"${BASE_DIR}/work/${IMG_DATE}-${IMG_NAME}"}"
  194. export DEPLOY_DIR=${DEPLOY_DIR:-"${BASE_DIR}/deploy"}
  195. export DEPLOY_ZIP="${DEPLOY_ZIP:-1}"
  196. export LOG_FILE="${WORK_DIR}/build.log"
  197. export TARGET_HOSTNAME=${TARGET_HOSTNAME:-raspberrypi}
  198. export FIRST_USER_NAME=${FIRST_USER_NAME:-pi}
  199. export FIRST_USER_PASS=${FIRST_USER_PASS:-raspberry}
  200. export RELEASE=${RELEASE:-bullseye}
  201. export WPA_ESSID
  202. export WPA_PASSWORD
  203. export WPA_COUNTRY
  204. export ENABLE_SSH="${ENABLE_SSH:-0}"
  205. export PUBKEY_ONLY_SSH="${PUBKEY_ONLY_SSH:-0}"
  206. export LOCALE_DEFAULT="${LOCALE_DEFAULT:-en_GB.UTF-8}"
  207. export KEYBOARD_KEYMAP="${KEYBOARD_KEYMAP:-gb}"
  208. export KEYBOARD_LAYOUT="${KEYBOARD_LAYOUT:-English (UK)}"
  209. export TIMEZONE_DEFAULT="${TIMEZONE_DEFAULT:-Europe/London}"
  210. export GIT_HASH=${GIT_HASH:-"$(git rev-parse HEAD)"}
  211. export PUBKEY_SSH_FIRST_USER
  212. export CLEAN
  213. export IMG_NAME
  214. export APT_PROXY
  215. export STAGE
  216. export STAGE_DIR
  217. export STAGE_WORK_DIR
  218. export PREV_STAGE
  219. export PREV_STAGE_DIR
  220. export ROOTFS_DIR
  221. export PREV_ROOTFS_DIR
  222. export IMG_SUFFIX
  223. export NOOBS_NAME
  224. export NOOBS_DESCRIPTION
  225. export EXPORT_DIR
  226. export EXPORT_ROOTFS_DIR
  227. export QUILT_PATCHES
  228. export QUILT_NO_DIFF_INDEX=1
  229. export QUILT_NO_DIFF_TIMESTAMPS=1
  230. export QUILT_REFRESH_ARGS="-p ab"
  231. # shellcheck source=scripts/common
  232. source "${SCRIPT_DIR}/common"
  233. # shellcheck source=scripts/dependencies_check
  234. source "${SCRIPT_DIR}/dependencies_check"
  235. export NO_PRERUN_QCOW2="${NO_PRERUN_QCOW2:-1}"
  236. export USE_QCOW2="${USE_QCOW2:-0}"
  237. export BASE_QCOW2_SIZE=${BASE_QCOW2_SIZE:-12G}
  238. source "${SCRIPT_DIR}/qcow2_handling"
  239. if [ "${USE_QCOW2}" = "1" ]; then
  240. NO_PRERUN_QCOW2=1
  241. else
  242. NO_PRERUN_QCOW2=0
  243. fi
  244. export NO_PRERUN_QCOW2="${NO_PRERUN_QCOW2:-1}"
  245. dependencies_check "${BASE_DIR}/depends"
  246. #check username is valid
  247. if [[ ! "$FIRST_USER_NAME" =~ ^[a-z][-a-z0-9_]*$ ]]; then
  248. echo "Invalid FIRST_USER_NAME: $FIRST_USER_NAME"
  249. exit 1
  250. fi
  251. if [[ -n "${APT_PROXY}" ]] && ! curl --silent "${APT_PROXY}" >/dev/null ; then
  252. echo "Could not reach APT_PROXY server: ${APT_PROXY}"
  253. exit 1
  254. fi
  255. if [[ -n "${WPA_PASSWORD}" && ${#WPA_PASSWORD} -lt 8 || ${#WPA_PASSWORD} -gt 63 ]] ; then
  256. echo "WPA_PASSWORD" must be between 8 and 63 characters
  257. exit 1
  258. fi
  259. if [[ "${PUBKEY_ONLY_SSH}" = "1" && -z "${PUBKEY_SSH_FIRST_USER}" ]]; then
  260. echo "Must set 'PUBKEY_SSH_FIRST_USER' to a valid SSH public key if using PUBKEY_ONLY_SSH"
  261. exit 1
  262. fi
  263. mkdir -p "${WORK_DIR}"
  264. log "Begin ${BASE_DIR}"
  265. STAGE_LIST=${STAGE_LIST:-${BASE_DIR}/stage*}
  266. for STAGE_DIR in $STAGE_LIST; do
  267. STAGE_DIR=$(realpath "${STAGE_DIR}")
  268. run_stage
  269. done
  270. CLEAN=1
  271. for EXPORT_DIR in ${EXPORT_DIRS}; do
  272. STAGE_DIR=${BASE_DIR}/export-image
  273. # shellcheck source=/dev/null
  274. source "${EXPORT_DIR}/EXPORT_IMAGE"
  275. EXPORT_ROOTFS_DIR=${WORK_DIR}/$(basename "${EXPORT_DIR}")/rootfs
  276. if [ "${USE_QCOW2}" = "1" ]; then
  277. USE_QCOW2=0
  278. EXPORT_NAME="${IMG_FILENAME}${IMG_SUFFIX}"
  279. echo "------------------------------------------------------------------------"
  280. echo "Running export stage for ${EXPORT_NAME}"
  281. rm -f "${WORK_DIR}/export-image/${EXPORT_NAME}.img" || true
  282. rm -f "${WORK_DIR}/export-image/${EXPORT_NAME}.qcow2" || true
  283. rm -f "${WORK_DIR}/${EXPORT_NAME}.img" || true
  284. rm -f "${WORK_DIR}/${EXPORT_NAME}.qcow2" || true
  285. EXPORT_STAGE=$(basename "${EXPORT_DIR}")
  286. for s in $STAGE_LIST; do
  287. TMP_LIST=${TMP_LIST:+$TMP_LIST }$(basename "${s}")
  288. done
  289. FIRST_STAGE=${TMP_LIST%% *}
  290. FIRST_IMAGE="image-${FIRST_STAGE}.qcow2"
  291. pushd "${WORK_DIR}" > /dev/null
  292. echo "Creating new base "${EXPORT_NAME}.qcow2" from ${FIRST_IMAGE}"
  293. cp "./${FIRST_IMAGE}" "${EXPORT_NAME}.qcow2"
  294. ARR=($TMP_LIST)
  295. # rebase stage images to new export base
  296. for CURR_STAGE in "${ARR[@]}"; do
  297. if [ "${CURR_STAGE}" = "${FIRST_STAGE}" ]; then
  298. PREV_IMG="${EXPORT_NAME}"
  299. continue
  300. fi
  301. echo "Rebasing image-${CURR_STAGE}.qcow2 onto ${PREV_IMG}.qcow2"
  302. qemu-img rebase -f qcow2 -u -b ${PREV_IMG}.qcow2 image-${CURR_STAGE}.qcow2
  303. if [ "${CURR_STAGE}" = "${EXPORT_STAGE}" ]; then
  304. break
  305. fi
  306. PREV_IMG="image-${CURR_STAGE}"
  307. done
  308. # commit current export stage into base export image
  309. echo "Committing image-${EXPORT_STAGE}.qcow2 to ${EXPORT_NAME}.qcow2"
  310. qemu-img commit -f qcow2 -p -b "${EXPORT_NAME}.qcow2" image-${EXPORT_STAGE}.qcow2
  311. # rebase stage images back to original first stage for easy re-run
  312. for CURR_STAGE in "${ARR[@]}"; do
  313. if [ "${CURR_STAGE}" = "${FIRST_STAGE}" ]; then
  314. PREV_IMG="image-${CURR_STAGE}"
  315. continue
  316. fi
  317. echo "Rebasing back image-${CURR_STAGE}.qcow2 onto ${PREV_IMG}.qcow2"
  318. qemu-img rebase -f qcow2 -u -b ${PREV_IMG}.qcow2 image-${CURR_STAGE}.qcow2
  319. if [ "${CURR_STAGE}" = "${EXPORT_STAGE}" ]; then
  320. break
  321. fi
  322. PREV_IMG="image-${CURR_STAGE}"
  323. done
  324. popd > /dev/null
  325. mkdir -p "${WORK_DIR}/export-image/rootfs"
  326. mv "${WORK_DIR}/${EXPORT_NAME}.qcow2" "${WORK_DIR}/export-image/"
  327. echo "Mounting image ${WORK_DIR}/export-image/${EXPORT_NAME}.qcow2 to rootfs ${WORK_DIR}/export-image/rootfs"
  328. mount_qimage "${WORK_DIR}/export-image/${EXPORT_NAME}.qcow2" "${WORK_DIR}/export-image/rootfs"
  329. CLEAN=0
  330. run_stage
  331. CLEAN=1
  332. USE_QCOW2=1
  333. else
  334. run_stage
  335. fi
  336. if [ "${USE_QEMU}" != "1" ]; then
  337. if [ -e "${EXPORT_DIR}/EXPORT_NOOBS" ]; then
  338. # shellcheck source=/dev/null
  339. source "${EXPORT_DIR}/EXPORT_NOOBS"
  340. STAGE_DIR="${BASE_DIR}/export-noobs"
  341. if [ "${USE_QCOW2}" = "1" ]; then
  342. USE_QCOW2=0
  343. run_stage
  344. USE_QCOW2=1
  345. else
  346. run_stage
  347. fi
  348. fi
  349. fi
  350. done
  351. if [ -x postrun.sh ]; then
  352. log "Begin postrun.sh"
  353. cd "${BASE_DIR}"
  354. ./postrun.sh
  355. log "End postrun.sh"
  356. fi
  357. if [ "${USE_QCOW2}" = "1" ]; then
  358. unload_qimage
  359. fi
  360. log "End ${BASE_DIR}"