install.sh 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. #!/bin/bash
  2. # We don't need return codes for "$(command)", only stdout is needed.
  3. # Allow `[[ -n "$(command)" ]]`, `func "$(command)"`, pipes, etc.
  4. # shellcheck disable=SC2312
  5. set -u
  6. abort() {
  7. printf "%s\n" "$@" >&2
  8. exit 1
  9. }
  10. # Fail fast with a concise message when not using bash
  11. # Single brackets are needed here for POSIX compatibility
  12. # shellcheck disable=SC2292
  13. if [ -z "${BASH_VERSION:-}" ]
  14. then
  15. abort "Bash is required to interpret this script."
  16. fi
  17. # Check if script is run with force-interactive mode in CI
  18. if [[ -n "${CI-}" && -n "${INTERACTIVE-}" ]]
  19. then
  20. abort "Cannot run force-interactive mode in CI."
  21. fi
  22. # Check if both `INTERACTIVE` and `NONINTERACTIVE` are set
  23. # Always use single-quoted strings with `exp` expressions
  24. # shellcheck disable=SC2016
  25. if [[ -n "${INTERACTIVE-}" && -n "${NONINTERACTIVE-}" ]]
  26. then
  27. abort 'Both `$INTERACTIVE` and `$NONINTERACTIVE` are set. Please unset at least one variable and try again.'
  28. fi
  29. # Check if script is run in POSIX mode
  30. if [[ -n "${POSIXLY_CORRECT+1}" ]]
  31. then
  32. abort 'Bash must not run in POSIX mode. Please unset POSIXLY_CORRECT and try again.'
  33. fi
  34. usage() {
  35. cat <<EOS
  36. Homebrew Installer
  37. Usage: [NONINTERACTIVE=1] [CI=1] install.sh [options]
  38. -h, --help Display this message.
  39. NONINTERACTIVE Install without prompting for user input
  40. CI Install in CI mode (e.g. do not prompt for user input)
  41. EOS
  42. exit "${1:-0}"
  43. }
  44. while [[ $# -gt 0 ]]
  45. do
  46. case "$1" in
  47. -h | --help) usage ;;
  48. *)
  49. warn "Unrecognized option: '$1'"
  50. usage 1
  51. ;;
  52. esac
  53. done
  54. # string formatters
  55. if [[ -t 1 ]]
  56. then
  57. tty_escape() { printf "\033[%sm" "$1"; }
  58. else
  59. tty_escape() { :; }
  60. fi
  61. tty_mkbold() { tty_escape "1;$1"; }
  62. tty_underline="$(tty_escape "4;39")"
  63. tty_blue="$(tty_mkbold 34)"
  64. tty_red="$(tty_mkbold 31)"
  65. tty_bold="$(tty_mkbold 39)"
  66. tty_reset="$(tty_escape 0)"
  67. shell_join() {
  68. local arg
  69. printf "%s" "$1"
  70. shift
  71. for arg in "$@"
  72. do
  73. printf " "
  74. printf "%s" "${arg// /\ }"
  75. done
  76. }
  77. chomp() {
  78. printf "%s" "${1/"$'\n'"/}"
  79. }
  80. ohai() {
  81. printf "${tty_blue}==>${tty_bold} %s${tty_reset}\n" "$(shell_join "$@")"
  82. }
  83. warn() {
  84. printf "${tty_red}Warning${tty_reset}: %s\n" "$(chomp "$1")" >&2
  85. }
  86. # Check if script is run non-interactively (e.g. CI)
  87. # If it is run non-interactively we should not prompt for passwords.
  88. # Always use single-quoted strings with `exp` expressions
  89. # shellcheck disable=SC2016
  90. if [[ -z "${NONINTERACTIVE-}" ]]
  91. then
  92. if [[ -n "${CI-}" ]]
  93. then
  94. warn 'Running in non-interactive mode because `$CI` is set.'
  95. NONINTERACTIVE=1
  96. elif [[ ! -t 0 ]]
  97. then
  98. if [[ -z "${INTERACTIVE-}" ]]
  99. then
  100. warn 'Running in non-interactive mode because `stdin` is not a TTY.'
  101. NONINTERACTIVE=1
  102. else
  103. warn 'Running in interactive mode despite `stdin` not being a TTY because `$INTERACTIVE` is set.'
  104. fi
  105. fi
  106. else
  107. ohai 'Running in non-interactive mode because `$NONINTERACTIVE` is set.'
  108. fi
  109. # USER isn't always set so provide a fall back for the installer and subprocesses.
  110. if [[ -z "${USER-}" ]]
  111. then
  112. USER="$(chomp "$(id -un)")"
  113. export USER
  114. fi
  115. # First check OS.
  116. OS="$(uname)"
  117. if [[ "${OS}" == "Linux" ]]
  118. then
  119. HOMEBREW_ON_LINUX=1
  120. elif [[ "${OS}" == "Darwin" ]]
  121. then
  122. HOMEBREW_ON_MACOS=1
  123. else
  124. abort "Homebrew is only supported on macOS and Linux."
  125. fi
  126. # Required installation paths. To install elsewhere (which is unsupported)
  127. # you can untar https://github.com/Homebrew/brew/tarball/master
  128. # anywhere you like.
  129. if [[ -n "${HOMEBREW_ON_MACOS-}" ]]
  130. then
  131. UNAME_MACHINE="$(/usr/bin/uname -m)"
  132. if [[ "${UNAME_MACHINE}" == "arm64" ]]
  133. then
  134. # On ARM macOS, this script installs to /opt/homebrew only
  135. HOMEBREW_PREFIX="/opt/homebrew"
  136. HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}"
  137. else
  138. # On Intel macOS, this script installs to /usr/local only
  139. HOMEBREW_PREFIX="/usr/local"
  140. HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}/Homebrew"
  141. fi
  142. HOMEBREW_CACHE="${HOME}/Library/Caches/Homebrew"
  143. STAT_PRINTF=("/usr/bin/stat" "-f")
  144. PERMISSION_FORMAT="%A"
  145. CHOWN=("/usr/sbin/chown")
  146. CHGRP=("/usr/bin/chgrp")
  147. GROUP="admin"
  148. TOUCH=("/usr/bin/touch")
  149. INSTALL=("/usr/bin/install" -d -o "root" -g "wheel" -m "0755")
  150. else
  151. UNAME_MACHINE="$(uname -m)"
  152. # On Linux, this script installs to /home/linuxbrew/.linuxbrew only
  153. HOMEBREW_PREFIX="/home/linuxbrew/.linuxbrew"
  154. HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}/Homebrew"
  155. HOMEBREW_CACHE="${HOME}/.cache/Homebrew"
  156. STAT_PRINTF=("/usr/bin/stat" "--printf")
  157. PERMISSION_FORMAT="%a"
  158. CHOWN=("/bin/chown")
  159. CHGRP=("/bin/chgrp")
  160. GROUP="$(id -gn)"
  161. TOUCH=("/bin/touch")
  162. INSTALL=("/usr/bin/install" -d -o "${USER}" -g "${GROUP}" -m "0755")
  163. fi
  164. CHMOD=("/bin/chmod")
  165. MKDIR=("/bin/mkdir" "-p")
  166. HOMEBREW_BREW_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/brew"
  167. HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/homebrew-core"
  168. # Use remote URLs of Homebrew repositories from environment if set.
  169. HOMEBREW_BREW_GIT_REMOTE="${HOMEBREW_BREW_GIT_REMOTE:-"${HOMEBREW_BREW_DEFAULT_GIT_REMOTE}"}"
  170. HOMEBREW_CORE_GIT_REMOTE="${HOMEBREW_CORE_GIT_REMOTE:-"${HOMEBREW_CORE_DEFAULT_GIT_REMOTE}"}"
  171. # The URLs with and without the '.git' suffix are the same Git remote. Do not prompt.
  172. if [[ "${HOMEBREW_BREW_GIT_REMOTE}" == "${HOMEBREW_BREW_DEFAULT_GIT_REMOTE}.git" ]]
  173. then
  174. HOMEBREW_BREW_GIT_REMOTE="${HOMEBREW_BREW_DEFAULT_GIT_REMOTE}"
  175. fi
  176. if [[ "${HOMEBREW_CORE_GIT_REMOTE}" == "${HOMEBREW_CORE_DEFAULT_GIT_REMOTE}.git" ]]
  177. then
  178. HOMEBREW_CORE_GIT_REMOTE="${HOMEBREW_CORE_DEFAULT_GIT_REMOTE}"
  179. fi
  180. export HOMEBREW_{BREW,CORE}_GIT_REMOTE
  181. # TODO: bump version when new macOS is released or announced
  182. MACOS_NEWEST_UNSUPPORTED="15.0"
  183. # TODO: bump version when new macOS is released
  184. MACOS_OLDEST_SUPPORTED="12.0"
  185. # For Homebrew on Linux
  186. REQUIRED_RUBY_VERSION=2.6 # https://github.com/Homebrew/brew/pull/6556
  187. REQUIRED_GLIBC_VERSION=2.13 # https://docs.brew.sh/Homebrew-on-Linux#requirements
  188. REQUIRED_CURL_VERSION=7.41.0 # HOMEBREW_MINIMUM_CURL_VERSION in brew.sh in Homebrew/brew
  189. REQUIRED_GIT_VERSION=2.7.0 # HOMEBREW_MINIMUM_GIT_VERSION in brew.sh in Homebrew/brew
  190. # no analytics during installation
  191. export HOMEBREW_NO_ANALYTICS_THIS_RUN=1
  192. export HOMEBREW_NO_ANALYTICS_MESSAGE_OUTPUT=1
  193. unset HAVE_SUDO_ACCESS # unset this from the environment
  194. have_sudo_access() {
  195. if [[ ! -x "/usr/bin/sudo" ]]
  196. then
  197. return 1
  198. fi
  199. local -a SUDO=("/usr/bin/sudo")
  200. if [[ -n "${SUDO_ASKPASS-}" ]]
  201. then
  202. SUDO+=("-A")
  203. elif [[ -n "${NONINTERACTIVE-}" ]]
  204. then
  205. SUDO+=("-n")
  206. fi
  207. if [[ -z "${HAVE_SUDO_ACCESS-}" ]]
  208. then
  209. if [[ -n "${NONINTERACTIVE-}" ]]
  210. then
  211. "${SUDO[@]}" -l mkdir &>/dev/null
  212. else
  213. "${SUDO[@]}" -v && "${SUDO[@]}" -l mkdir &>/dev/null
  214. fi
  215. HAVE_SUDO_ACCESS="$?"
  216. fi
  217. if [[ -n "${HOMEBREW_ON_MACOS-}" ]] && [[ "${HAVE_SUDO_ACCESS}" -ne 0 ]]
  218. then
  219. abort "Need sudo access on macOS (e.g. the user ${USER} needs to be an Administrator)!"
  220. fi
  221. return "${HAVE_SUDO_ACCESS}"
  222. }
  223. execute() {
  224. if ! "$@"
  225. then
  226. abort "$(printf "Failed during: %s" "$(shell_join "$@")")"
  227. fi
  228. }
  229. execute_sudo() {
  230. local -a args=("$@")
  231. if [[ "${EUID:-${UID}}" != "0" ]] && have_sudo_access
  232. then
  233. if [[ -n "${SUDO_ASKPASS-}" ]]
  234. then
  235. args=("-A" "${args[@]}")
  236. fi
  237. ohai "/usr/bin/sudo" "${args[@]}"
  238. execute "/usr/bin/sudo" "${args[@]}"
  239. else
  240. ohai "${args[@]}"
  241. execute "${args[@]}"
  242. fi
  243. }
  244. getc() {
  245. local save_state
  246. save_state="$(/bin/stty -g)"
  247. /bin/stty raw -echo
  248. IFS='' read -r -n 1 -d '' "$@"
  249. /bin/stty "${save_state}"
  250. }
  251. ring_bell() {
  252. # Use the shell's audible bell.
  253. if [[ -t 1 ]]
  254. then
  255. printf "\a"
  256. fi
  257. }
  258. wait_for_user() {
  259. local c
  260. echo
  261. echo "Press ${tty_bold}RETURN${tty_reset}/${tty_bold}ENTER${tty_reset} to continue or any other key to abort:"
  262. getc c
  263. # we test for \r and \n because some stuff does \r instead
  264. if ! [[ "${c}" == $'\r' || "${c}" == $'\n' ]]
  265. then
  266. exit 1
  267. fi
  268. }
  269. major_minor() {
  270. echo "${1%%.*}.$(
  271. x="${1#*.}"
  272. echo "${x%%.*}"
  273. )"
  274. }
  275. version_gt() {
  276. [[ "${1%.*}" -gt "${2%.*}" ]] || [[ "${1%.*}" -eq "${2%.*}" && "${1#*.}" -gt "${2#*.}" ]]
  277. }
  278. version_ge() {
  279. [[ "${1%.*}" -gt "${2%.*}" ]] || [[ "${1%.*}" -eq "${2%.*}" && "${1#*.}" -ge "${2#*.}" ]]
  280. }
  281. version_lt() {
  282. [[ "${1%.*}" -lt "${2%.*}" ]] || [[ "${1%.*}" -eq "${2%.*}" && "${1#*.}" -lt "${2#*.}" ]]
  283. }
  284. check_run_command_as_root() {
  285. [[ "${EUID:-${UID}}" == "0" ]] || return
  286. # Allow Azure Pipelines/GitHub Actions/Docker/Concourse/Kubernetes to do everything as root (as it's normal there)
  287. [[ -f /.dockerenv ]] && return
  288. [[ -f /run/.containerenv ]] && return
  289. [[ -f /proc/1/cgroup ]] && grep -E "azpl_job|actions_job|docker|garden|kubepods" -q /proc/1/cgroup && return
  290. abort "Don't run this as root!"
  291. }
  292. should_install_command_line_tools() {
  293. if [[ -n "${HOMEBREW_ON_LINUX-}" ]]
  294. then
  295. return 1
  296. fi
  297. if version_gt "${macos_version}" "10.13"
  298. then
  299. ! [[ -e "/Library/Developer/CommandLineTools/usr/bin/git" ]]
  300. else
  301. ! [[ -e "/Library/Developer/CommandLineTools/usr/bin/git" ]] ||
  302. ! [[ -e "/usr/include/iconv.h" ]]
  303. fi
  304. }
  305. get_permission() {
  306. "${STAT_PRINTF[@]}" "${PERMISSION_FORMAT}" "$1"
  307. }
  308. user_only_chmod() {
  309. [[ -d "$1" ]] && [[ "$(get_permission "$1")" != 75[0145] ]]
  310. }
  311. exists_but_not_writable() {
  312. [[ -e "$1" ]] && ! [[ -r "$1" && -w "$1" && -x "$1" ]]
  313. }
  314. get_owner() {
  315. "${STAT_PRINTF[@]}" "%u" "$1"
  316. }
  317. file_not_owned() {
  318. [[ "$(get_owner "$1")" != "$(id -u)" ]]
  319. }
  320. get_group() {
  321. "${STAT_PRINTF[@]}" "%g" "$1"
  322. }
  323. file_not_grpowned() {
  324. [[ " $(id -G "${USER}") " != *" $(get_group "$1") "* ]]
  325. }
  326. # Please sync with 'test_ruby()' in 'Library/Homebrew/utils/ruby.sh' from the Homebrew/brew repository.
  327. test_ruby() {
  328. if [[ ! -x "$1" ]]
  329. then
  330. return 1
  331. fi
  332. "$1" --enable-frozen-string-literal --disable=gems,did_you_mean,rubyopt -rrubygems -e \
  333. "abort if Gem::Version.new(RUBY_VERSION.to_s.dup).to_s.split('.').first(2) != \
  334. Gem::Version.new('${REQUIRED_RUBY_VERSION}').to_s.split('.').first(2)" 2>/dev/null
  335. }
  336. test_curl() {
  337. if [[ ! -x "$1" ]]
  338. then
  339. return 1
  340. fi
  341. local curl_version_output curl_name_and_version
  342. curl_version_output="$("$1" --version 2>/dev/null)"
  343. curl_name_and_version="${curl_version_output%% (*}"
  344. version_ge "$(major_minor "${curl_name_and_version##* }")" "$(major_minor "${REQUIRED_CURL_VERSION}")"
  345. }
  346. test_git() {
  347. if [[ ! -x "$1" ]]
  348. then
  349. return 1
  350. fi
  351. local git_version_output
  352. git_version_output="$("$1" --version 2>/dev/null)"
  353. if [[ "${git_version_output}" =~ "git version "([^ ]*).* ]]
  354. then
  355. version_ge "$(major_minor "${BASH_REMATCH[1]}")" "$(major_minor "${REQUIRED_GIT_VERSION}")"
  356. else
  357. abort "Unexpected Git version: '${git_version_output}'!"
  358. fi
  359. }
  360. # Search for the given executable in PATH (avoids a dependency on the `which` command)
  361. which() {
  362. # Alias to Bash built-in command `type -P`
  363. type -P "$@"
  364. }
  365. # Search PATH for the specified program that satisfies Homebrew requirements
  366. # function which is set above
  367. # shellcheck disable=SC2230
  368. find_tool() {
  369. if [[ $# -ne 1 ]]
  370. then
  371. return 1
  372. fi
  373. local executable
  374. while read -r executable
  375. do
  376. if [[ "${executable}" != /* ]]
  377. then
  378. warn "Ignoring ${executable} (relative paths don't work)"
  379. elif "test_$1" "${executable}"
  380. then
  381. echo "${executable}"
  382. break
  383. fi
  384. done < <(which -a "$1")
  385. }
  386. no_usable_ruby() {
  387. [[ -z "$(find_tool ruby)" ]]
  388. }
  389. outdated_glibc() {
  390. local glibc_version
  391. glibc_version="$(ldd --version | head -n1 | grep -o '[0-9.]*$' | grep -o '^[0-9]\+\.[0-9]\+')"
  392. version_lt "${glibc_version}" "${REQUIRED_GLIBC_VERSION}"
  393. }
  394. if [[ -n "${HOMEBREW_ON_LINUX-}" ]] && no_usable_ruby && outdated_glibc
  395. then
  396. abort "$(
  397. cat <<EOABORT
  398. Homebrew requires Ruby ${REQUIRED_RUBY_VERSION} which was not found on your system.
  399. Homebrew portable Ruby requires Glibc version ${REQUIRED_GLIBC_VERSION} or newer,
  400. and your Glibc version is too old. See:
  401. ${tty_underline}https://docs.brew.sh/Homebrew-on-Linux#requirements${tty_reset}
  402. Please install Ruby ${REQUIRED_RUBY_VERSION} and add its location to your PATH.
  403. EOABORT
  404. )"
  405. fi
  406. # Invalidate sudo timestamp before exiting (if it wasn't active before).
  407. if [[ -x /usr/bin/sudo ]] && ! /usr/bin/sudo -n -v 2>/dev/null
  408. then
  409. trap '/usr/bin/sudo -k' EXIT
  410. fi
  411. # Things can fail later if `pwd` doesn't exist.
  412. # Also sudo prints a warning message for no good reason
  413. cd "/usr" || exit 1
  414. ####################################################################### script
  415. # shellcheck disable=SC2016
  416. ohai 'Checking for `sudo` access (which may request your password)...'
  417. if [[ -n "${HOMEBREW_ON_MACOS-}" ]]
  418. then
  419. [[ "${EUID:-${UID}}" == "0" ]] || have_sudo_access
  420. elif ! [[ -w "${HOMEBREW_PREFIX}" ]] &&
  421. ! [[ -w "/home/linuxbrew" ]] &&
  422. ! [[ -w "/home" ]] &&
  423. ! have_sudo_access
  424. then
  425. abort "$(
  426. cat <<EOABORT
  427. Insufficient permissions to install Homebrew to \"${HOMEBREW_PREFIX}\" (the default prefix).
  428. Alternative (unsupported) installation methods are available at:
  429. https://docs.brew.sh/Installation#alternative-installs
  430. Please note this will require most formula to build from source, a buggy, slow and energy-inefficient experience.
  431. We will close any issues without response for these unsupported configurations.
  432. EOABORT
  433. )"
  434. fi
  435. HOMEBREW_CORE="${HOMEBREW_REPOSITORY}/Library/Taps/homebrew/homebrew-core"
  436. check_run_command_as_root
  437. if [[ -d "${HOMEBREW_PREFIX}" && ! -x "${HOMEBREW_PREFIX}" ]]
  438. then
  439. abort "$(
  440. cat <<EOABORT
  441. The Homebrew prefix ${tty_underline}${HOMEBREW_PREFIX}${tty_reset} exists but is not searchable.
  442. If this is not intentional, please restore the default permissions and
  443. try running the installer again:
  444. sudo chmod 775 ${HOMEBREW_PREFIX}
  445. EOABORT
  446. )"
  447. fi
  448. if [[ -n "${HOMEBREW_ON_MACOS-}" ]]
  449. then
  450. # On macOS, support 64-bit Intel and ARM
  451. if [[ "${UNAME_MACHINE}" != "arm64" ]] && [[ "${UNAME_MACHINE}" != "x86_64" ]]
  452. then
  453. abort "Homebrew is only supported on Intel and ARM processors!"
  454. fi
  455. else
  456. # On Linux, support only 64-bit Intel
  457. if [[ "${UNAME_MACHINE}" == "aarch64" ]]
  458. then
  459. abort "$(
  460. cat <<EOABORT
  461. Homebrew on Linux is not supported on ARM processors.
  462. ${tty_underline}https://docs.brew.sh/Homebrew-on-Linux#arm-unsupported${tty_reset}
  463. EOABORT
  464. )"
  465. elif [[ "${UNAME_MACHINE}" != "x86_64" ]]
  466. then
  467. abort "Homebrew on Linux is only supported on Intel processors!"
  468. fi
  469. fi
  470. if [[ -n "${HOMEBREW_ON_MACOS-}" ]]
  471. then
  472. macos_version="$(major_minor "$(/usr/bin/sw_vers -productVersion)")"
  473. if version_lt "${macos_version}" "10.7"
  474. then
  475. abort "$(
  476. cat <<EOABORT
  477. Your Mac OS X version is too old. See:
  478. ${tty_underline}https://github.com/mistydemeo/tigerbrew${tty_reset}
  479. EOABORT
  480. )"
  481. elif version_lt "${macos_version}" "10.11"
  482. then
  483. abort "Your OS X version is too old."
  484. elif version_ge "${macos_version}" "${MACOS_NEWEST_UNSUPPORTED}" ||
  485. version_lt "${macos_version}" "${MACOS_OLDEST_SUPPORTED}"
  486. then
  487. who="We"
  488. what=""
  489. if version_ge "${macos_version}" "${MACOS_NEWEST_UNSUPPORTED}"
  490. then
  491. what="pre-release version"
  492. else
  493. who+=" (and Apple)"
  494. what="old version"
  495. fi
  496. ohai "You are using macOS ${macos_version}."
  497. ohai "${who} do not provide support for this ${what}."
  498. echo "$(
  499. cat <<EOS
  500. This installation may not succeed.
  501. After installation, you will encounter build failures with some formulae.
  502. Please create pull requests instead of asking for help on Homebrew\'s GitHub,
  503. Twitter or any other official channels. You are responsible for resolving any
  504. issues you experience while you are running this ${what}.
  505. EOS
  506. )
  507. " | tr -d "\\"
  508. fi
  509. fi
  510. ohai "This script will install:"
  511. echo "${HOMEBREW_PREFIX}/bin/brew"
  512. echo "${HOMEBREW_PREFIX}/share/doc/homebrew"
  513. echo "${HOMEBREW_PREFIX}/share/man/man1/brew.1"
  514. echo "${HOMEBREW_PREFIX}/share/zsh/site-functions/_brew"
  515. echo "${HOMEBREW_PREFIX}/etc/bash_completion.d/brew"
  516. echo "${HOMEBREW_REPOSITORY}"
  517. # Keep relatively in sync with
  518. # https://github.com/Homebrew/brew/blob/master/Library/Homebrew/keg.rb
  519. directories=(
  520. bin etc include lib sbin share opt var
  521. Frameworks
  522. etc/bash_completion.d lib/pkgconfig
  523. share/aclocal share/doc share/info share/locale share/man
  524. share/man/man1 share/man/man2 share/man/man3 share/man/man4
  525. share/man/man5 share/man/man6 share/man/man7 share/man/man8
  526. var/log var/homebrew var/homebrew/linked
  527. bin/brew
  528. )
  529. group_chmods=()
  530. for dir in "${directories[@]}"
  531. do
  532. if exists_but_not_writable "${HOMEBREW_PREFIX}/${dir}"
  533. then
  534. group_chmods+=("${HOMEBREW_PREFIX}/${dir}")
  535. fi
  536. done
  537. # zsh refuses to read from these directories if group writable
  538. directories=(share/zsh share/zsh/site-functions)
  539. zsh_dirs=()
  540. for dir in "${directories[@]}"
  541. do
  542. zsh_dirs+=("${HOMEBREW_PREFIX}/${dir}")
  543. done
  544. directories=(
  545. bin etc include lib sbin share var opt
  546. share/zsh share/zsh/site-functions
  547. var/homebrew var/homebrew/linked
  548. Cellar Caskroom Frameworks
  549. )
  550. mkdirs=()
  551. for dir in "${directories[@]}"
  552. do
  553. if ! [[ -d "${HOMEBREW_PREFIX}/${dir}" ]]
  554. then
  555. mkdirs+=("${HOMEBREW_PREFIX}/${dir}")
  556. fi
  557. done
  558. user_chmods=()
  559. mkdirs_user_only=()
  560. if [[ "${#zsh_dirs[@]}" -gt 0 ]]
  561. then
  562. for dir in "${zsh_dirs[@]}"
  563. do
  564. if [[ ! -d "${dir}" ]]
  565. then
  566. mkdirs_user_only+=("${dir}")
  567. elif user_only_chmod "${dir}"
  568. then
  569. user_chmods+=("${dir}")
  570. fi
  571. done
  572. fi
  573. chmods=()
  574. if [[ "${#group_chmods[@]}" -gt 0 ]]
  575. then
  576. chmods+=("${group_chmods[@]}")
  577. fi
  578. if [[ "${#user_chmods[@]}" -gt 0 ]]
  579. then
  580. chmods+=("${user_chmods[@]}")
  581. fi
  582. chowns=()
  583. chgrps=()
  584. if [[ "${#chmods[@]}" -gt 0 ]]
  585. then
  586. for dir in "${chmods[@]}"
  587. do
  588. if file_not_owned "${dir}"
  589. then
  590. chowns+=("${dir}")
  591. fi
  592. if file_not_grpowned "${dir}"
  593. then
  594. chgrps+=("${dir}")
  595. fi
  596. done
  597. fi
  598. if [[ "${#group_chmods[@]}" -gt 0 ]]
  599. then
  600. ohai "The following existing directories will be made group writable:"
  601. printf "%s\n" "${group_chmods[@]}"
  602. fi
  603. if [[ "${#user_chmods[@]}" -gt 0 ]]
  604. then
  605. ohai "The following existing directories will be made writable by user only:"
  606. printf "%s\n" "${user_chmods[@]}"
  607. fi
  608. if [[ "${#chowns[@]}" -gt 0 ]]
  609. then
  610. ohai "The following existing directories will have their owner set to ${tty_underline}${USER}${tty_reset}:"
  611. printf "%s\n" "${chowns[@]}"
  612. fi
  613. if [[ "${#chgrps[@]}" -gt 0 ]]
  614. then
  615. ohai "The following existing directories will have their group set to ${tty_underline}${GROUP}${tty_reset}:"
  616. printf "%s\n" "${chgrps[@]}"
  617. fi
  618. if [[ "${#mkdirs[@]}" -gt 0 ]]
  619. then
  620. ohai "The following new directories will be created:"
  621. printf "%s\n" "${mkdirs[@]}"
  622. fi
  623. if should_install_command_line_tools
  624. then
  625. ohai "The Xcode Command Line Tools will be installed."
  626. fi
  627. non_default_repos=""
  628. additional_shellenv_commands=()
  629. if [[ "${HOMEBREW_BREW_DEFAULT_GIT_REMOTE}" != "${HOMEBREW_BREW_GIT_REMOTE}" ]]
  630. then
  631. ohai "HOMEBREW_BREW_GIT_REMOTE is set to a non-default URL:"
  632. echo "${tty_underline}${HOMEBREW_BREW_GIT_REMOTE}${tty_reset} will be used as the Homebrew/brew Git remote."
  633. non_default_repos="Homebrew/brew"
  634. additional_shellenv_commands+=("export HOMEBREW_BREW_GIT_REMOTE=\"${HOMEBREW_BREW_GIT_REMOTE}\"")
  635. fi
  636. if [[ "${HOMEBREW_CORE_DEFAULT_GIT_REMOTE}" != "${HOMEBREW_CORE_GIT_REMOTE}" ]]
  637. then
  638. ohai "HOMEBREW_CORE_GIT_REMOTE is set to a non-default URL:"
  639. echo "${tty_underline}${HOMEBREW_CORE_GIT_REMOTE}${tty_reset} will be used as the Homebrew/homebrew-core Git remote."
  640. non_default_repos="${non_default_repos:-}${non_default_repos:+ and }Homebrew/homebrew-core"
  641. additional_shellenv_commands+=("export HOMEBREW_CORE_GIT_REMOTE=\"${HOMEBREW_CORE_GIT_REMOTE}\"")
  642. fi
  643. if [[ -n "${HOMEBREW_NO_INSTALL_FROM_API-}" ]]
  644. then
  645. ohai "HOMEBREW_NO_INSTALL_FROM_API is set."
  646. echo "Homebrew/homebrew-core will be tapped during this ${tty_bold}install${tty_reset} run."
  647. fi
  648. if [[ -z "${NONINTERACTIVE-}" ]]
  649. then
  650. ring_bell
  651. wait_for_user
  652. fi
  653. if [[ -d "${HOMEBREW_PREFIX}" ]]
  654. then
  655. if [[ "${#chmods[@]}" -gt 0 ]]
  656. then
  657. execute_sudo "${CHMOD[@]}" "u+rwx" "${chmods[@]}"
  658. fi
  659. if [[ "${#group_chmods[@]}" -gt 0 ]]
  660. then
  661. execute_sudo "${CHMOD[@]}" "g+rwx" "${group_chmods[@]}"
  662. fi
  663. if [[ "${#user_chmods[@]}" -gt 0 ]]
  664. then
  665. execute_sudo "${CHMOD[@]}" "go-w" "${user_chmods[@]}"
  666. fi
  667. if [[ "${#chowns[@]}" -gt 0 ]]
  668. then
  669. execute_sudo "${CHOWN[@]}" "${USER}" "${chowns[@]}"
  670. fi
  671. if [[ "${#chgrps[@]}" -gt 0 ]]
  672. then
  673. execute_sudo "${CHGRP[@]}" "${GROUP}" "${chgrps[@]}"
  674. fi
  675. else
  676. execute_sudo "${INSTALL[@]}" "${HOMEBREW_PREFIX}"
  677. fi
  678. if [[ "${#mkdirs[@]}" -gt 0 ]]
  679. then
  680. execute_sudo "${MKDIR[@]}" "${mkdirs[@]}"
  681. execute_sudo "${CHMOD[@]}" "ug=rwx" "${mkdirs[@]}"
  682. if [[ "${#mkdirs_user_only[@]}" -gt 0 ]]
  683. then
  684. execute_sudo "${CHMOD[@]}" "go-w" "${mkdirs_user_only[@]}"
  685. fi
  686. execute_sudo "${CHOWN[@]}" "${USER}" "${mkdirs[@]}"
  687. execute_sudo "${CHGRP[@]}" "${GROUP}" "${mkdirs[@]}"
  688. fi
  689. if ! [[ -d "${HOMEBREW_REPOSITORY}" ]]
  690. then
  691. execute_sudo "${MKDIR[@]}" "${HOMEBREW_REPOSITORY}"
  692. fi
  693. execute_sudo "${CHOWN[@]}" "-R" "${USER}:${GROUP}" "${HOMEBREW_REPOSITORY}"
  694. if ! [[ -d "${HOMEBREW_CACHE}" ]]
  695. then
  696. if [[ -n "${HOMEBREW_ON_MACOS-}" ]]
  697. then
  698. execute_sudo "${MKDIR[@]}" "${HOMEBREW_CACHE}"
  699. else
  700. execute "${MKDIR[@]}" "${HOMEBREW_CACHE}"
  701. fi
  702. fi
  703. if exists_but_not_writable "${HOMEBREW_CACHE}"
  704. then
  705. execute_sudo "${CHMOD[@]}" "g+rwx" "${HOMEBREW_CACHE}"
  706. fi
  707. if file_not_owned "${HOMEBREW_CACHE}"
  708. then
  709. execute_sudo "${CHOWN[@]}" "-R" "${USER}" "${HOMEBREW_CACHE}"
  710. fi
  711. if file_not_grpowned "${HOMEBREW_CACHE}"
  712. then
  713. execute_sudo "${CHGRP[@]}" "-R" "${GROUP}" "${HOMEBREW_CACHE}"
  714. fi
  715. if [[ -d "${HOMEBREW_CACHE}" ]]
  716. then
  717. execute "${TOUCH[@]}" "${HOMEBREW_CACHE}/.cleaned"
  718. fi
  719. if should_install_command_line_tools && version_ge "${macos_version}" "10.13"
  720. then
  721. ohai "Searching online for the Command Line Tools"
  722. # This temporary file prompts the 'softwareupdate' utility to list the Command Line Tools
  723. clt_placeholder="/tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress"
  724. execute_sudo "${TOUCH[@]}" "${clt_placeholder}"
  725. clt_label_command="/usr/sbin/softwareupdate -l |
  726. grep -B 1 -E 'Command Line Tools' |
  727. awk -F'*' '/^ *\\*/ {print \$2}' |
  728. sed -e 's/^ *Label: //' -e 's/^ *//' |
  729. sort -V |
  730. tail -n1"
  731. clt_label="$(chomp "$(/bin/bash -c "${clt_label_command}")")"
  732. if [[ -n "${clt_label}" ]]
  733. then
  734. ohai "Installing ${clt_label}"
  735. execute_sudo "/usr/sbin/softwareupdate" "-i" "${clt_label}"
  736. execute_sudo "/usr/bin/xcode-select" "--switch" "/Library/Developer/CommandLineTools"
  737. fi
  738. execute_sudo "/bin/rm" "-f" "${clt_placeholder}"
  739. fi
  740. # Headless install may have failed, so fallback to original 'xcode-select' method
  741. if should_install_command_line_tools && test -t 0
  742. then
  743. ohai "Installing the Command Line Tools (expect a GUI popup):"
  744. execute "/usr/bin/xcode-select" "--install"
  745. echo "Press any key when the installation has completed."
  746. getc
  747. execute_sudo "/usr/bin/xcode-select" "--switch" "/Library/Developer/CommandLineTools"
  748. fi
  749. if [[ -n "${HOMEBREW_ON_MACOS-}" ]] && ! output="$(/usr/bin/xcrun clang 2>&1)" && [[ "${output}" == *"license"* ]]
  750. then
  751. abort "$(
  752. cat <<EOABORT
  753. You have not agreed to the Xcode license.
  754. Before running the installer again please agree to the license by opening
  755. Xcode.app or running:
  756. sudo xcodebuild -license
  757. EOABORT
  758. )"
  759. fi
  760. USABLE_GIT=/usr/bin/git
  761. if [[ -n "${HOMEBREW_ON_LINUX-}" ]]
  762. then
  763. USABLE_GIT="$(find_tool git)"
  764. if [[ -z "$(command -v git)" ]]
  765. then
  766. abort "$(
  767. cat <<EOABORT
  768. You must install Git before installing Homebrew. See:
  769. ${tty_underline}https://docs.brew.sh/Installation${tty_reset}
  770. EOABORT
  771. )"
  772. fi
  773. if [[ -z "${USABLE_GIT}" ]]
  774. then
  775. abort "$(
  776. cat <<EOABORT
  777. The version of Git that was found does not satisfy requirements for Homebrew.
  778. Please install Git ${REQUIRED_GIT_VERSION} or newer and add it to your PATH.
  779. EOABORT
  780. )"
  781. fi
  782. if [[ "${USABLE_GIT}" != /usr/bin/git ]]
  783. then
  784. export HOMEBREW_GIT_PATH="${USABLE_GIT}"
  785. ohai "Found Git: ${HOMEBREW_GIT_PATH}"
  786. fi
  787. fi
  788. if ! command -v curl >/dev/null
  789. then
  790. abort "$(
  791. cat <<EOABORT
  792. You must install cURL before installing Homebrew. See:
  793. ${tty_underline}https://docs.brew.sh/Installation${tty_reset}
  794. EOABORT
  795. )"
  796. elif [[ -n "${HOMEBREW_ON_LINUX-}" ]]
  797. then
  798. USABLE_CURL="$(find_tool curl)"
  799. if [[ -z "${USABLE_CURL}" ]]
  800. then
  801. abort "$(
  802. cat <<EOABORT
  803. The version of cURL that was found does not satisfy requirements for Homebrew.
  804. Please install cURL ${REQUIRED_CURL_VERSION} or newer and add it to your PATH.
  805. EOABORT
  806. )"
  807. elif [[ "${USABLE_CURL}" != /usr/bin/curl ]]
  808. then
  809. export HOMEBREW_CURL_PATH="${USABLE_CURL}"
  810. ohai "Found cURL: ${HOMEBREW_CURL_PATH}"
  811. fi
  812. fi
  813. ohai "Downloading and installing Homebrew..."
  814. (
  815. cd "${HOMEBREW_REPOSITORY}" >/dev/null || return
  816. # we do it in four steps to avoid merge errors when reinstalling
  817. execute "${USABLE_GIT}" "-c" "init.defaultBranch=master" "init" "--quiet"
  818. # "git remote add" will fail if the remote is defined in the global config
  819. execute "${USABLE_GIT}" "config" "remote.origin.url" "${HOMEBREW_BREW_GIT_REMOTE}"
  820. execute "${USABLE_GIT}" "config" "remote.origin.fetch" "+refs/heads/*:refs/remotes/origin/*"
  821. # ensure we don't munge line endings on checkout
  822. execute "${USABLE_GIT}" "config" "--bool" "core.autocrlf" "false"
  823. # make sure symlinks are saved as-is
  824. execute "${USABLE_GIT}" "config" "--bool" "core.symlinks" "true"
  825. execute "${USABLE_GIT}" "fetch" "--force" "origin"
  826. execute "${USABLE_GIT}" "fetch" "--force" "--tags" "origin"
  827. execute "${USABLE_GIT}" "remote" "set-head" "origin" "--auto" >/dev/null
  828. LATEST_GIT_TAG="$("${USABLE_GIT}" tag --list --sort="-version:refname" | head -n1)"
  829. if [[ -z "${LATEST_GIT_TAG}" ]]
  830. then
  831. abort "Failed to query latest Homebrew/brew Git tag."
  832. fi
  833. execute "${USABLE_GIT}" "checkout" "--force" "-B" "stable" "${LATEST_GIT_TAG}"
  834. if [[ "${HOMEBREW_REPOSITORY}" != "${HOMEBREW_PREFIX}" ]]
  835. then
  836. if [[ "${HOMEBREW_REPOSITORY}" == "${HOMEBREW_PREFIX}/Homebrew" ]]
  837. then
  838. execute "ln" "-sf" "../Homebrew/bin/brew" "${HOMEBREW_PREFIX}/bin/brew"
  839. else
  840. abort "The Homebrew/brew repository should be placed in the Homebrew prefix directory."
  841. fi
  842. fi
  843. if [[ -n "${HOMEBREW_NO_INSTALL_FROM_API-}" && ! -d "${HOMEBREW_CORE}" ]]
  844. then
  845. # Always use single-quoted strings with `exp` expressions
  846. # shellcheck disable=SC2016
  847. ohai 'Tapping homebrew/core because `$HOMEBREW_NO_INSTALL_FROM_API` is set.'
  848. (
  849. execute "${MKDIR[@]}" "${HOMEBREW_CORE}"
  850. cd "${HOMEBREW_CORE}" >/dev/null || return
  851. execute "${USABLE_GIT}" "-c" "init.defaultBranch=master" "init" "--quiet"
  852. execute "${USABLE_GIT}" "config" "remote.origin.url" "${HOMEBREW_CORE_GIT_REMOTE}"
  853. execute "${USABLE_GIT}" "config" "remote.origin.fetch" "+refs/heads/*:refs/remotes/origin/*"
  854. execute "${USABLE_GIT}" "config" "--bool" "core.autocrlf" "false"
  855. execute "${USABLE_GIT}" "config" "--bool" "core.symlinks" "true"
  856. execute "${USABLE_GIT}" "fetch" "--force" "origin" "refs/heads/master:refs/remotes/origin/master"
  857. execute "${USABLE_GIT}" "remote" "set-head" "origin" "--auto" >/dev/null
  858. execute "${USABLE_GIT}" "reset" "--hard" "origin/master"
  859. cd "${HOMEBREW_REPOSITORY}" >/dev/null || return
  860. ) || exit 1
  861. fi
  862. execute "${HOMEBREW_PREFIX}/bin/brew" "update" "--force" "--quiet"
  863. ) || exit 1
  864. if [[ ":${PATH}:" != *":${HOMEBREW_PREFIX}/bin:"* ]]
  865. then
  866. warn "${HOMEBREW_PREFIX}/bin is not in your PATH.
  867. Instructions on how to configure your shell for Homebrew
  868. can be found in the 'Next steps' section below."
  869. fi
  870. ohai "Installation successful!"
  871. echo
  872. ring_bell
  873. # Use an extra newline and bold to avoid this being missed.
  874. ohai "Homebrew has enabled anonymous aggregate formulae and cask analytics."
  875. echo "$(
  876. cat <<EOS
  877. ${tty_bold}Read the analytics documentation (and how to opt-out) here:
  878. ${tty_underline}https://docs.brew.sh/Analytics${tty_reset}
  879. No analytics data has been sent yet (nor will any be during this ${tty_bold}install${tty_reset} run).
  880. EOS
  881. )
  882. "
  883. ohai "Homebrew is run entirely by unpaid volunteers. Please consider donating:"
  884. echo "$(
  885. cat <<EOS
  886. ${tty_underline}https://github.com/Homebrew/brew#donations${tty_reset}
  887. EOS
  888. )
  889. "
  890. (
  891. cd "${HOMEBREW_REPOSITORY}" >/dev/null || return
  892. execute "${USABLE_GIT}" "config" "--replace-all" "homebrew.analyticsmessage" "true"
  893. execute "${USABLE_GIT}" "config" "--replace-all" "homebrew.caskanalyticsmessage" "true"
  894. ) || exit 1
  895. ohai "Next steps:"
  896. case "${SHELL}" in
  897. */bash*)
  898. if [[ -n "${HOMEBREW_ON_LINUX-}" ]]
  899. then
  900. shell_rcfile="${HOME}/.bashrc"
  901. else
  902. shell_rcfile="${HOME}/.bash_profile"
  903. fi
  904. ;;
  905. */zsh*)
  906. if [[ -n "${HOMEBREW_ON_LINUX-}" ]]
  907. then
  908. shell_rcfile="${ZDOTDIR:-"${HOME}"}/.zshrc"
  909. else
  910. shell_rcfile="${ZDOTDIR:-"${HOME}"}/.zprofile"
  911. fi
  912. ;;
  913. */fish*)
  914. shell_rcfile="${HOME}/.config/fish/config.fish"
  915. ;;
  916. *)
  917. shell_rcfile="${ENV:-"${HOME}/.profile"}"
  918. ;;
  919. esac
  920. if grep -qs "eval \"\$(${HOMEBREW_PREFIX}/bin/brew shellenv)\"" "${shell_rcfile}"
  921. then
  922. if ! [[ -x "$(command -v brew)" ]]
  923. then
  924. cat <<EOS
  925. - Run this command in your terminal to add Homebrew to your ${tty_bold}PATH${tty_reset}:
  926. eval "\$(${HOMEBREW_PREFIX}/bin/brew shellenv)"
  927. EOS
  928. fi
  929. else
  930. cat <<EOS
  931. - Run these two commands in your terminal to add Homebrew to your ${tty_bold}PATH${tty_reset}:
  932. (echo; echo 'eval "\$(${HOMEBREW_PREFIX}/bin/brew shellenv)"') >> ${shell_rcfile}
  933. eval "\$(${HOMEBREW_PREFIX}/bin/brew shellenv)"
  934. EOS
  935. fi
  936. if [[ -n "${non_default_repos}" ]]
  937. then
  938. plural=""
  939. if [[ "${#additional_shellenv_commands[@]}" -gt 1 ]]
  940. then
  941. plural="s"
  942. fi
  943. printf -- "- Run these commands in your terminal to add the non-default Git remote%s for %s:\n" "${plural}" "${non_default_repos}"
  944. printf " echo '# Set PATH, MANPATH, etc., for Homebrew.' >> %s\n" "${shell_rcfile}"
  945. printf " echo '%s' >> ${shell_rcfile}\n" "${additional_shellenv_commands[@]}"
  946. printf " %s\n" "${additional_shellenv_commands[@]}"
  947. fi
  948. if [[ -n "${HOMEBREW_ON_LINUX-}" ]]
  949. then
  950. echo "- Install Homebrew's dependencies if you have sudo access:"
  951. if [[ -x "$(command -v apt-get)" ]]
  952. then
  953. echo " sudo apt-get install build-essential"
  954. elif [[ -x "$(command -v yum)" ]]
  955. then
  956. echo " sudo yum groupinstall 'Development Tools'"
  957. elif [[ -x "$(command -v pacman)" ]]
  958. then
  959. echo " sudo pacman -S base-devel"
  960. elif [[ -x "$(command -v apk)" ]]
  961. then
  962. echo " sudo apk add build-base"
  963. fi
  964. cat <<EOS
  965. For more information, see:
  966. ${tty_underline}https://docs.brew.sh/Homebrew-on-Linux${tty_reset}
  967. - We recommend that you install GCC:
  968. brew install gcc
  969. EOS
  970. fi
  971. cat <<EOS
  972. - Run ${tty_bold}brew help${tty_reset} to get started
  973. - Further documentation:
  974. ${tty_underline}https://docs.brew.sh${tty_reset}
  975. EOS