cvm

Форк
0
/
trunk 
446 строк · 13.5 Кб
1
#!/bin/bash
2

3
###############################################################################
4
#                                                                             #
5
#   Setup                                                                     #
6
#                                                                             #
7
###############################################################################
8

9
set -euo pipefail
10

11
readonly TRUNK_LAUNCHER_VERSION="1.2.7" # warning: this line is auto-updated
12

13
readonly SUCCESS_MARK="\033[0;32m✔\033[0m"
14
readonly FAIL_MARK="\033[0;31m✘\033[0m"
15
readonly PROGRESS_MARKS=("⡿" "⢿" "⣻" "⣽" "⣾" "⣷" "⣯" "⣟")
16

17
# This is how mktemp(1) decides where to create stuff in tmpfs.
18
readonly TMPDIR="${TMPDIR:-/tmp}"
19

20
KERNEL=$(uname | tr "[:upper:]" "[:lower:]")
21
if [[ ${KERNEL} == mingw64* || ${KERNEL} == msys* ]]; then
22
  KERNEL="mingw"
23
fi
24
readonly KERNEL
25

26
MACHINE=$(uname -m)
27
if [[ $MACHINE == "aarch64" ]]; then
28
  MACHINE="arm64";
29
fi
30

31
readonly MACHINE
32

33
PLATFORM="${KERNEL}-${MACHINE}"
34
readonly PLATFORM
35

36
PLATFORM_UNDERSCORE="${KERNEL}_${MACHINE}"
37
readonly PLATFORM_UNDERSCORE
38

39
# https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences
40
# [nF is "cursor previous line" and moves to the beginning of the nth previous line
41
# [0K is "erase display" and clears from the cursor to the end of the screen
42
readonly CLEAR_LAST_MSG="\033[1F\033[0K"
43

44
if [[ ! -z ${CI:-} && "${CI}" = true && -z ${TRUNK_LAUNCHER_QUIET:-} ]]; then
45
  TRUNK_LAUNCHER_QUIET=1
46
else
47
  TRUNK_LAUNCHER_QUIET=${TRUNK_LAUNCHER_QUIET:-${TRUNK_QUIET:-false}}
48
fi
49

50
readonly TRUNK_LAUNCHER_DEBUG
51

52
if [[ ${TRUNK_LAUNCHER_QUIET} != false ]]; then
53
  exec 3>&1 4>&2 &>/dev/null
54
fi
55

56
TRUNK_CACHE="${TRUNK_CACHE:-}"
57
if [[ -n ${TRUNK_CACHE} ]]; then
58
  :
59
elif [[ -n ${XDG_CACHE_HOME:-} ]]; then
60
  TRUNK_CACHE="${XDG_CACHE_HOME}/trunk"
61
else
62
  TRUNK_CACHE="${HOME}/.cache/trunk"
63
fi
64
readonly TRUNK_CACHE
65
readonly CLI_DIR="${TRUNK_CACHE}/cli"
66
mkdir -p "${CLI_DIR}"
67

68
# platform check
69
readonly MINIMUM_MACOS_VERSION="10.15"
70
check_darwin_version() {
71
  local osx_version
72
  osx_version="$(sw_vers -productVersion)"
73

74
  # trunk-ignore-begin(shellcheck/SC2312): the == will fail if anything inside the $() fails
75
  if [[ "$(printf "%s\n%s\n" "${MINIMUM_MACOS_VERSION}" "${osx_version}" |
76
    sort --version-sort |
77
    head -n 1)" == "${MINIMUM_MACOS_VERSION}"* ]]; then
78
    return
79
  fi
80
  # trunk-ignore-end(shellcheck/SC2312)
81

82
  echo -e "${FAIL_MARK} Trunk requires at least MacOS ${MINIMUM_MACOS_VERSION}" \
83
    "(yours is ${osx_version}). See https://docs.trunk.io for more info."
84
  exit 1
85
}
86

87
if [[ ${PLATFORM} == "darwin-x86_64" || ${PLATFORM} == "darwin-arm64" ]]; then
88
  check_darwin_version
89
elif [[ ${PLATFORM} == "linux-x86_64" || ${PLATFORM} == "linux-arm64" || ${PLATFORM} == "windows-x86_64" || ${PLATFORM} == "mingw-x86_64" ]]; then
90
  :
91
else
92
  echo -e "${FAIL_MARK} Trunk is only supported on Linux (x64_64, arm64), MacOS (x86_64, arm64), and Windows (x86_64)." \
93
    "See https://docs.trunk.io for more info."
94
  exit 1
95
fi
96

97
TRUNK_TMPDIR="${TMPDIR}/trunk-$(
98
  set -e
99
  id -u
100
)/launcher_logs"
101
readonly TRUNK_TMPDIR
102
mkdir -p "${TRUNK_TMPDIR}"
103

