common 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. #!/usr/bin/env bash
  2. # Copyright (C) 2016 Paul Kocialkowski <contact@paulk.fr>
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. BUILD_SYSTEM="libreboot"
  17. PROJECTS="projects"
  18. SOURCES="sources"
  19. BUILD="build"
  20. INSTALL="install"
  21. RELEASE="release"
  22. SYSTEMS="systems"
  23. IMAGES="images"
  24. TOOLS="tools"
  25. CONFIGS="configs"
  26. PATCHES="patches"
  27. TARGETS="targets"
  28. REVISION="revision"
  29. VARIANTS="variants"
  30. BLOBS="blobs"
  31. BLOBS_IGNORE="blobs-ignore"
  32. BLOBS_DISCOVER="blobs-discover"
  33. DEPENDENCIES="dependencies"
  34. DOTEPOCH=".epoch"
  35. DOTRNDSEED=".rndseed"
  36. DOTVERSION=".version"
  37. DOTREVISION=".revision"
  38. DOTTARFILES=".tarfiles"
  39. ARCHIVE="tar.xz"
  40. CHECKSUM="sha256sum"
  41. DSIG="asc"
  42. CONFIG_SHELL="${CONFIG_SHELL:-$(which bash)}"
  43. EDITOR="${EDITOR:-$(which vi || true)}"
  44. TASKS="${TASKS:-1}"
  45. function_check() {
  46. local function=$1
  47. declare -f -F "$function" > /dev/null
  48. }
  49. variable_check() {
  50. local variable=$1
  51. test ! -z "${!variable}"
  52. }
  53. arguments_list() {
  54. local argument
  55. for argument in "$@"
  56. do
  57. printf '%s\n' "$argument"
  58. done
  59. }
  60. download_wrapper() {
  61. local download_dir="$1"
  62. shift
  63. local uris=($@)
  64. local wget_options=(
  65. '--config=/dev/null'
  66. '--secure-protocol=PFS'
  67. "--directory-prefix=$download_dir"
  68. '--continue'
  69. '--'
  70. )
  71. local curl_options=(
  72. '-q'
  73. '--continue-at -'
  74. '--remote-name'
  75. '--retry 20'
  76. '--ssl'
  77. '--tlsv1.2'
  78. '--'
  79. )
  80. if hash wget > /dev/null 2>&1; then
  81. wget "${wget_options[@]}" "${uris[@]}"
  82. elif hash curl > /dev/null 2>&1; then
  83. (
  84. cd "$download_dir"
  85. curl "${curl_options[@]}" "${uris[@]}"
  86. )
  87. else
  88. printf '\n%s\n\n' 'Error: Neither wget nor curl were found' 1>&2
  89. return 1
  90. fi
  91. }
  92. diff_patch() {
  93. local sources_path=$1
  94. local patch_path=$2
  95. patch -fd "$sources_path" -r - < "$patch_path"
  96. }
  97. diff_patch_check() {
  98. local sources_path=$1
  99. local patch_path=$2
  100. patch -sfd "$sources_path" --dry-run < "$patch_path" > /dev/null 2>&1
  101. }
  102. path_wildcard_expand() {
  103. local path=$@
  104. # Evaluation fails with unescaped whitespaces.
  105. path=$(printf '%s\n' "$path" | sed "s/ /\\\ /g")
  106. eval "arguments_list "$path""
  107. }
  108. file_checksum_create() {
  109. local path=$1
  110. local checksum_path="$path.$CHECKSUM"
  111. local name=$(basename "$path")
  112. local directory_path=$(dirname "$path")
  113. (
  114. cd "$directory_path"
  115. sha256sum "$name" > "$checksum_path"
  116. )
  117. }
  118. file_checksum_check() {
  119. local path=$1
  120. local checksum_path="$path.$CHECKSUM"
  121. local name=$(basename "$path")
  122. local directory_path=$(dirname "$path")
  123. if ! [[ -f "$checksum_path" ]]
  124. then
  125. printf 1>&2 '%s\n' 'Could not verify file checksum!'
  126. return 1
  127. fi
  128. (
  129. cd "$directory_path"
  130. sha256sum -c "$checksum_path"
  131. )
  132. }
  133. file_signature_create() {
  134. local path=$1
  135. local signature_path="$path.$DSIG"
  136. if [[ -z "$RELEASE_KEY" ]]
  137. then
  138. return 0
  139. fi
  140. gpg --default-key "$RELEASE_KEY" --armor --output "$signature_path" --detach-sign --yes "$path"
  141. }
  142. file_signature_check() {
  143. local path=$1
  144. local signature_path="$path.$DSIG"
  145. if ! [[ -f "$signature_path" ]]
  146. then
  147. printf 1>&2 '%s\n' 'Could not verify file signature!'
  148. return 1
  149. fi
  150. gpg --armor --verify "$signature_path" "$path"
  151. }
  152. file_verification_create() {
  153. local path=$1
  154. file_checksum_create "$path"
  155. file_signature_create "$path"
  156. }
  157. file_verification_check() {
  158. local path=$1
  159. file_checksum_check "$path"
  160. file_signature_check "$path"
  161. }
  162. file_exists_check() {
  163. local path=$1
  164. test -f "$path"
  165. }
  166. directory_filled_check() {
  167. local path=$1
  168. if [[ -z "$(ls -A "$path" 2> /dev/null)" ]]
  169. then
  170. return 1
  171. else
  172. return 0
  173. fi
  174. }
  175. archive_files_create() {
  176. local source_path="$1"
  177. local directory="$(basename "$source_path")"
  178. local tarfiles_path="$source_path/$DOTTARFILES"
  179. local revision_path="$source_path/$DOTREVISION"
  180. local version_path="$source_path/$DOTVERSION"
  181. local epoch_path="$source_path/$DOTEPOCH"
  182. local rnd_seed_path="$source_path/$DOTRNDSEED"
  183. # Files in "$tarfiles_path" are NUL terminated.
  184. # `tr '\0' '\n'` for human-readable output.
  185. if git_check "$source_path"; then
  186. git_files "$source_path" > "$tarfiles_path"
  187. printf '%s\0' "$DOTTARFILES" >> "$tarfiles_path"
  188. else
  189. find "$source_path" -print0 | env LC_ALL='C.UTF-8' sort -z | sed -z "1d;s,^$source_path/\\?,,;/^$DOTTARFILES\$/d" > "$tarfiles_path"
  190. fi
  191. for dotfile in "$revision_path" \
  192. "$version_path" \
  193. "$epoch_path" \
  194. "$rnd_seed_path"
  195. do
  196. if [[ -f "$dotfile" ]]; then
  197. printf '%s\0' ".${dotfile##*.}" >> "$tarfiles_path"
  198. fi
  199. done
  200. }
  201. archive_files_date() {
  202. local source_path="$1"
  203. local epoch_path="$source_path/$DOTEPOCH"
  204. if [[ -n "$SOURCE_DATE_EPOCH" ]]; then
  205. find "$source_path" -execdir touch --no-dereference --date="@$SOURCE_DATE_EPOCH" {} +
  206. fi
  207. }
  208. archive_create() {
  209. local archive_path="$1"
  210. local source_path="$2"
  211. local directory="$3"
  212. local tarfiles_path="$source_path/$DOTTARFILES"
  213. local directory_path="$(dirname "$archive_path")"
  214. mkdir -p "$directory_path"
  215. if [[ -z "$directory" ]]; then
  216. directory="$(basename "$source_path")"
  217. fi
  218. archive_files_create "$source_path"
  219. archive_files_date "$source_path"
  220. local tar_options=(
  221. --create
  222. --xz
  223. --file="$archive_path"
  224. --files-from="$tarfiles_path"
  225. --transform="s,^,$directory/,S"
  226. --no-recursion
  227. --warning=no-filename-with-nuls
  228. --null
  229. --owner=0
  230. --group=0
  231. --numeric-owner
  232. )
  233. (
  234. cd "$source_path"
  235. tar "${tar_options[@]}"
  236. )
  237. }
  238. archive_extract() {
  239. local archive_path="$1"
  240. local destination_path="$2"
  241. if [[ -z "$destination_path" ]]; then
  242. destination_path="$(dirname "$archive_path")"
  243. fi
  244. tar -xf "$archive_path" -ps -C "$destination_path"
  245. }
  246. rootfs_files_create() {
  247. local source_path="$1"
  248. local directory="$(basename "$source_path")"
  249. local tarfiles_path="$source_path/$DOTTARFILES"
  250. # Files in "$tarfiles_path" are NUL terminated.
  251. # `tr '\0' '\n'` for human-readable output.
  252. execute_root find "$source_path" -print0 | env LC_ALL='C.UTF-8' sort -z | sed -z "1d;s,^$source_path/\\?,,;/^$DOTTARFILES\$/d" > "$tarfiles_path"
  253. }
  254. rootfs_files_date() {
  255. local source_path="$1"
  256. local epoch_path="$source_path/$DOTEPOCH"
  257. if [[ -n "$SOURCE_DATE_EPOCH" ]]; then
  258. execute_root find "$source_path" -execdir touch --no-dereference --date="@$SOURCE_DATE_EPOCH" {} +
  259. fi
  260. }
  261. rootfs_create() {
  262. local rootfs_path="$1"
  263. local source_path="$2"
  264. local directory="$3"
  265. local tarfiles_path="$source_path/$DOTTARFILES"
  266. local directory_path="$(dirname "$rootfs_path")"
  267. mkdir -p "$directory_path"
  268. if [[ -z "$directory" ]]; then
  269. directory="$(basename "$source_path")"
  270. fi
  271. rootfs_files_create "$source_path"
  272. rootfs_files_date "$source_path"
  273. local tar_options=(
  274. --create
  275. --xz
  276. --file="$rootfs_path"
  277. --files-from="$tarfiles_path"
  278. --no-recursion
  279. --warning=no-filename-with-nuls
  280. --null
  281. --owner=0
  282. --group=0
  283. --numeric-owner
  284. )
  285. (
  286. cd "$source_path"
  287. execute_root tar "${tar_options[@]}"
  288. )
  289. execute_root chmod 644 "$rootfs_path"
  290. execute_root chown "$USER:$USER" "$rootfs_path"
  291. }
  292. requirements() {
  293. local requirement
  294. local requirement_path
  295. for requirement in "$@"
  296. do
  297. requirement_path=$(which "$requirement" || true)
  298. if [[ -z "$requirement_path" ]]
  299. then
  300. printf 1>&2 '%s\n' "Missing requirement: $requirement"
  301. exit 1
  302. fi
  303. done
  304. }
  305. requirements_root() {
  306. local requirement
  307. local requirement_path
  308. for requirement in "$@"
  309. do
  310. # We need to keep stdout output to show the command.
  311. requirement_path=$(execute_root which "$requirement" || true)
  312. if [[ -z "$requirement_path" ]]
  313. then
  314. printf 1>&2 '%s\n' "Missing requirement: $requirement"
  315. exit 1
  316. fi
  317. done
  318. }
  319. arguments_concat() {
  320. local delimiter=$1
  321. shift
  322. local concat
  323. for argument in "$@"
  324. do
  325. if [[ -n "$concat" ]]
  326. then
  327. concat="$concat""$delimiter""$argument"
  328. else
  329. concat="$argument"
  330. fi
  331. done
  332. printf '%s\n' "$concat"
  333. }
  334. execute_root() {
  335. local sudo=$(which sudo 2> /dev/null || true)
  336. local arguments
  337. printf 1>&2 '%s' 'Running command as root: '
  338. printf 1>&2 '%b\n' "$*"
  339. if [[ -n "$sudo" ]]
  340. then
  341. sudo "$@"
  342. else
  343. # Quote arguments for eval through su.
  344. arguments=$(printf '%q ' "$@")
  345. su -c "$arguments"
  346. fi
  347. }