forked from chromebrew/chromebrew
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·518 lines (448 loc) · 19.3 KB
/
install.sh
File metadata and controls
executable file
·518 lines (448 loc) · 19.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
#!/bin/bash
# Exit on fail.
set -eE
RESET='\e[0m'
# Simplify colors and print errors to stderr (2).
echo_error() { echo -e "\e[1;91m${*}${RESET}" >&2; } # Use Light Red for errors.
echo_info() { echo -e "\e[1;33m${*}${RESET}" >&1; } # Use Yellow for informational messages.
echo_success() { echo -e "\e[1;32m${*}${RESET}" >&1; } # Use Green for success messages.
echo_intra() { echo -e "\e[1;34m${*}${RESET}" >&1; } # Use Blue for intrafunction messages.
echo_out() { echo -e "\e[0;37m${*}${RESET}" >&1; } # Use Gray for program output.
# Add proper support for parsing /etc/lsb-release
# Reference: https://www.chromium.org/chromium-os/developer-library/reference/infrastructure/lsb-release/
lsbval() {
local key="$1"
local lsbfile="${2:-/etc/lsb-release}"
if ! echo "${key}" | grep -Eq '^[a-zA-Z0-9_]+$'; then
return 1
fi
sed -E -n -e \
"/^[[:space:]]*${key}[[:space:]]*=/{
s:^[^=]+=[[:space:]]*::
s:[[:space:]]+$::
p
}" "${lsbfile}"
}
# Print a message before exit on error
set_trap() { trap "echo_error 'An error occured during the installation :/'" ERR; }
set_trap
# Check if the script is being run as root.
if [ "${EUID}" == "0" ]; then
echo_error "Chromebrew should not be installed or run as root."
echo_info "Please login as 'chronos' and restart the install."
exit 1
fi
# Reject crostini.
if [[ -d /opt/google/cros-containers && "${CREW_FORCE_INSTALL}" != '1' ]]; then
echo_error "Crostini containers are not supported by Chromebrew :/"
echo_info "Run 'CREW_FORCE_INSTALL=1 bash <(curl -Ls git.io/vddgY) && . ~/.bashrc' to perform install anyway"
exit 1
fi
# Reject non-stable Chrome OS channels.
if [ -f /etc/lsb-release ]; then
if [[ ! "$(lsbval CHROMEOS_RELEASE_TRACK)" =~ stable-channel && "${CREW_FORCE_INSTALL}" != '1' ]]; then
echo_error "The beta, dev, and canary channel are unsupported by Chromebrew."
echo_info "Run 'CREW_FORCE_INSTALL=1 bash <(curl -Ls git.io/vddgY) && . ~/.bashrc' to perform install anyway."
exit 1
fi
CHROMEOS_RELEASE_CHROME_MILESTONE="$(lsbval CHROMEOS_RELEASE_CHROME_MILESTONE)"
else
echo_info "Unable to detect system information, installation will continue."
fi
# Check if the user owns the CREW_PREFIX directory, as sudo is unnecessary if this is the case.
# Check if the user is on ChromeOS v117+ and not in the VT-2 console, as sudo will not work.
: "${CREW_PREFIX:=/usr/local}"
if [[ "$(stat -c '%u' "${CREW_PREFIX}")" == "$(id -u)" ]] && sudo 2>&1 | grep -q 'no new privileges'; then
echo_error "Please run the installer in the VT-2 shell."
echo_info "To start the VT-2 session, type Ctrl + Alt + ->"
exit 1
fi
# Make sure installation directory is clean.
if [ -d "${CREW_PREFIX}" ]; then
if [ "$(ls -A "${CREW_PREFIX}")" ]; then
echo_error "${CREW_PREFIX} is not empty, would you like it to be cleared?"
echo_info "This will delete ALL files in ${CREW_PREFIX}!"
echo_info "Continue?"
select continue in "Yes" "No"; do
if [[ "${continue}" == "Yes" ]]; then
sudo find "${CREW_PREFIX}" -mindepth 1 -delete
break 2
else
exit 1
fi
done
fi
else
sudo mkdir -p "${CREW_PREFIX}"
fi
# Do not redundantly use sudo if the user already owns the directory.
if [ "$(stat -c '%u' "${CREW_PREFIX}")" != "$(id -u)" ]; then
# This will allow things to work without sudo.
sudo chown "$(id -u)":"$(id -g)" "${CREW_PREFIX}"
fi
# Default chromebrew repo values.
: "${OWNER:=chromebrew}"
: "${REPO:=chromebrew}"
: "${BRANCH:=master}"
# Chromebrew directories.
CREW_LIB_PATH="${CREW_PREFIX}/lib/crew"
CREW_CONFIG_PATH="${CREW_PREFIX}/etc/crew"
CREW_META_PATH="${CREW_CONFIG_PATH}/meta"
CREW_BREW_DIR="${CREW_PREFIX}/tmp/crew"
CREW_DEST_DIR="${CREW_BREW_DIR}/dest"
: "${CREW_CACHE_DIR:=$CREW_PREFIX/tmp/packages}"
if [ -n "$CREW_CACHE_ENABLED" ]; then
echo_intra "Verifying setup of ${CREW_CACHE_DIR} since CREW_CACHE_ENABLED is set..."
mkdir -p "${CREW_CACHE_DIR}"
sudo chown -R "$(id -u)":"$(id -g)" "${CREW_CACHE_DIR}" || true
fi
# Architecture
# For container usage, where we want to specify i686 arch
# on a x86_64 host by setting ARCH=i686.
: "${ARCH:=$(uname -m)}"
# For container usage, when we are emulating armv7l via linux32, where uname -m will report armv8l.
# Additionally, if the architecture is aarch64, set it to armv7l, as we treat as if it was armv7l.
# When we have proper support for aarch64, remove this.
if [[ "${ARCH}" = "armv8l" ]] || [[ "${ARCH}" = "aarch64" ]]; then
ARCH='armv7l'
fi
if [[ "$ARCH" == "x86_64" ]]; then
LIB_SUFFIX='64'
fi
# Warn users of the AMD segfault issue and allow them to work around it.
# The easiest way to distinguish StoneyRidge platorms is to check for the FMA4
# instruction, as it was first introduced in Bulldozer and later dropped in Zen.
if grep -s "fma4" /proc/cpuinfo ; then
echo_info "Notice: You are running an AMD StoneyRidge device; due to some bugs some packages may fail with a segmentation fault and need to be rebuilt."
echo_info "If this happens, please report them to: https://github.com/chromebrew/chromebrew/issues"
echo_info "If the install fails, try running 'CREW_AMD_INSTALL=1 bash <(curl -Ls git.io/vddgY) && . ~/.bashrc'"
if [ "${CREW_AMD_INSTALL}" == "1" ]; then
# Otherwise one may get segfaults during install on stoneyridge devices.
# See https://github.com/chromebrew/chromebrew/issues/8823
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
fi
fi
echo_success "Welcome to Chromebrew!"
# Prompt user to enter the sudo password if it is set.
# If the PASSWD_FILE specified by chromeos-setdevpasswd exist, that means a sudo password is set.
if [[ "$(< /usr/sbin/chromeos-setdevpasswd)" =~ PASSWD_FILE=\'([^\']+) ]] && [ -f "${BASH_REMATCH[1]}" ]; then
echo_intra "Please enter the developer mode password."
# Reset sudo timeout.
sudo -k
sudo /bin/true
fi
# Force curl to use system libraries.
function curl_wrapper () {
# Retry if download failed.
# The --retry/--retry-all-errors parameter in curl will not work with
# the 'curl: (7) Couldn't connect to server' error, a for loop is used
# here.
for (( i = 0; i < 4; i++ )); do
if [[ "$ARCH" == "i686" ]]; then
# i686 curl throws a "SSL certificate problem: self signed certificate in certificate chain" error.
env -u LD_LIBRARY_PATH curl -kC - "${@}" && return 0
else
# Force TLS as we know GitLab supports it.
env -u LD_LIBRARY_PATH curl --ssl-reqd --tlsv1.2 -C - "${@}" && return 0
fi
echo_info "Retrying, $((3-i)) retries left."
done
# The download failed if we're still here.
echo_error "Download failed :/ Please check your network settings."
return 1
}
# This will create the directories.
crew_folders="bin cache doc docbook include lib/crew/packages lib$LIB_SUFFIX libexec man sbin share var etc/crew/meta etc/env.d tmp/crew/dest"
# shellcheck disable=SC2086
# Quoting crew_folders leads to breakage.
(cd "${CREW_PREFIX}" && mkdir -p ${crew_folders})
# Remove old git config directories if they exist.
find "${CREW_LIB_PATH}" -mindepth 1 -delete
echo_out 'Set up the local package repo...'
# Download the chromebrew repository.
curl_wrapper -L --progress-bar https://github.com/"${OWNER}"/"${REPO}"/tarball/"${BRANCH}" | tar -xz --strip-components=1 -C "${CREW_LIB_PATH}"
BOOTSTRAP_PACKAGES='zstd_static glibc_standalone libxcrypt upx patchelf lz4 zlib xzutils zstd zlib_ng crew_mvdir ruby git ca_certificates libyaml openssl gmp'
# Older i686 systems.
if [[ "${ARCH}" == "i686" ]]; then
LIBC_VERSION='2.23'
BOOTSTRAP_PACKAGES+=' gcc_lib'
fi
if [[ -n "${CHROMEOS_RELEASE_CHROME_MILESTONE}" ]]; then
# shellcheck disable=SC2231
if (( "${CHROMEOS_RELEASE_CHROME_MILESTONE}" > "112" )); then
# Recent Arm systems have a cut down system.
if [[ "${ARCH}" == "armv7l" ]];then
LIBC_VERSION='2.27'
BOOTSTRAP_PACKAGES+=' bzip2 ncurses readline pcre2 gcc_lib'
fi
fi
fi
# Create the device.json file.
cd "${CREW_CONFIG_PATH}"
echo_info "\nCreating device.json."
jq --arg key0 'architecture' --arg value0 "${ARCH}" \
--arg key1 'installed_packages' \
'. | .[$key0]=$value0 | .[$key1]=[]' <<<'{}' > device.json
# Functions to maintain packages.
# These functions are for handling packages.
function download_check () {
cd "$CREW_BREW_DIR"
# Use cached file if available and caching is enabled.
if [ -n "$CREW_CACHE_ENABLED" ]; then
echo_intra "Looking for ${3} in ${CREW_CACHE_DIR}"
if [[ -f "$CREW_CACHE_DIR/${3}" ]] ; then
echo_info "$CREW_CACHE_DIR/${3} found."
echo_intra "Verifying cached ${1}..."
echo_success "$(echo "${4}" "$CREW_CACHE_DIR/${3}" | sha256sum -c -)"
case "${?}" in
0)
ln -sf "$CREW_CACHE_DIR/${3}" "$CREW_BREW_DIR/${3}" || true
return
;;
*)
echo_error "Verification of cached ${1} failed, downloading."
esac
else
echo_intra "$CREW_CACHE_DIR/${3} not found"
fi
fi
# Download
echo_intra "Downloading ${1}..."
curl_wrapper '-#' -L "${2}" -o "${3}"
# Verify
echo_intra "Verifying ${1}..."
if echo "${4}" "${3}" | sha256sum -c - ; then
if [ -n "$CREW_CACHE_ENABLED" ] ; then
cp "${3}" "$CREW_CACHE_DIR/${3}" || true
fi
echo_success "Verification of ${1} succeeded."
return 0
else
if [[ ${5} -lt 2 ]]; then
echo_error "Verification of ${1} failed, something may be wrong with the download."
exit 1
else
echo_info "Verification of ${1} failed. Will try another sha256 hash if available."
return 1
fi
fi
}
function extract_install () {
# Start with a clean slate.
rm -rf "${CREW_DEST_DIR}"
mkdir "${CREW_DEST_DIR}"
cd "${CREW_DEST_DIR}"
XZ_STATUS=
if ! xz --help &>/dev/null; then
XZ_STATUS="broken"
elif [[ -f /usr/bin/xz ]] && env -u LD_LIBRARY_PATH /usr/bin/xz --help &>/dev/null; then
XZ_STATUS="system"
fi
ZSTD_STATUS=
if ! zstd --help &>/dev/null; then
ZSTD_STATUS="broken"
elif [[ -f /usr/bin/zstd ]] && env -u LD_LIBRARY_PATH /usr/bin/zstd --help &>/dev/null; then
ZSTD_STATUS="system"
fi
[[ -z ${XZ_STATUS} ]] || echo_info "XZ: ${XZ_STATUS}"
[[ -z ${ZSTD_STATUS} ]] || echo_info "ZSTD: ${ZSTD_STATUS}"
# Extract and install.
echo_intra "Extracting ${1} ..."
if [[ "${2##*.}" == "xz" ]]; then
if [[ -z $XZ_STATUS ]]; then
tar xpf ../"${2}"
elif [[ $XZ_STATUS == 'system' ]]; then
env -u LD_LIBRARY_PATH tar -I /usr/bin/xz -xpf ../"${2}"
elif [[ $XZ_STATUS == 'broken' ]] && [[ -z $ZSTD_STATUS ]] && zstd --help 2>/dev/null| grep -q lzma; then
tar -I zstd -xpf ../"${2}"
elif [[ $XZ_STATUS == 'broken' ]] && [[ $ZSTD_STATUS == 'broken' ]]; then
echo_error "xz and zstd are broken. Install will fail." && exit 1
elif [[ $XZ_STATUS == 'broken' ]] && [[ $ZSTD_STATUS == 'system' ]]; then
env -u LD_LIBRARY_PATH tar -I /usr/bin/zstd -xpf ../"${2}"
fi
fi
if [[ "${2##*.}" == "zst" ]]; then
if [[ -z $ZSTD_STATUS ]] && tar --usage | grep -q zstd ; then
tar xpf ../"${2}"
elif [[ $ZSTD_STATUS == 'system' ]]; then
env -u LD_LIBRARY_PATH tar -I /usr/bin/zstd -xpf ../"${2}"
elif [[ $ZSTD_STATUS == 'broken' ]]; then
echo_error "zstd is broken. Install will fail."
exit 1
else
tar -I zstd -xpf ../"${2}"
fi
fi
echo_intra "Installing ${1}..."
tar cpf - ./*/* | (cd /; tar xp --keep-directory-symlink -m -f -)
if [[ "${1}" == 'glibc_standalone' ]]; then
# set LD_AUDIT to ignore libC.so.6 requests
# export LD_AUDIT="${CREW_PREFIX}/opt/glibc-libs/crew-audit.so"
# update ld.so cache
ldconfig
else
# decompress and switch to glibc_standalone for existing binaries
if command -v upx &> /dev/null; then
echo_intra "Running upx on ${1}..."
grep "/usr/local/\(bin\|lib\|lib${LIB_SUFFIX}\)" < filelist | xargs -P "$(nproc)" -n1 upx -qq -d 2> /dev/null || true
fi
if command -v patchelf &> /dev/null; then
echo_intra "Running patchelf on ${1}..."
grep '/usr/local/bin' < filelist | xargs -P "$(nproc)" -n1 patchelf --set-interpreter "${CREW_PREFIX}/bin/ld.so" 2> /dev/null || true
fi
fi
mv ./dlist "${CREW_META_PATH}/${1}.directorylist"
mv ./filelist "${CREW_META_PATH}/${1}.filelist"
}
function update_device_json () {
cd "${CREW_CONFIG_PATH}"
echo_intra "Adding new information on ${1} ${2} to device.json..."
new_info=$(jq --arg name "$1" --arg version "$2" --arg sha256 "$3" '.installed_packages |= . + [{"name": $name, "version": $version, "sha256": $sha256}]' device.json)
cat <<< "${new_info}" > device.json
}
function install_ruby_gem () {
for gem in "$@"; do
ruby_gem="${gem}"
echo_intra "Installing ${ruby_gem^} gem..."
gem install -N "${ruby_gem}" --conservative
gem_version="$(ruby -e "gem('${ruby_gem}')" -e "puts Gem.loaded_specs['${ruby_gem}'].version.to_s")"
json_gem_version="${gem_version}-${CREW_RUBY_VER}"
crew_gem_package="ruby_${ruby_gem//-/_}"
update_device_json "${crew_gem_package}" "${json_gem_version}" ""
gem_filelist_path="${CREW_META_PATH}/${crew_gem_package}.filelist"
echo_intra "Saving ${ruby_gem^} filelist..."
gem contents "${ruby_gem}" > "${gem_filelist_path}"
echo_success "${ruby_gem^} gem installed."
BOOTSTRAP_PACKAGES+=" ${crew_gem_package}"
done
}
echo_info "Downloading Bootstrap packages:\n${BOOTSTRAP_PACKAGES}"
# Set LD_LIBRARY_PATH so crew doesn't break on i686, xz doesn't fail on
# x86_64, and the mandb postinstall doesn't fail in newer arm
# containers.
echo "LD_LIBRARY_PATH=$CREW_PREFIX/lib${LIB_SUFFIX}:/lib${LIB_SUFFIX}" >> "$CREW_PREFIX"/etc/env.d/00-library
export LD_LIBRARY_PATH="${CREW_PREFIX}/lib${LIB_SUFFIX}:/lib${LIB_SUFFIX}"
# Extract, install and register packages.
for package in $BOOTSTRAP_PACKAGES; do
cd "${CREW_LIB_PATH}/packages"
version=$(grep "\ \ version" "${package}.rb" | head -n 1 | sed "s/#{LIBC_VERSION}/$LIBC_VERSION/g" | sed "s/#{@gcc_libc_version}/$LIBC_VERSION/g" | awk '{print substr($2,2,length($2)-2)}')
binary_compression=$(sed -n "s/.*binary_compression '\([^']*\)'.*/\1/p" "${package}.rb")
if [[ -z "$binary_compression" ]]; then
binary_compression='tar.zst'
fi
url="https://gitlab.com/api/v4/projects/26210301/packages/generic/${package}/${version}_${ARCH}/${package}-${version}-chromeos-${ARCH}.${binary_compression}"
tarfile=$(basename "${url}")
sha256=$(sed -n "s/.*${ARCH}: '\([^']*\)'.*/\1/p" "${package}.rb")
shacount=$(echo "$sha256" | wc -w)
for sha in $sha256
do
if download_check "${package}" "${url}" "${tarfile}" "${sha}" "${shacount}"; then
extract_install "${package}" "${tarfile}"
update_device_json "${package}" "${version}" "${sha}"
fi
done
done
# Work around https://github.com/chromebrew/chromebrew/issues/3305.
# shellcheck disable=SC2024
sudo ldconfig &> /tmp/crew_ldconfig || true
echo_out "\nCreating symlink to 'crew' in ${CREW_PREFIX}/bin/"
ln -sfv "../lib/crew/bin/crew" "${CREW_PREFIX}/bin/"
echo "export CREW_PREFIX=${CREW_PREFIX}" >> "${CREW_PREFIX}/etc/env.d/profile"
echo_info 'Updating RubyGems...'
gem sources -u
gem update --no-update-sources -N --system
# Mark packages as installed for pre-installed gems.
mapfile -t installed_gems < <(gem list | awk -F ' \(' '{print $1, $2}' | sed -e 's/default://' -e 's/)//' -e 's/,//' | awk '{print $1, $2}')
CREW_RUBY_VER="ruby$(ruby -e 'puts RUBY_VERSION.slice(/(?:.*(?=\.))/)')"
for i in "${!installed_gems[@]}"
do
j="${installed_gems[$i]}"
gem_package="${j% *}"
crew_gem_package="ruby_${gem_package//-/_}"
gem_version="${j#* }"
gem contents "${gem_package}" > "${CREW_META_PATH}/${crew_gem_package}.filelist"
update_device_json "ruby_${gem_package//-/_}" "${gem_version}-${CREW_RUBY_VER}" ""
done
echo_info "Installing essential ruby gems...\n"
BOOTSTRAP_GEMS='base64 bigdecimal connection_pool concurrent-ruby drb i18n logger minitest securerandom tzinfo activesupport highline ptools'
# shellcheck disable=SC2086
install_ruby_gem ${BOOTSTRAP_GEMS}
# This is needed for SSL env variables to be populated so ruby doesn't
# complain about missing certs, resulting in failed https connections.
echo_info "Installing crew_profile_base...\n"
yes | crew install crew_profile_base
# shellcheck disable=SC1090
trap - ERR && source ~/.bashrc && set_trap
echo_info "Installing core Chromebrew packages...\n"
yes | crew install core
echo_info "\nRunning Bootstrap package postinstall scripts...\n"
# Due to a bug in crew where it accepts spaces in package files names rather than
# splitting strings at spaces, we cannot quote ${BOOTSTRAP_PACKAGES}.
# shellcheck disable=SC2086
for i in ${BOOTSTRAP_PACKAGES}
do
echo_info "Doing postinstall for $i"
crew postinstall $i || echo_error "Postinstall for $i failed."
done
if ! "${CREW_PREFIX}"/bin/git version &> /dev/null; then
echo_error "\nGit is broken on your system, and crew update will not work properly."
echo_error "Please report this here:"
echo_error "https://github.com/chromebrew/chromebrew/issues\n\n"
else
echo_info "Synchronizing local package repo..."
cd "${CREW_LIB_PATH}"
# Make the git default branch error messages go away.
git config --global init.defaultBranch main
# Setup the folder with git information.
git init --ref-format=reftable
git remote add origin "https://github.com/${OWNER}/${REPO}"
# Help handle situations where GitHub is down.
git config --local http.lowSpeedLimit 1000
git config --local http.lowSpeedTime 5
# Checkout, overwriting local files.
git fetch --all
git checkout -f "${BRANCH}"
# Set sparse-checkout folders.
git sparse-checkout set packages "manifest/${ARCH}" lib commands bin crew tests tools
git reset --hard origin/"${BRANCH}"
# Set mtimes of files to when the file was committed.
git-restore-mtime -sq 2>/dev/null
OWNER=${OWNER} REPO=${REPO} crew update && yes | crew upgrade
echo_info "Cleaning up older ruby gem versions...\n"
gem cleanup
fi
echo -e "${RESET}"
echo " . .
..,:;;;::'..
.':lllllllool,.
...cl;..... ,::;'.
.'oc...;::::..0KKo.
.'od: .:::::, lolc.
.'lNMMMO ;ooc.,XMMWx;:;.
.dMMMMMMXkMMMMxoMMMMMMMMO.
.:O0NMMMMMMMMMM0MMMMMN0Oc.
.:xdloddddddoXMMMk:x:....
.xMNOKX0OOOOxcodlcXMN0O0XKc.
.OMXOKXOOOOOk;ol:OXMK...;N0.
'XMKOXXOOOOOk:docOKMW, .kW;
.cMMKOXXOOOOOOOOOOO0MM; .lMc.
.cMM00XKOOOOkkkkkkOOWMl. .cMo.
.lMWO0XKOOOkkkkkkkkONMo. ;Wk.
.oMNO0X0OOkkkkkkkkkOXMd..,oW0'
.xMNO0X0OOkkkkkkkkkkXMWKXKOx;.
.0MXOOOOOOkkkkkkkkkOKM0..
'NMWNXXKK000000KKXNNMMX.
.;okk0XNWWMMMMWWNKOkdc'.
.....'cc:cc:''..."
echo " ___ _ _
/ (_)|\ |\\
| ||__ ,_ __ _ _ _ __ |/_ ,_ __ _ _ _
| |/ | / | / \/ |/ |/ | |_/ | \/ | |_/ /| | |\_
\___/| |_/ |_/\__/ | | |_/|__/\__/ |_/|__/ \_/ \_/
"
echo_intra "
Edit ${CREW_PREFIX}/etc/env.d/03-pager to change the default PAGER.
most is used by default
You may wish to edit the ${CREW_PREFIX}/etc/env.d/02-editor file for an editor default.
Chromebrew provides nano, vim and emacs as default TUI editor options."
echo_success "Chromebrew installed successfully and package lists updated."