104
# For the `mv $TOOL_TMPDIR/trunk $TOOL_DIR` to be atomic (i.e. just inode renames), the source and destination filesystems need to be the same
105
TOOL_TMPDIR=$(mktemp -d "${CLI_DIR}/tmp.XXXXXXXXXX")
106
readonly TOOL_TMPDIR
107

108
cleanup() {
109
  rm -rf "${TOOL_TMPDIR}"
110
  if [[ $1 == "0" ]]; then
111
    rm -rf "${TRUNK_TMPDIR}"
112
  fi
113
}
114
trap 'cleanup $?' EXIT
115

116
# e.g. 2022-02-16-20-40-31-0800
117
dt_str() { date +"%Y-%m-%d-%H-%M-%S%z"; }
118

119
LAUNCHER_TMPDIR="${TOOL_TMPDIR}/launcher"
120
readonly LAUNCHER_TMPDIR
121
mkdir -p "${LAUNCHER_TMPDIR}"
122

123
if [[ -n ${TRUNK_LAUNCHER_DEBUG:-} ]]; then
124
  set -x
125
fi
126

127
# launcher awk
128
#
129
# BEGIN{ORS="";}
130
#   use "" as the output record separator
131
#   ORS defaults to "\n" for bwk, which results in
132
#     $(printf "foo bar" | awk '{print $2}') == "bar\n"
133
#
134
# {gsub(/\r/, "", $0)}
135
#   for every input record (i.e. line), the regex "\r" should be replaced with ""
136
#   This is necessary to handle CRLF files in a portable fashion.
137
#
138
# Some StackOverflow answers suggest using RS="\r?\n" to handle CRLF files (RS is the record
139
# separator, i.e. the line delimiter); unfortunately, original-awk only allows single-character
140
# values for RS (see https://www.gnu.org/software/gawk/manual/gawk.html#awk-split-records).
141
lawk() {
142
  awk 'BEGIN{ORS="";}{gsub(/\r/, "", $0)}'"${1}" "${@:2}"
143
}
144
awk_test() {
145
  # trunk-ignore-begin(shellcheck/SC2310,shellcheck/SC2312)
146
  # SC2310 and SC2312 are about set -e not propagating to the $(); if that happens, the string
147
  # comparison will fail and we'll claim the user's awk doesn't work
148
  if [[ $(
149
    set -e
150
    printf 'k1: v1\n \tk2: v2\r\n' | lawk '/[ \t]+k2:/{print $2}'
151
  ) == 'v2' &&
152
  $(
153
    set -e
154
    printf 'k1: v1\r\n\t k2: v2\r\n' | lawk '/[ \t]+k2:/{print $2}'
155
  ) == 'v2' ]]; then
156
    return
157
  fi
158
  # trunk-ignore-end(shellcheck/SC2310,shellcheck/SC2312)
159

160
  echo -e "${FAIL_MARK} Trunk does not work with your awk;" \
161
    "please report this at https://slack.trunk.io."
162
  echo -e "Your version of awk is:"
163
  awk --version || awk -Wversion
164
  exit 1
165
}
166
awk_test
167

