cipd 6.43 KB
Newer Older
1 2 3 4 5 6
#!/bin/bash -e

# Copyright (c) 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

7 8
set -e -o pipefail

9
MYPATH=$(dirname "${BASH_SOURCE[0]}")
10
CYGWIN=false
11 12

UNAME=`uname -s | tr '[:upper:]' '[:lower:]'`
13
case "${UNAME}" in
14
  linux)
15
    OS=linux
16
    ;;
17
  cygwin*)
18
    OS=windows
19 20 21
    CYGWIN=true
    ;;
  msys*|mingw*)
22
    OS=windows
23 24
    ;;
  darwin)
25
    OS=mac
26 27
    ;;
  *)
28
    >&2 echo "CIPD not supported on ${UNAME}"
29 30 31 32
    exit 1
esac

UNAME=`uname -m | tr '[:upper:]' '[:lower:]'`
33
case "${UNAME}" in
34 35 36
  x86_64|amd64)
    ARCH=amd64
    ;;
37 38 39
  s390x)  # best-effort support for IBM s390x: crbug.com/764087
    ARCH=s390x
    ;;
40 41 42
  ppc64)  # best-effort support for 64-bit PowerPC: crbug.com/773857
    ARCH=ppc64
    ;;
43
  ppc64le)  # best-effort support for 64-bit PowerPC/LE: crbug.com/773857
44 45
    ARCH=ppc64le
    ;;
46 47 48
  aarch64)
    ARCH=arm64
    ;;
49 50 51
  armv7l)
    ARCH=armv6l
    ;;
52
  arm*)
53
    ARCH="${UNAME}"
54 55 56 57
    ;;
  *86)
    ARCH=386
    ;;
58
  mips*)
59
    # detect mips64le vs mips64.
60
    ARCH="${UNAME}"
61 62 63
    if lscpu | grep -q "Little Endian"; then
      ARCH+=le
    fi
64
    ;;
65
  *)
66
    >&2 echo "UNKNOWN Machine architecture: ${UNAME}"
67 68 69
    exit 1
esac

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
# CIPD_BACKEND can be changed to ...-dev for manual testing.
CIPD_BACKEND="https://chrome-infra-packages.appspot.com"
VERSION_FILE="${MYPATH}/cipd_client_version"

CLIENT="${MYPATH}/.cipd_client"
VERSION=`cat "${VERSION_FILE}"`
PLATFORM="${OS}-${ARCH}"

URL="${CIPD_BACKEND}/client?platform=${PLATFORM}&version=${VERSION}"
USER_AGENT="depot_tools/$(git -C ${MYPATH} rev-parse HEAD 2>/dev/null || echo "???")"


# calc_sha256 is "portable" variant of sha256sum. It uses sha256sum when
# available (most Linuxes and cygwin) and 'shasum -a 256' otherwise (for OSX).
#
# Args:
#   Path to a file.
# Stdout:
#   Lowercase SHA256 hex digest of the file.
function calc_sha256() {
  if hash sha256sum 2> /dev/null ; then
    sha256sum "$1" | cut -d' ' -f1
  elif hash shasum 2> /dev/null ; then
    shasum -a 256 "$1" | cut -d' ' -f1
  else
    >&2 echo -n ""
    >&2 echo -n "Don't know how to calculate SHA256 on your platform. "
    >&2 echo -n "Please use your package manager to install one before continuing:"
    >&2 echo
    >&2 echo "  sha256sum"
    >&2 echo -n "  shasum"
    >&2 echo ""
    return 1
  fi
}


# expected_sha256 reads the expected SHA256 hex digest from *.digests file.
#
# Args:
#   Name of the platform to get client's digest for.
# Stdout:
#   Lowercase SHA256 hex digest.
function expected_sha256() {
  local line
  while read -r line; do
    if [[ "${line}" =~ ^([0-9a-z\-]+)[[:blank:]]+sha256[[:blank:]]+([0-9a-f]+)$ ]] ; then
      local plat="${BASH_REMATCH[1]}"
      local hash="${BASH_REMATCH[2]}"
      if [ "${plat}" ==  "$1" ]; then
        echo "${hash}"
        return 0
      fi
    fi
  done < "${VERSION_FILE}.digests"

  >&2 echo -n ""
  >&2 echo -n "Platform $1 is not supported by the CIPD client bootstrap: "
  >&2 echo -n "there's no pinned SHA256 hash for it in the *.digests file."
  >&2 echo ""

  return 1
}
133 134


