logo

live-bootstrap

Mirror of <https://github.com/fosslinux/live-bootstrap>

mirror.sh (5371B)


  1. #!/bin/sh
  2. # This script is intentionally written in POSIX sh to be cross-platform.
  3. #
  4. # SPDX-License-Identifier: GPL-3.0-or-later
  5. # SPDX-FileCopyrightText: 2025 fosslinux <fosslinux@aussies.space>
  6. set -e
  7. # Check arguments, etc
  8. if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
  9. echo "Usage: $0 <destination> [state]"
  10. exit 1
  11. fi
  12. dest=$1
  13. if [ ! -d "${dest}" ]; then
  14. echo "${dest} must be a directory"
  15. exit 1
  16. fi
  17. if [ ! -w "${dest}" ]; then
  18. echo "you must be able to write to ${dest}"
  19. exit 1
  20. fi
  21. dest=$(realpath "${dest}")
  22. state=$2
  23. if [ "${state}" = "" ]; then
  24. state="${PWD}/mirrorstate"
  25. fi
  26. state="$(realpath "${state}")"
  27. #######
  28. # Download a HTTP file
  29. download_file() {
  30. url=${1}
  31. out=${2}
  32. # Download the file
  33. continue_arg=""
  34. if [ -e "${out}" ]; then
  35. continue_arg="-C -"
  36. fi
  37. # shellcheck disable=SC2086
  38. curl -L ${continue_arg} -o "${out}" "${url}"
  39. }
  40. # Check if a git reference exists in a given repository
  41. git_ref_exists() {
  42. repo=${1}
  43. ref=${2}
  44. # change this to git show-ref once it is sufficiently not-new
  45. ( cd "${repo}" || exit && git cat-file -t "${ref}" >/dev/null 2>&1 )
  46. return $?
  47. }
  48. checksum_file() {
  49. sha256sum "${1}" | cut -d' ' -f1
  50. }
  51. do_file() {
  52. uri=${1}
  53. echo "${uri}"
  54. if echo "${uri}" | grep -qE "^https?://"; then
  55. # HTTP file
  56. checksum=${2}
  57. filename=${3}
  58. if [ "${filename}" = "" ]; then
  59. filename=$(basename "${uri}")
  60. fi
  61. # Check if the file is already downloaded & the checksum is the same
  62. dest_file=${dest}/${filename}
  63. if [ -e "${dest_file}" ]; then
  64. existing_checksum=$(checksum_file "${dest_file}")
  65. if [ "${checksum}" = "${existing_checksum}" ]; then
  66. # There is nothing we need to do here
  67. return
  68. fi
  69. fi
  70. # Attempt up to 3 times
  71. retries=3
  72. matching=no
  73. while [ "${retries}" -gt 0 ]; do
  74. download_file "${uri}" "${dest}/${filename}"
  75. my_checksum=$(checksum_file "${dest_file}")
  76. if [ "${checksum}" = "${my_checksum}" ]; then
  77. matching="yes"
  78. break
  79. fi
  80. retries=$((retries - 1))
  81. if [ "${retries}" -gt 0 ]; then
  82. echo "${uri}: checksum did not match, trying again"
  83. rm "${dest}/${filename}"
  84. fi
  85. sleep 1
  86. done
  87. if [ "${matching}" = "no" ]; then
  88. echo "${uri}: checksums do not match"
  89. exit 1
  90. fi
  91. elif echo "${uri}" | grep -qE "^git://"; then
  92. # Creating a tarball from a git repository
  93. # Very unfortunately, different sites have different rules.
  94. uri_path=${uri#git://}
  95. # GitHub does not have git:// protocol support
  96. if echo "${uri}" | grep -Eq "^git://github.com"; then
  97. uri=https://${uri_path}
  98. fi
  99. repo=${uri%~*}
  100. outdir=${state}/git/${repo#*://}
  101. reference=${uri##*~}
  102. http_src=${2}
  103. checksum=${3}
  104. tarball=${4:-$(basename "${http_src}")}
  105. if [ "${tarball}" = "_" ]; then
  106. echo "${uri}: ERROR! Must have tarball name if no http source."
  107. exit 1
  108. fi
  109. tarball=${dest}/${tarball}
  110. # Check if tarball already generated + matches checksum
  111. checksum=${3}
  112. if [ -e "${tarball}" ]; then
  113. existing_checksum=$(checksum_file "${tarball}")
  114. if [ "${existing_checksum}" = "${checksum}" ]; then
  115. return
  116. fi
  117. rm "${tarball}"
  118. fi
  119. # Clone the repository, or update it if needed
  120. if [ ! -e "${outdir}" ]; then
  121. mkdir -p "$(dirname "${outdir}")"
  122. git clone "${repo}" "${outdir}"
  123. elif ! git_ref_exists "${outdir}" "${reference}" ; then
  124. (
  125. cd "${outdir}" || exit
  126. git pull
  127. )
  128. fi
  129. # Sanity check: the reference we want exists
  130. if ! git_ref_exists "${outdir}" "${reference}"; then
  131. echo "${reference} not found in ${repo} (${outdir})"
  132. exit 1
  133. fi
  134. # Generate the prefix for the tarball
  135. prefix_ref=${reference}
  136. # All git repositories we already use remove "v"s from the beginning
  137. # of branch/tag names in the tarball prefix
  138. if echo "${reference}" | grep -Eq "^v[0-9]"; then
  139. prefix_ref=$(echo "${reference}" | sed "s/^v//")
  140. fi
  141. prefix=$(basename "${repo}" | sed "s/.git$//")-${prefix_ref}
  142. (
  143. cd "${outdir}" || exit
  144. git config tar.tar.gz.command gzip
  145. # -T1 avoids non-determinism due to threading
  146. # This may not be correct for forges other than Savannah
  147. git config tar.tar.xz.command "xz -T1"
  148. git archive "${reference}" -o "${tarball}" --prefix "${prefix}/"
  149. )
  150. my_checksum=$(sha256sum "${tarball}" | cut -d' ' -f1)
  151. if [ "${my_checksum}" != "${checksum}" ]; then
  152. echo "${uri}: generated tarball does not match checksum"
  153. exit 1
  154. fi
  155. fi
  156. }
  157. for src in steps/*/sources; do
  158. while read -r line; do
  159. # shellcheck disable=SC2086
  160. do_file ${line}
  161. uri=$(echo "${line}" | cut -d' ' -f1)
  162. done < "${src}"
  163. done