168
readonly CURL_FLAGS="${CURL_FLAGS:- -vvv --max-time 120 --retry 3 --fail}"
169
readonly WGET_FLAGS="${WGET_FLAGS:- --verbose --tries=3 --limit-rate=10M}"
170
TMP_DOWNLOAD_LOG="${TRUNK_TMPDIR}/download-$(
171
  set -e
172
  dt_str
173
).log"
174
readonly TMP_DOWNLOAD_LOG
175

176
# Detect whether we should use wget or curl.
177
if command -v wget &>/dev/null; then
178
  download_cmd() {
179
    local url="${1}"
180
    local output_to="${2}"
181
    # trunk-ignore-begin(shellcheck/SC2312): we don't care if wget --version errors
182
    cat >>"${TMP_DOWNLOAD_LOG}" <<EOF
183
Using wget to download '${url}' to '${output_to}'
184

185
Is Trunk up?: https://status.trunk.io
186

187
WGET_FLAGS: ${WGET_FLAGS}
188

189
wget --version:
190
$(wget --version 2>&1)
191

192
EOF
193
    # trunk-ignore-end(shellcheck/SC2312)
194

195
    # Support BusyBox wget
196
    if wget --help 2>&1 | grep BusyBox; then
197
      wget "${url}" -O "${output_to}" 2>>"${TMP_DOWNLOAD_LOG}" &
198
    else
199
      # trunk-ignore(shellcheck/SC2086): we deliberately don't quote WGET_FLAGS
200
      wget ${WGET_FLAGS} "${url}" --output-document "${output_to}" 2>>"${TMP_DOWNLOAD_LOG}" &
201
    fi
202
  }
203
elif command -v curl &>/dev/null; then
204
  download_cmd() {
205
    local url="${1}"
206
    local output_to="${2}"
207
    # trunk-ignore-begin(shellcheck/SC2312): we don't care if curl --version errors
208
    cat >>"${TMP_DOWNLOAD_LOG}" <<EOF
209
Using curl to download '${url}' to '${output_to}'
210

211
Is Trunk up?: https://status.trunk.io
212

213
CURL_FLAGS: ${CURL_FLAGS}
214

215
curl --version:
216
$(curl --version)
217

218
EOF
219
    # trunk-ignore-end(shellcheck/SC2312)
220

221
    # trunk-ignore(shellcheck/SC2086): we deliberately don't quote CURL_FLAGS
222
    curl ${CURL_FLAGS} "${url}" --output "${output_to}" 2>>"${TMP_DOWNLOAD_LOG}" &
223
  }
224
else
225
  download_cmd() {
226
    echo -e "${FAIL_MARK} Cannot download '${url}'; please install curl or wget."
227
    exit 1
228
  }
229
fi
230

