install.sh 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. #!/bin/bash
  2. # exit on fail
  3. set -e
  4. #chromebrew directories
  5. : "${OWNER:=rainestorme}"
  6. : "${REPO:=chromebrew}"
  7. : "${BRANCH:=master}"
  8. URL="https://raw.githubusercontent.com/${OWNER}/${REPO}/${BRANCH}"
  9. : "${CREW_PREFIX:=/mnt/stateful_partition/murkmod/chromebrew}"
  10. CREW_LIB_PATH="${CREW_PREFIX}/lib/crew"
  11. CREW_CONFIG_PATH="${CREW_PREFIX}/etc/crew"
  12. CREW_BREW_DIR="${CREW_PREFIX}/tmp/crew"
  13. CREW_DEST_DIR="${CREW_BREW_DIR}/dest"
  14. CREW_PACKAGES_PATH="${CREW_LIB_PATH}/packages"
  15. : "${CURL:=/usr/bin/curl}"
  16. : "${CREW_CACHE_DIR:=$CREW_PREFIX/tmp/packages}"
  17. # For container usage, where we want to specify i686 arch
  18. # on a x86_64 host by setting ARCH=i686.
  19. : "${ARCH:=$(/usr/bin/uname -m)}"
  20. # For container usage, when we are emulating armv7l via linux32
  21. # /usr/bin/uname -m reports armv8l.
  22. ARCH="${ARCH/armv8l/armv7l}"
  23. # BOOTSTRAP_PACKAGES cannot depend on crew_profile_base for their core operations (completion scripts are fine)
  24. BOOTSTRAP_PACKAGES="crew_mvdir pixz ca_certificates ruby openssl"
  25. [ -x /usr/bin/zstd ] || BOOTSTRAP_PACKAGES="zstd ${BOOTSTRAP_PACKAGES}" # use system zstd if available
  26. # i686 requires gcc and openssl
  27. [ "${ARCH}" == "i686" ] && BOOTSTRAP_PACKAGES+=" gcc"
  28. RED='\e[1;91m'; # Use Light Red for errors.
  29. YELLOW='\e[1;33m'; # Use Yellow for informational messages.
  30. GREEN='\e[1;32m'; # Use Green for success messages.
  31. BLUE='\e[1;34m'; # Use Blue for intrafunction messages.
  32. GRAY='\e[0;37m'; # Use Gray for program output.
  33. MAGENTA='\e[1;35m';
  34. RESET='\e[0m'
  35. # Simplify colors and print errors to stderr (2).
  36. echo_error() { echo -e "${RED}${*}${RESET}" >&2; }
  37. echo_info() { echo -e "${YELLOW}${*}${RESET}" >&1; }
  38. echo_success() { echo -e "${GREEN}${*}${RESET}" >&1; }
  39. echo_intra() { echo -e "${BLUE}${*}${RESET}" >&1; }
  40. echo_out() { echo -e "${GRAY}${*}${RESET}" >&1; }
  41. echo_other() { echo -e "${MAGENTA}${*}${RESET}" >&2; }
  42. # Skip all checks if running on a docker container.
  43. [[ -f "/.dockerenv" ]] && CREW_FORCE_INSTALL=1
  44. # Reject crostini.
  45. if [[ -d /opt/google/cros-containers && "${CREW_FORCE_INSTALL}" != '1' ]]; then
  46. echo_error "Crostini containers are not supported by Chromebrew :/"
  47. echo_info "Run 'curl -Ls git.io/vddgY | CREW_FORCE_INSTALL=1 bash' to perform install anyway"
  48. exit 1
  49. fi
  50. # Disallow non-stable channels Chrome OS.
  51. if [ -f /etc/lsb-release ]; then
  52. if [[ ! "$(< /etc/lsb-release)" =~ CHROMEOS_RELEASE_TRACK=stable-channel$'\n' && "${CREW_FORCE_INSTALL}" != '1' ]]; then
  53. echo_error "The beta, dev, and canary channel are unsupported by Chromebrew"
  54. echo_info "Run 'curl -Ls git.io/vddgY | CREW_FORCE_INSTALL=1 bash' to perform install anyway"
  55. exit 1
  56. fi
  57. else
  58. echo_info "Unable to detect system information, installation will continue."
  59. fi
  60. if [ "${EUID}" == "0" ]; then
  61. echo_error "Chromebrew should not be installed or run as root."
  62. exit 1;
  63. fi
  64. echo_success "Welcome to Chromebrew!"
  65. # Prompt user to enter the sudo password if it set.
  66. # If the PASSWD_FILE specified by chromeos-setdevpasswd exist, that means a sudo password is set.
  67. if [[ "$(< /usr/sbin/chromeos-setdevpasswd)" =~ PASSWD_FILE=\'([^\']+) ]] && [ -f "${BASH_REMATCH[1]}" ]; then
  68. echo_intra "Please enter the developer mode password"
  69. # Reset sudo timeout.
  70. sudo -k
  71. sudo /bin/true
  72. fi
  73. # Force curl to use system libraries.
  74. function curl () {
  75. # Retry if download failed.
  76. # The --retry/--retry-all-errors parameter in curl will not work with
  77. # the 'curl: (7) Couldn't connect to server' error, a for loop is used
  78. # here.
  79. for (( i = 0; i < 4; i++ )); do
  80. # force TLS as we know GitLab supports it
  81. env -u LD_LIBRARY_PATH ${CURL} --ssl-reqd --tlsv1.2 -C - "${@}" && return 0
  82. echo_info "Retrying, $((3-i)) retries left."
  83. done
  84. # The download failed if we're still here.
  85. echo_error "Download failed :/ Please check your network settings."
  86. return 1
  87. }
  88. case "${ARCH}" in
  89. "i686"|"x86_64"|"armv7l"|"aarch64")
  90. LIB_SUFFIX=
  91. # See https://superuser.com/a/1369875
  92. # If /bin/bash is 64-bit, then set LIB_SUFFIX, as this is true on both
  93. # x86_64 and aarch64 userspace
  94. # shellcheck disable=SC2046
  95. [ $(od -An -t x1 -j 4 -N 1 /bin/bash) == 02 ] && LIB_SUFFIX='64'
  96. if [[ $LIB_SUFFIX == '64' ]] && [[ $ARCH == 'aarch64' ]]; then
  97. echo_error "Your device is not supported by Chromebrew yet :/"
  98. exit 1
  99. fi
  100. ;;
  101. *)
  102. echo_error "Your device is not supported by Chromebrew yet :/"
  103. exit 1
  104. ;;
  105. esac
  106. echo_info "\n\nDoing initial setup for install in ${CREW_PREFIX}."
  107. echo_info "This may take a while if there are preexisting files in ${CREW_PREFIX}...\n"
  108. # This will allow things to work without sudo.
  109. crew_folders="bin cache doc docbook etc include lib lib$LIB_SUFFIX libexec man sbin share tmp var"
  110. for folder in $crew_folders
  111. do
  112. if [ -d "${CREW_PREFIX}"/"${folder}" ]; then
  113. echo_intra "Resetting ownership of ${CREW_PREFIX}/${folder}"
  114. sudo chown -R "$(id -u)":"$(id -g)" "${CREW_PREFIX}"/"${folder}"
  115. fi
  116. done
  117. sudo chown "$(id -u)":"$(id -g)" "${CREW_PREFIX}"
  118. # Delete ${CREW_PREFIX}/{var,local} symlinks on some Chromium OS distro
  119. # if they exist.
  120. [ -L ${CREW_PREFIX}/var ] && sudo rm -f "${CREW_PREFIX}/var"
  121. [ -L ${CREW_PREFIX}/local ] && sudo rm -f "${CREW_PREFIX}/local"
  122. # Prepare directories.
  123. for dir in "${CREW_CONFIG_PATH}/meta" "${CREW_DEST_DIR}" "${CREW_PACKAGES_PATH}" "${CREW_CACHE_DIR}" ; do
  124. if [ ! -d "${dir}" ]; then
  125. mkdir -p "${dir}"
  126. fi
  127. done
  128. echo_info "\nDownloading information for Bootstrap packages..."
  129. echo -en "${GRAY}"
  130. # Use parallel mode if available.
  131. CURL_OPTS="-OL"
  132. [[ "$(curl --help curl)" =~ --parallel ]] && CURL_OPTS+="Z"
  133. BOOTSTRAP_PKGS="${BOOTSTRAP_PACKAGES// /.rb,}.rb"
  134. cd "${CREW_PACKAGES_PATH}" && curl "${CURL_OPTS}" "${URL}/packages/{${BOOTSTRAP_PKGS}}"
  135. echo -e "${RESET}"
  136. # Prepare url and sha256.
  137. urls=()
  138. sha256s=()
  139. case "${ARCH}" in
  140. "armv7l"|"aarch64")
  141. if ! type "xz" > /dev/null; then
  142. urls+=('https://github.com/snailium/chrome-cross/releases/download/v1.8.1/xz-5.2.3-chromeos-armv7l.tar.gz')
  143. sha256s+=('4dc9f086ee7613ab0145ec0ed5ac804c80c620c92f515cb62bae8d3c508cbfe7')
  144. fi
  145. ;;
  146. esac
  147. # Create the device.json file if it doesn't exist.
  148. cd "${CREW_CONFIG_PATH}"
  149. if [ ! -f device.json ]; then
  150. echo_info "\nCreating new device.json."
  151. jq --arg key0 'architecture' --arg value0 "${ARCH}" \
  152. --arg key1 'installed_packages' \
  153. '. | .[$key0]=$value0 | .[$key1]=[]' <<<'{}' > device.json
  154. fi
  155. for package in ${BOOTSTRAP_PACKAGES}; do
  156. pkgfile="${CREW_PACKAGES_PATH}/${package}.rb"
  157. [[ "$(sed -n '/binary_sha256/,/}/p' "${pkgfile}")" =~ .*${ARCH}:[[:blank:]]*[\'\"]([^\'\"]*) ]]
  158. sha256s+=("${BASH_REMATCH[1]}")
  159. [[ "$(sed -n '/binary_url/,/}/p' "${pkgfile}")" =~ .*${ARCH}:[[:blank:]]*[\'\"]([^\'\"]*) ]]
  160. urls+=("${BASH_REMATCH[1]}")
  161. done
  162. # These functions are for handling packages.
  163. function download_check () {
  164. cd "$CREW_BREW_DIR"
  165. # Use cached file if available and caching enabled.
  166. if [ -n "$CREW_CACHE_ENABLED" ] && [[ -f "$CREW_CACHE_DIR/${3}" ]] ; then
  167. echo_intra "Verifying cached ${1}..."
  168. echo_success "$(echo "${4}" "$CREW_CACHE_DIR/${3}" | sha256sum -c -)"
  169. case "${?}" in
  170. 0)
  171. ln -sf "$CREW_CACHE_DIR/${3}" "$CREW_BREW_DIR/${3}" || true
  172. return
  173. ;;
  174. *)
  175. echo_error "Verification of cached ${1} failed, downloading."
  176. esac
  177. fi
  178. #download
  179. echo_intra "Downloading ${1}..."
  180. curl '-#' -L "${2}" -o "${3}"
  181. #verify
  182. echo_intra "Verifying ${1}..."
  183. echo_success "$(echo "${4}" "${3}" | sha256sum -c -)"
  184. case "${?}" in
  185. 0)
  186. if [ -n "$CREW_CACHE_ENABLED" ] ; then
  187. cp "${3}" "$CREW_CACHE_DIR/${3}" || true
  188. fi
  189. return
  190. ;;
  191. *)
  192. echo_error "Verification failed, something may be wrong with the download."
  193. exit 1;;
  194. esac
  195. }
  196. function extract_install () {
  197. # Start with a clean slate.
  198. rm -rf "${CREW_DEST_DIR}"
  199. mkdir "${CREW_DEST_DIR}"
  200. cd "${CREW_DEST_DIR}"
  201. #Extract and install.
  202. echo_intra "Extracting ${1} ..."
  203. case "${2}" in
  204. *.zst)
  205. if [[ -e /usr/bin/zstd ]]; then
  206. tar -I /usr/bin/zstd -xpf ../"${2}"
  207. elif ("${CREW_PREFIX}"/bin/zstd --version &> /dev/null); then
  208. tar -I "${CREW_PREFIX}"/bin/zstd -xpf ../"${2}"
  209. else
  210. echo "Zstd is broken or nonfunctional, and some packages can not be extracted properly."
  211. exit 1
  212. fi
  213. ;;
  214. *.tpxz)
  215. if "${CREW_PREFIX}"/bin/pixz -h &> /dev/null; then
  216. tar -I "${CREW_PREFIX}"/bin/pixz -xpf ../"${2}"
  217. else
  218. echo "Pixz is broken or nonfunctional, and some packages can not be extracted properly."
  219. exit 1
  220. fi
  221. ;;
  222. *)
  223. tar xpf ../"${2}"
  224. ;;
  225. esac
  226. echo_intra "Installing ${1} ..."
  227. tar cpf - ./*/* | (cd /; tar xp --keep-directory-symlink -m -f -)
  228. mv ./dlist "${CREW_CONFIG_PATH}/meta/${1}.directorylist"
  229. mv ./filelist "${CREW_CONFIG_PATH}/meta/${1}.filelist"
  230. }
  231. function update_device_json () {
  232. cd "${CREW_CONFIG_PATH}"
  233. if [[ $(jq --arg key "$1" -e '.installed_packages[] | select(.name == $key )' device.json) ]]; then
  234. echo_intra "Updating version number of ${1} in device.json..."
  235. ver_num=$(jq --arg key0 "$1" --arg value0 "$2" '(.installed_packages[] | select(.name == $key0) | .version) |= $value0' device.json)
  236. cat <<< "${ver_num}" > device.json
  237. else
  238. echo_intra "Adding new information on ${1} to device.json..."
  239. new_info=$(jq --arg key0 "$1" --arg value0 "$2" '.installed_packages |= . + [{"name": $key0, "version": $value0}]' device.json)
  240. cat <<< "${new_info}" > device.json
  241. fi
  242. }
  243. echo_info "Downloading Bootstrap packages...\n"
  244. # Extract, install and register packages.
  245. for i in $(seq 0 $((${#urls[@]} - 1))); do
  246. url=${urls["${i}"]}
  247. sha256=${sha256s["${i}"]}
  248. tarfile=$(basename "${url}")
  249. name="${tarfile%%-*}" # extract string before first '-'
  250. rest="${tarfile#*-}" # extract string after first '-'
  251. version="${rest%%-chromeos*}"
  252. # extract string between first '-' and "-chromeos"
  253. download_check "${name}" "${url}" "${tarfile}" "${sha256}"
  254. extract_install "${name}" "${tarfile}"
  255. update_device_json "${name}" "${version}"
  256. done
  257. echo_info "\nCreating symlink to 'crew' in ${CREW_PREFIX}/bin/"
  258. echo -e "${GRAY}"
  259. ln -sfv "../lib/crew/bin/crew" "${CREW_PREFIX}/bin/"
  260. echo -e "${RESET}"
  261. echo_info "Setup and synchronize local package repo..."
  262. echo -e "${GRAY}"
  263. # Remove old git config directories if they exist.
  264. find "${CREW_LIB_PATH}" -mindepth 1 -delete
  265. curl -L --progress-bar https://github.com/"${OWNER}"/"${REPO}"/tarball/"${BRANCH}" | tar -xz --strip-components=1 -C "${CREW_LIB_PATH}"
  266. # Set LD_LIBRARY_PATH so crew doesn't break on i686 and
  267. # the mandb install doesn't fail.
  268. export LD_LIBRARY_PATH="${CREW_PREFIX}/lib${LIB_SUFFIX}"
  269. echo_info "Fixing crew alias..."
  270. if ! cat ~/.bashrc | grep CREW_PREFIX; then
  271. echo 'export CREW_PREFIX=/mnt/stateful_partition/murkmod/chromebrew' >> ~/.bashrc
  272. echo 'export PATH="/mnt/stateful_partition/murkmod/chromebrew/bin:/mnt/stateful_partition/murkmod/chromebrew/sbin:$PATH"' >> ~/.bashrc
  273. echo 'export LD_LIBRARY_PATH=/mnt/stateful_partition/murkmod/chromebrew/lib' >> ~/.bashrc
  274. echo 'alias crew="/usr/local/bin/ruby /mnt/stateful_partition/murkmod/chromebrew/lib/crew/bin/crew"' >> ~/.bashrc
  275. source ~/.bashrc
  276. fi
  277. # Since we just downloaded the package repo, just update package
  278. # compatibility information.
  279. /usr/local/bin/ruby /mnt/stateful_partition/murkmod/chromebrew/lib/crew/bin/crew update compatible
  280. echo_info "Installing core Chromebrew packages...\n"
  281. yes | /usr/local/bin/ruby /mnt/stateful_partition/murkmod/chromebrew/lib/crew/bin/crew install core
  282. echo_info "\nRunning Bootstrap package postinstall scripts...\n"
  283. /usr/local/bin/ruby /mnt/stateful_partition/murkmod/chromebrew/lib/crew/bin/crew postinstall "${BOOTSTRAP_PACKAGES}"
  284. if ! "${CREW_PREFIX}"/bin/git version &> /dev/null; then
  285. echo_error "\nGit is broken on your system, and crew update will not work properly."
  286. echo_error "Please report this here:"
  287. echo_error "https://github.com/chromebrew/chromebrew/issues\n\n"
  288. else
  289. echo_info "Synchronizng local package repo..."
  290. # First clear out temporary package repo so we can replace it with the
  291. # repo downloaded via git.
  292. find "${CREW_LIB_PATH}" -mindepth 1 -delete
  293. # Do a minimal clone, which also sets origin to the master/main branch
  294. # by default. For more on why this setup might be useful see:
  295. # https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/
  296. # If using alternate branch don't use depth=1 .
  297. [[ "$BRANCH" == "master" ]] && GIT_DEPTH="--depth=1" || GIT_DEPTH=
  298. git clone "${GIT_DEPTH}" --filter=blob:none --no-checkout "https://github.com/${OWNER}/${REPO}.git" "${CREW_LIB_PATH}"
  299. cd "${CREW_LIB_PATH}"
  300. # Checkout, overwriting local files.
  301. [[ "$BRANCH" != "master" ]] && git fetch --all
  302. git checkout "${BRANCH}"
  303. # Set sparse-checkout folders.
  304. git sparse-checkout set packages lib bin crew tools
  305. git reset --hard origin/"${BRANCH}"
  306. fi
  307. echo -e "${RESET}"
  308. echo " . .
  309. ..,:;;;::'..
  310. .':lllllllool,.
  311. ...cl;..... ,::;'.
  312. .'oc...;::::..0KKo.
  313. .'od: .:::::, lolc.
  314. .'lNMMMO ;ooc.,XMMWx;:;.
  315. .dMMMMMMXkMMMMxoMMMMMMMMO.
  316. .:O0NMMMMMMMMMM0MMMMMN0Oc.
  317. .:xdloddddddoXMMMk:x:....
  318. .xMNOKX0OOOOxcodlcXMN0O0XKc.
  319. .OMXOKXOOOOOk;ol:OXMK...;N0.
  320. 'XMKOXXOOOOOk:docOKMW, .kW;
  321. .cMMKOXXOOOOOOOOOOO0MM; .lMc.
  322. .cMM00XKOOOOkkkkkkOOWMl. .cMo.
  323. .lMWO0XKOOOkkkkkkkkONMo. ;Wk.
  324. .oMNO0X0OOkkkkkkkkkOXMd..,oW0'
  325. .xMNO0X0OOkkkkkkkkkkXMWKXKOx;.
  326. .0MXOOOOOOkkkkkkkkkOKM0..
  327. 'NMWNXXKK000000KKXNNMMX.
  328. .;okk0XNWWMMMMWWNKOkdc'.
  329. .....'cc:cc:''..."
  330. echo " ___ _ _
  331. / (_)|\ |\\
  332. | ||__ ,_ __ _ _ _ __ |/_ ,_ __ _ _ _
  333. | |/ | / | / \/ |/ |/ | |_/ | \/ | |_/ /| | |\_
  334. \___/| |_/ |_/\__/ | | |_/|__/\__/ |_/|__/ \_/ \_/
  335. "
  336. if [[ "${CREW_PREFIX}" != "/usr/local" ]]; then
  337. echo_info "\n$
  338. Since you have installed Chromebrew in a directory other than '/usr/local',
  339. you need to run these commands to complete your installation:
  340. "
  341. echo_intra "
  342. echo 'export CREW_PREFIX=${CREW_PREFIX}' >> ~/.bashrc
  343. echo 'export PATH=\"\${CREW_PREFIX}/bin:\${CREW_PREFIX}/sbin:\${PATH}\"' >> ~/.bashrc
  344. echo 'export LD_LIBRARY_PATH=${CREW_PREFIX}/lib${LIB_SUFFIX}' >> ~/.bashrc
  345. source ~/.bashrc"
  346. fi
  347. echo_intra "
  348. Edit ${CREW_PREFIX}/etc/env.d/03-pager to change the default PAGER.
  349. more is used by default
  350. You may wish to edit the ${CREW_PREFIX}/etc/env.d/02-editor file for an editor default.
  351. Chromebrew provides nano, vim and emacs as default TUI editor options."
  352. echo_success "Chromebrew installed successfully and package lists updated."