cipd 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #!/usr/bin/env bash
  2. # Copyright (c) 2016 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. set -e -o pipefail
  6. # Run custom-built cipd client. This is useful when cipd is not available upstream
  7. # (i.e. unsupported platform).
  8. if [ ! -z "${CUSTOM_CIPD_CLIENT}" ]; then
  9. exec "${CUSTOM_CIPD_CLIENT}" "${@}"
  10. fi
  11. # Export for other depot_tools scripts to re-use.
  12. export DEPOT_TOOLS_DIR="${DEPOT_TOOLS_DIR:-$(dirname "${BASH_SOURCE[0]}")}"
  13. export DEPOT_TOOLS_UNAME_S="${DEPOT_TOOLS_UNAME_S:-$(uname -s | tr '[:upper:]' '[:lower:]')}"
  14. CYGWIN=false
  15. # Make sure this starts empty
  16. ARCH=
  17. UNAME="${DEPOT_TOOLS_UNAME_S}"
  18. case "${UNAME}" in
  19. aix)
  20. OS="${UNAME}"
  21. ARCH="ppc64" # apparently 'uname -m' returns something very different
  22. ;;
  23. linux)
  24. OS="${UNAME}"
  25. ;;
  26. cygwin*)
  27. OS=windows
  28. CYGWIN=true
  29. ;;
  30. msys*|mingw*)
  31. OS=windows
  32. ;;
  33. darwin)
  34. OS=mac
  35. # Allow mac users to override easily override arch detection
  36. if [ ! -z "${ARCH_MAC_OVERRIDE}" ]; then
  37. ARCH="${ARCH_MAC_OVERRIDE}"
  38. fi
  39. ;;
  40. *)
  41. >&2 echo "CIPD not supported on ${UNAME}"
  42. exit 1
  43. esac
  44. if [ -z $ARCH ]; then
  45. UNAME=`uname -m | tr '[:upper:]' '[:lower:]'`
  46. case "${UNAME}" in
  47. x86_64|amd64)
  48. ARCH=amd64
  49. ;;
  50. s390x|ppc64|ppc64le) # best-effort support
  51. ARCH="${UNAME}"
  52. ;;
  53. aarch64)
  54. ARCH=arm64
  55. ;;
  56. armv7l)
  57. ARCH=armv6l
  58. ;;
  59. arm*)
  60. ARCH="${UNAME}"
  61. ;;
  62. *86)
  63. ARCH=386
  64. ;;
  65. mips*)
  66. # detect mips64le vs mips64.
  67. ARCH="${UNAME}"
  68. if lscpu | grep -q "Little Endian"; then
  69. ARCH+=le
  70. fi
  71. ;;
  72. riscv64)
  73. ARCH=riscv64
  74. ;;
  75. *)
  76. >&2 echo "UNKNOWN Machine architecture: ${UNAME}"
  77. exit 1
  78. esac
  79. fi
  80. # CIPD_BACKEND can be changed to ...-dev for manual testing.
  81. CIPD_BACKEND="https://chrome-infra-packages.appspot.com"
  82. VERSION_FILE="${DEPOT_TOOLS_DIR}/cipd_client_version"
  83. CIPD_ROOT="${DEPOT_TOOLS_DIR}"
  84. # value in .cipd_client_root file overrides the default root.
  85. CIPD_ROOT_OVERRIDE_FILE="${DEPOT_TOOLS_DIR}/.cipd_client_root"
  86. if [ -f "${CIPD_ROOT_OVERRIDE_FILE}" ]; then
  87. CIPD_ROOT=$(<"${CIPD_ROOT_OVERRIDE_FILE}")
  88. mkdir -p "${CIPD_ROOT}"
  89. fi
  90. CLIENT="${CIPD_ROOT}/.cipd_client"
  91. PLATFORM="${OS}-${ARCH}"
  92. # A value in .cipd_client_platform overrides the "guessed" platform.
  93. PLATFORM_OVERRIDE_FILE="${DEPOT_TOOLS_DIR}/.cipd_client_platform"
  94. if [ -f "${PLATFORM_OVERRIDE_FILE}" ]; then
  95. PLATFORM=$(<"${PLATFORM_OVERRIDE_FILE}")
  96. fi
  97. USER_AGENT="depot_tools/$(git -C ${DEPOT_TOOLS_DIR} rev-parse HEAD 2>/dev/null || echo "???")"
  98. # calc_sha256 is "portable" variant of sha256sum. It uses sha256sum when
  99. # available (most Linuxes and cygwin) and 'shasum -a 256' otherwise (for OSX).
  100. #
  101. # Args:
  102. # Path to a file.
  103. # Stdout:
  104. # Lowercase SHA256 hex digest of the file.
  105. function calc_sha256() {
  106. if hash sha256sum 2> /dev/null ; then
  107. sha256sum "$1" | cut -d' ' -f1
  108. elif hash shasum 2> /dev/null ; then
  109. shasum -a 256 "$1" | cut -d' ' -f1
  110. else
  111. >&2 echo -n ""
  112. >&2 echo -n "Don't know how to calculate SHA256 on your platform. "
  113. >&2 echo -n "Please use your package manager to install one before continuing:"
  114. >&2 echo
  115. >&2 echo " sha256sum"
  116. >&2 echo -n " shasum"
  117. >&2 echo ""
  118. return 1
  119. fi
  120. }
  121. # expected_sha256 reads the expected SHA256 hex digest from *.digests file.
  122. #
  123. # Args:
  124. # Name of the platform to get client's digest for.
  125. # Stdout:
  126. # Lowercase SHA256 hex digest.
  127. function expected_sha256() {
  128. local line
  129. while read -r line; do
  130. if [[ "${line}" =~ ^([0-9a-z\-]+)[[:blank:]]+sha256[[:blank:]]+([0-9a-f]+)$ ]] ; then
  131. local plat="${BASH_REMATCH[1]}"
  132. local hash="${BASH_REMATCH[2]}"
  133. if [ "${plat}" == "$1" ]; then
  134. echo "${hash}"
  135. return 0
  136. fi
  137. fi
  138. done < "${VERSION_FILE}.digests"
  139. >&2 echo -n ""
  140. >&2 echo -n "Platform $1 is not supported by the CIPD client bootstrap: "
  141. >&2 echo -n "there's no pinned SHA256 hash for it in the *.digests file."
  142. >&2 echo ""
  143. return 1
  144. }
  145. # clean_bootstrap bootstraps the client from scratch using 'curl' or 'wget'.
  146. #
  147. # It checks that the SHA256 of the downloaded file is known. Exits the script
  148. # if the client can't be downloaded or its hash doesn't match the expected one.
  149. function clean_bootstrap() {
  150. local expected_hash=$(expected_sha256 "${PLATFORM}")
  151. if [ -z "${expected_hash}" ] ; then
  152. exit 1
  153. fi
  154. local VERSION=$(<"${VERSION_FILE}")
  155. local URL="${CIPD_BACKEND}/client?platform=${PLATFORM}&version=${VERSION}"
  156. # Download the client into a temporary file, check its hash, then move it into
  157. # the final location.
  158. #
  159. # This wonky tempdir method works on Linux and Mac.
  160. local CIPD_CLIENT_TMP=$(\
  161. mktemp -p "${CIPD_ROOT}" 2>/dev/null || \
  162. mktemp "${CIPD_ROOT}/.cipd_client.XXXXXXX")
  163. if hash curl 2> /dev/null ; then
  164. curl "${URL}" -s --show-error -f --retry 3 --retry-delay 5 -A "${USER_AGENT}" -L -o "${CIPD_CLIENT_TMP}"
  165. elif hash wget 2> /dev/null ; then
  166. wget "${URL}" -q -t 3 -w 5 --retry-connrefused -U "${USER_AGENT}" -O "${CIPD_CLIENT_TMP}"
  167. else
  168. >&2 echo -n ""
  169. >&2 echo -n "Your platform is missing a supported fetch command. "
  170. >&2 echo "Please use your package manager to install one before continuing:"
  171. >&2 echo
  172. >&2 echo " curl"
  173. >&2 echo " wget"
  174. >&2 echo
  175. >&2 echo "Alternately, manually download:"
  176. >&2 echo " ${URL}"
  177. >&2 echo -n "To ${CLIENT}, and then re-run this command."
  178. >&2 echo ""
  179. rm "${CIPD_CLIENT_TMP}"
  180. exit 1
  181. fi
  182. local actual_hash=$(calc_sha256 "${CIPD_CLIENT_TMP}")
  183. if [ -z "${actual_hash}" ] ; then
  184. rm "${CIPD_CLIENT_TMP}"
  185. exit 1
  186. fi
  187. if [ "${actual_hash}" != "${expected_hash}" ]; then
  188. >&2 echo -n ""
  189. >&2 echo "SHA256 digest of the downloaded CIPD client is incorrect:"
  190. >&2 echo " Expecting ${expected_hash}"
  191. >&2 echo " Got ${actual_hash}"
  192. >&2 echo -n "Refusing to run it. Check that *.digests file is up-to-date."
  193. >&2 echo ""
  194. rm "${CIPD_CLIENT_TMP}"
  195. exit 1
  196. fi
  197. set +e
  198. chmod +x "${CIPD_CLIENT_TMP}"
  199. mv "${CIPD_CLIENT_TMP}" "${CLIENT}"
  200. set -e
  201. }
  202. # self_update launches CIPD client's built-in selfupdate mechanism.
  203. #
  204. # It is more efficient that redownloading the binary all the time.
  205. function self_update() {
  206. "${CLIENT}" selfupdate -version-file "${VERSION_FILE}" -service-url "${CIPD_BACKEND}"
  207. }
  208. # Nuke the existing client if its platform doesn't match what we want now. We
  209. # crudely search for a CIPD client package name in the .cipd_version JSON file.
  210. # It has only "instance_id" as the other field (looking like a base64 string),
  211. # so mismatches are very unlikely.
  212. INSTALLED_VERSION_FILE="${CIPD_ROOT}/.versions/.cipd_client.cipd_version"
  213. if [ -f "${INSTALLED_VERSION_FILE}" ]; then
  214. JSON_BODY=$(<"${INSTALLED_VERSION_FILE}")
  215. if [[ "$JSON_BODY" != *"infra/tools/cipd/${PLATFORM}"* ]]; then
  216. >&2 echo "Detected CIPD client platform change to ${PLATFORM}."
  217. >&2 echo "Deleting the existing client to trigger the bootstrap..."
  218. rm -f "${CLIENT}" "${INSTALLED_VERSION_FILE}"
  219. fi
  220. fi
  221. # If the client binary doesn't exist, do the bootstrap from scratch.
  222. if [ ! -x "${CLIENT}" ]; then
  223. clean_bootstrap
  224. fi
  225. # If the client binary exists, ask it to self-update.
  226. export CIPD_HTTP_USER_AGENT_PREFIX="${USER_AGENT}"
  227. if ! self_update 2> /dev/null ; then
  228. >&2 echo -n ""
  229. >&2 echo -n "CIPD selfupdate failed. "
  230. >&2 echo -n "Trying to bootstrap the CIPD client from scratch..."
  231. >&2 echo ""
  232. clean_bootstrap
  233. if ! self_update ; then # need to run it again to setup .cipd_version file
  234. >&2 echo -n ""
  235. >&2 echo -n "Bootstrap from scratch for ${PLATFORM} failed! "
  236. >&2 echo "Run the following commands to diagnose if this is repeating:"
  237. >&2 echo " export CIPD_HTTP_USER_AGENT_PREFIX=${USER_AGENT}/manual"
  238. >&2 echo -n " ${CLIENT} selfupdate -version-file ${VERSION_FILE}"
  239. >&2 echo ""
  240. exit 1
  241. fi
  242. fi
  243. # CygWin requires changing absolute paths to Windows form. Relative paths
  244. # are typically okay as Windows generally accepts both forward and back
  245. # slashes. This could possibly be constrained to only /tmp/ and /cygdrive/.
  246. if ${CYGWIN}; then
  247. args=("$@")
  248. for i in `seq 2 $#`; do
  249. arg="${@:$i:1}"
  250. if [ "${arg:0:1}" == "/" ]; then
  251. last=$((i-1))
  252. next=$((i+1))
  253. set -- "${@:1:$last}" `cygpath -w "$arg"` "${@:$next}"
  254. fi
  255. done
  256. echo "${CLIENT}" "${@}"
  257. fi
  258. exec "${CLIENT}" "${@}"