231
download_url() {
232
  local url="${1}"
233
  local output_to="${2}"
234
  local progress_message="${3:-}"
235

236
  if [[ -n ${progress_message} ]]; then
237
    echo -e "${PROGRESS_MARKS[0]} ${progress_message}..."
238
  fi
239

240
  download_cmd "${url}" "${output_to}"
241
  local download_pid="$!"
242

243
  local i_prog=0
244
  while [[ -d "/proc/${download_pid}" && -n ${progress_message} ]]; do
245
    echo -e "${CLEAR_LAST_MSG}${PROGRESS_MARKS[${i_prog}]} ${progress_message}..."
246
    sleep 0.2
247
    i_prog=$(((i_prog + 1) % ${#PROGRESS_MARKS[@]}))
248
  done
249

250
  local download_log
251
  if ! wait "${download_pid}"; then
252
    download_log="${TRUNK_TMPDIR}/launcher-download-$(
253
      set -e
254
      dt_str
255
    ).log"
256
    mv "${TMP_DOWNLOAD_LOG}" "${download_log}"
257
    echo -e "${CLEAR_LAST_MSG}${FAIL_MARK} ${progress_message}... FAILED (see ${download_log})"
258
    echo -e "Please check your connection and try again." \
259
      "If you continue to see this error message," \
260
      "consider reporting it to us at https://slack.trunk.io."
261
    exit 1
262
  fi
263

264
  if [[ -n ${progress_message} ]]; then
265
    echo -e "${CLEAR_LAST_MSG}${SUCCESS_MARK} ${progress_message}... done"
266
  fi
267

268
}
269

270
# sha256sum is in coreutils, so we prefer that over shasum, which is installed with perl
271
if command -v sha256sum &>/dev/null; then
272
  :
273
elif command -v shasum &>/dev/null; then
274
  sha256sum() { shasum -a 256 "$@"; }
275
else
276
  sha256sum() {
277
    echo -e "${FAIL_MARK} Cannot compute sha256; please install sha256sum or shasum"
278
    exit 1
279
  }
280
fi
281

282
###############################################################################
283
#                                                                             #
284
#   CLI resolution functions                                                  #
285
#                                                                             #
286
###############################################################################
287

288
trunk_yaml_abspath() {
289
  local repo_head
290
  local cwd
291

292
  if repo_head=$(git rev-parse --show-toplevel 2>/dev/null); then
293
    echo "${repo_head}/.trunk/trunk.yaml"
294
  elif [[ -f .trunk/trunk.yaml ]]; then
295
    cwd="$(pwd)"
296
    echo "${cwd}/.trunk/trunk.yaml"
297
  else
298
    echo ""
299
  fi
300
}
301

302
read_cli_version_from() {
303
  local config_abspath="${1}"
304
  local cli_version
305

306
  cli_version="$(
307
    set -e
308
    lawk '/[ \t]+version:/{print $2; exit;}' "${config_abspath}"
309
  )"
310
  if [[ -z ${cli_version} ]]; then
311
    echo -e "${FAIL_MARK} Invalid .trunk/trunk.yaml, no cli version found." \
312
      "See https://docs.trunk.io for more info." >&2
313
    exit 1
314
  fi
315

316
  echo "${cli_version}"
317
}
318

319
download_cli() {
320
  local dl_version="${1}"
321
  local expected_sha256="${2}"
322
  local actual_sha256
323

324
  readonly TMP_INSTALL_DIR="${LAUNCHER_TMPDIR}/install"
325
  mkdir -p "${TMP_INSTALL_DIR}"
326

327
  TRUNK_NEW_URL_VERSION=0.10.2-beta.1
328
  if sort --help 2>&1 | grep BusyBox; then
329
    readonly URL="https://trunk.io/releases/${dl_version}/trunk-${dl_version}-${PLATFORM}.tar.gz"
330
  else
331
    if [[ "$(printf "%s\n%s\n" "${TRUNK_NEW_URL_VERSION}" "${dl_version}" |
332
      sort --version-sort |
333
      head -n 1 || true)" == "${TRUNK_NEW_URL_VERSION}"* ]]; then
334
      readonly URL="https://trunk.io/releases/${dl_version}/trunk-${dl_version}-${PLATFORM}.tar.gz"
335
    else
336
      readonly URL="https://trunk.io/releases/trunk-${dl_version}.${KERNEL}.tar.gz"
337
    fi
338
  fi
339

340
  readonly DOWNLOAD_TAR_GZ="${TMP_INSTALL_DIR}/download-${dl_version}.tar.gz"
341

342
  download_url "${URL}" "${DOWNLOAD_TAR_GZ}" "Downloading Trunk ${dl_version}"
343

344
  if [[ -n ${expected_sha256:-} ]]; then
345
    local verifying_text="Verifying Trunk sha256..."
346
    echo -e "${PROGRESS_MARKS[0]} ${verifying_text}"
347

348
    actual_sha256="$(
349
      set -e
350
      sha256sum "${DOWNLOAD_TAR_GZ}" | lawk '{print $1}'
351
    )"
352

353
    if [[ ${actual_sha256} != "${expected_sha256}" ]]; then
354
      echo -e "${CLEAR_LAST_MSG}${FAIL_MARK} ${verifying_text} FAILED"
355
      echo "Expected sha256: ${expected_sha256}"
356
      echo "  Actual sha256: ${actual_sha256}"
357
      exit 1
358
    fi
359

360
    echo -e "${CLEAR_LAST_MSG}${SUCCESS_MARK} ${verifying_text} done"
361
  fi
362

363
  local unpacking_text="Unpacking Trunk..."
364
  echo -e "${PROGRESS_MARKS[0]} ${unpacking_text}"
365
  tar --strip-components=1 -C "${TMP_INSTALL_DIR}" -xf "${DOWNLOAD_TAR_GZ}"
366
  echo -e "${CLEAR_LAST_MSG}${SUCCESS_MARK} ${unpacking_text} done"
367

368
  rm -f "${DOWNLOAD_TAR_GZ}"
369
  mkdir -p "${TOOL_DIR}"
370
  readonly OLD_TOOL_DIR="${CLI_DIR}/${version}"
371
  # Create a backwards compatability link for old versions of trunk that want to write their
372
  # crashpad_handlers to that dir.
373
  if [[ ! -e ${OLD_TOOL_DIR} ]]; then
374
    ln -sf "${TOOL_PART}" "${OLD_TOOL_DIR}"
375
  fi
376
  mv -n "${TMP_INSTALL_DIR}/trunk" "${TOOL_DIR}/" || true
377
  rm -rf "${TMP_INSTALL_DIR}"
378
}
379

380
###############################################################################
381
#                                                                             #
382
#   CLI resolution                                                            #
383
#                                                                             #
384
###############################################################################
385

386
CONFIG_ABSPATH="$(
387
  set -e
388
  trunk_yaml_abspath
389
)"
390
readonly CONFIG_ABSPATH
391