135
# clean_bootstrap bootstraps the client from scratch using 'curl' or 'wget'.
136 137 138
#
# It checks that the SHA256 of the downloaded file is known. Exits the script
# if the client can't be downloaded or its hash doesn't match the expected one.
139
function clean_bootstrap() {
140 141 142 143
  local expected_hash=$(expected_sha256 "${PLATFORM}")
  if [ -z "${expected_hash}" ] ; then
    exit 1
  fi
144

145 146
  # Download the client into a temporary file, check its hash, then move it into
  # the final location.
147 148
  #
  # This wonky tempdir method works on Linux and Mac.
149
  local CIPD_CLIENT_TMP=$(\
150 151
    mktemp -p "${MYPATH}" 2>/dev/null || \
    mktemp "${MYPATH}/.cipd_client.XXXXXXX")
152

153
  if hash curl 2> /dev/null ; then
154
    curl "${URL}" -s --show-error -f -A "${USER_AGENT}" -L -o "${CIPD_CLIENT_TMP}"
155
  elif hash wget 2> /dev/null ; then
156
    wget "${URL}" -q -U "${USER_AGENT}" -O "${CIPD_CLIENT_TMP}"
157
  else
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    >&2 echo -n ""
    >&2 echo -n "Your platform is missing a supported fetch command. "
    >&2 echo "Please use your package manager to install one before continuing:"
    >&2 echo
    >&2 echo "  curl"
    >&2 echo "  wget"
    >&2 echo
    >&2 echo "Alternately, manually download:"
    >&2 echo "  ${URL}"
    >&2 echo -n "To ${CLIENT}, and then re-run this command."
    >&2 echo ""
    rm "${CIPD_CLIENT_TMP}"
    exit 1
  fi

  local actual_hash=$(calc_sha256 "${CIPD_CLIENT_TMP}")
  if [ -z "${actual_hash}" ] ; then
175
    rm "${CIPD_CLIENT_TMP}"
176 177
    exit 1
  fi
178

179 180 181 182 183 184 185 186 187 188
  if [ "${actual_hash}" != "${expected_hash}" ]; then
    >&2 echo -n ""
    >&2 echo "SHA256 digest of the downloaded CIPD client is incorrect:"
    >&2 echo "  Expecting ${expected_hash}"
    >&2 echo "  Got       ${actual_hash}"
    >&2 echo -n "Refusing to run it. Check that *.digests file is up-to-date."
    >&2 echo ""
    rm "${CIPD_CLIENT_TMP}"
    exit 1
  fi
189 190

  set +e
191 192
  chmod +x "${CIPD_CLIENT_TMP}"
  mv "${CIPD_CLIENT_TMP}" "${CLIENT}"
193
  set -e
194 195
}

196 197 198 199

# self_update launches CIPD client's built-in selfupdate mechanism.
#
# It is more efficient that redownloading the binary all the time.
200
function self_update() {
201
  "${CLIENT}" selfupdate -version-file "${VERSION_FILE}" -service-url "${CIPD_BACKEND}"
202 203
}

204 205

if [ ! -x "${CLIENT}" ]; then
206
  clean_bootstrap
207 208
fi

209 210 211 212 213 214
export CIPD_HTTP_USER_AGENT_PREFIX="${USER_AGENT}"
if ! self_update 2> /dev/null ; then
  >&2 echo -n ""
  >&2 echo -n "CIPD selfupdate failed. "
  >&2 echo -n "Trying to bootstrap the CIPD client from scratch..."
  >&2 echo ""
215 216
  clean_bootstrap
  if ! self_update ; then  # need to run it again to setup .cipd_version file
217 218 219 220 221 222 223
    >&2 echo -n ""
    >&2 echo -n "Bootstrap from scratch failed, something is seriously broken. "
    >&2 echo "Run the following commands to diagnose if this is repeating:"
    >&2 echo "  export CIPD_HTTP_USER_AGENT_PREFIX=${USER_AGENT}/manual"
    >&2 echo -n "  ${CLIENT} selfupdate -version-file ${VERSION_FILE}"
    >&2 echo ""
    exit 1
224
  fi
225 226
fi

227 228 229
# CygWin requires changing absolute paths to Windows form. Relative paths
# are typically okay as Windows generally accepts both forward and back
# slashes. This could possibly be constrained to only /tmp/ and /cygdrive/.
230
if ${CYGWIN}; then
231 232 233 234 235 236 237 238 239
  args=("$@")
  for i in `seq 2 $#`; do
    arg="${@:$i:1}"
    if [ "${arg:0:1}" == "/" ]; then
      last=$((i-1))
      next=$((i+1))
      set -- "${@:1:$last}" `cygpath -w "$arg"` "${@:$next}"
    fi
  done
240
  echo "${CLIENT}" "${@}"
241 242
fi

243
exec "${CLIENT}" "${@}"