392
version="${TRUNK_CLI_VERSION:-}"
393
if [[ -n ${version:-} ]]; then
394
  :
395
elif [[ -f ${CONFIG_ABSPATH} ]]; then
396
  version="$(
397
    set -e
398
    read_cli_version_from "${CONFIG_ABSPATH}"
399
  )"
400
  version_sha256="$(
401
    set -e
402
    lawk "/${PLATFORM_UNDERSCORE}:/"'{print $2}' "${CONFIG_ABSPATH}"
403
  )"
404
else
405
  readonly LATEST_FILE="${LAUNCHER_TMPDIR}/latest"
406
  download_url "https://trunk.io/releases/latest" "${LATEST_FILE}"
407
  version=$(
408
    set -e
409
    lawk '/version:/{print $2}' "${LATEST_FILE}"
410
  )
411
  version_sha256=$(
412
    set -e
413
    lawk "/${PLATFORM_UNDERSCORE}:/"'{print $2}' "${LATEST_FILE}"
414
  )
415
fi
416

417
readonly TOOL_PART="${version}-${PLATFORM}"
418
readonly TOOL_DIR="${CLI_DIR}/${TOOL_PART}"
419

420
if [[ ! -e ${TOOL_DIR}/trunk ]]; then
421
  download_cli "${version}" "${version_sha256:-}"
422
  echo # add newline between launcher and CLI output
423
fi
424

425
if [[ ${TRUNK_LAUNCHER_QUIET} != false ]]; then
426
  exec 1>&3 3>&- 2>&4 4>&-
427
fi
428

429
###############################################################################
430
#                                                                             #
431
#   CLI invocation                                                            #
432
#                                                                             #
433
###############################################################################
434

435
if [[ -n ${LATEST_FILE:-} ]]; then
436
  mv -n "${LATEST_FILE}" "${TOOL_DIR}/version" >/dev/null 2>&1 || true
437
fi
438

439
# NOTE: exec will overwrite the process image, so trap will not catch the exit signal.
440
# Therefore, run cleanup manually here.
441
cleanup 0
442

443
exec \
444
  env TRUNK_LAUNCHER_VERSION="${TRUNK_LAUNCHER_VERSION}" \
445
  env TRUNK_LAUNCHER_PATH="${BASH_SOURCE[0]}" \
446
  "${TOOL_DIR}/trunk" "$@"
447

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.