1# Copyright 2020 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14 15# Just in case PATH isn't already exported. 16export PATH 17 18# Note: Colors are unfortunately duplicated in several places; and removing the 19# duplication is not easy. Their locations are: 20# 21# - bootstrap.sh 22# - pw_cli/color.py 23# - pw_env_setup/py/pw_env_setup/colors.py 24# - pw_env_setup/util.fish 25# - pw_env_setup/util.sh 26# 27# So please keep them matching then modifying them. 28pw_none() { 29 echo -e "$*" 30} 31 32pw_red() { 33 echo -e "\033[0;31m$*\033[0m" 34} 35 36pw_bold_red() { 37 echo -e "\033[1;31m$*\033[0m" 38} 39 40pw_yellow() { 41 echo -e "\033[0;33m$*\033[0m" 42} 43 44pw_bold_yellow() { 45 echo -e "\033[1;33m$*\033[0m" 46} 47 48pw_green() { 49 echo -e "\033[0;32m$*\033[0m" 50} 51 52pw_bold_green() { 53 echo -e "\033[1;32m$*\033[0m" 54} 55 56pw_blue() { 57 echo -e "\033[1;34m$*\033[0m" 58} 59 60pw_cyan() { 61 echo -e "\033[1;36m$*\033[0m" 62} 63 64pw_magenta() { 65 echo -e "\033[0;35m$*\033[0m" 66} 67 68pw_bold_white() { 69 echo -e "\033[1;37m$*\033[0m" 70} 71 72pw_error() { 73 echo -e "\033[1;31m$*\033[0m" >& /dev/stderr 74} 75 76pw_error_info() { 77 echo -e "\033[0;31m$*\033[0m" >& /dev/stderr 78} 79 80pw_eval_sourced() { 81 if [ "$1" -eq 0 ]; then 82 # TODO(pwbug/354) Remove conditional after all downstream projects have 83 # changed to passing in second argument. 84 if [ -n "$2" ]; then 85 _PW_NAME=$(basename "$2" .sh) 86 else 87 _PW_NAME=$(basename "$_BOOTSTRAP_PATH" .sh) 88 fi 89 pw_error "Error: Attempting to $_PW_NAME in a subshell" 90 pw_error_info " Since $_PW_NAME.sh modifies your shell's environment" 91 pw_error_info " variables, it must be sourced rather than executed. In" 92 pw_error_info " particular, 'bash $_PW_NAME.sh' will not work since the " 93 pw_error_info " modified environment will get destroyed at the end of the" 94 pw_error_info " script. Instead, source the script's contents in your" 95 pw_error_info " shell:" 96 pw_error_info "" 97 pw_error_info " \$ source $_PW_NAME.sh" 98 exit 1 99 fi 100} 101 102pw_check_root() { 103 _PW_ROOT="$1" 104 if [[ "$_PW_ROOT" = *" "* ]]; then 105 pw_error "Error: The Pigweed path contains spaces\n" 106 pw_error_info " The path '$_PW_ROOT' contains spaces. " 107 pw_error_info " Pigweed's Python environment currently requires Pigweed to" 108 pw_error_info " be at a path without spaces. Please checkout Pigweed in a" 109 pw_error_info " directory without spaces and retry running bootstrap." 110 return -1 111 fi 112} 113 114pw_get_env_root() { 115 # PW_ENVIRONMENT_ROOT allows callers to specify where the environment should 116 # be installed. bootstrap.sh scripts should not use that variable to store the 117 # result of this function. This separation allows scripts to assume 118 # PW_ENVIRONMENT_ROOT came from the caller and not from a previous bootstrap 119 # possibly from another workspace. PW_ENVIRONMENT_ROOT will be cleared after 120 # environment setup completes. 121 if [ -n "$PW_ENVIRONMENT_ROOT" ]; then 122 echo "$PW_ENVIRONMENT_ROOT" 123 return 124 fi 125 126 # Determine project-level root directory. 127 if [ -n "$PW_PROJECT_ROOT" ]; then 128 _PW_ENV_PREFIX="$PW_PROJECT_ROOT" 129 else 130 _PW_ENV_PREFIX="$PW_ROOT" 131 fi 132 133 # If <root>/environment exists, use it. Otherwise, if <root>/.environment 134 # exists, use it. Finally, use <root>/environment. 135 _PW_DOTENV="$_PW_ENV_PREFIX/.environment" 136 _PW_ENV="$_PW_ENV_PREFIX/environment" 137 138 if [ -d "$_PW_DOTENV" ]; then 139 if [ -d "$_PW_ENV" ]; then 140 pw_error "Error: both possible environment directories exist." 141 pw_error_info " $_PW_DOTENV" 142 pw_error_info " $_PW_ENV" 143 pw_error_info " If only one of these folders exists it will be used for" 144 pw_error_info " the Pigweed environment. If neither exists" 145 pw_error_info " '<...>/environment' will be used. Since both exist," 146 pw_error_info " bootstrap doesn't know which to use. Please delete one" 147 pw_error_info " or both and rerun bootstrap." 148 exit 1 149 fi 150 fi 151 152 if [ -d "$_PW_ENV" ]; then 153 echo "$_PW_ENV" 154 elif [ -d "$_PW_DOTENV" ]; then 155 echo "$_PW_DOTENV" 156 else 157 echo "$_PW_ENV" 158 fi 159} 160 161# Note: This banner is duplicated in three places; which is a lesser evil than 162# the contortions that would be needed to share this snippet across shell, 163# batch, and Python. Locations: 164# 165# - pw_env_setup/util.fish 166# - pw_env_setup/util.sh 167# - pw_cli/branding.py 168# - pw_env_setup/py/pw_env_setup/windows_env_start.py 169# 170_PW_BANNER=$(cat <<EOF 171 ▒█████▄ █▓ ▄███▒ ▒█ ▒█ ░▓████▒ ░▓████▒ ▒▓████▄ 172 ▒█░ █░ ░█▒ ██▒ ▀█▒ ▒█░ █ ▒█ ▒█ ▀ ▒█ ▀ ▒█ ▀█▌ 173 ▒█▄▄▄█░ ░█▒ █▓░ ▄▄░ ▒█░ █ ▒█ ▒███ ▒███ ░█ █▌ 174 ▒█▀ ░█░ ▓█ █▓ ░█░ █ ▒█ ▒█ ▄ ▒█ ▄ ░█ ▄█▌ 175 ▒█ ░█░ ░▓███▀ ▒█▓▀▓█░ ░▓████▒ ░▓████▒ ▒▓████▀ 176EOF 177) 178 179_pw_banner() { 180 pw_magenta "$_PW_BANNER\n" 181} 182 183_PW_BANNER_FUNC="_pw_banner" 184 185_pw_hello() { 186 _PW_TEXT="$1" 187 # If $PW_BANNER_FUNC is defined, use that as the banner function 188 # instead of the default. 189 if [ -n "$PW_BANNER_FUNC" ]; then 190 _PW_BANNER_FUNC="$PW_BANNER_FUNC" 191 fi 192 # Display the banner unless PW_ENVSETUP_QUIET or 193 # PW_ENVSETUP_NO_BANNER is set. 194 if [ -z "$PW_ENVSETUP_QUIET" ] && [ -z "$PW_ENVSETUP_NO_BANNER" ]; then 195 pw_green "\n WELCOME TO...\n" 196 "$_PW_BANNER_FUNC" 197 pw_green "$_PW_TEXT" 198 fi 199} 200 201pw_deactivate() { 202 # Assume PW_ROOT and PW_PROJECT_ROOT have already been set and we need to 203 # preserve their values. 204 _NEW_PW_ROOT="$PW_ROOT" 205 _NEW_PW_PROJECT_ROOT="$PW_PROJECT_ROOT" 206 207 # Find deactivate script, run it, and then delete it. This way if the 208 # deactivate script is doing something wrong subsequent bootstraps still 209 # have a chance to pass. 210 _PW_DEACTIVATE_SH="$_PW_ACTUAL_ENVIRONMENT_ROOT/deactivate.sh" 211 if [ -f "$_PW_DEACTIVATE_SH" ]; then 212 . "$_PW_DEACTIVATE_SH" 213 rm -f "$_PW_DEACTIVATE_SH" &> /dev/null 214 fi 215 216 # If there's a _pw_deactivate function run it. Redirect output to /dev/null 217 # in case _pw_deactivate doesn't exist. Remove _pw_deactivate when complete. 218 if [ -n "$(command -v _pw_deactivate)" ]; then 219 _pw_deactivate > /dev/null 2> /dev/null 220 unset -f _pw_deactivate 221 fi 222 223 # Restore. 224 PW_ROOT="$_NEW_PW_ROOT" 225 export PW_ROOT 226 PW_PROJECT_ROOT="$_NEW_PW_PROJECT_ROOT" 227 export PW_PROJECT_ROOT 228} 229 230deactivate() { 231 pw_deactivate 232 unset -f pw_deactivate 233 unset -f deactivate 234 unset PW_ROOT 235 unset PW_PROJECT_ROOT 236 unset PW_BRANDING_BANNER 237 unset PW_BRANDING_BANNER_COLOR 238} 239 240# The next three functions use the following variables. 241# * PW_BANNER_FUNC: function to print banner 242# * PW_BOOTSTRAP_PYTHON: specific Python interpreter to use for bootstrap 243# * PW_ROOT: path to Pigweed root 244# * PW_ENVSETUP_QUIET: limit output if "true" 245# 246# All arguments passed in are passed on to env_setup.py in pw_bootstrap, 247# pw_activate takes no arguments, and pw_finalize takes the name of the script 248# "bootstrap" or "activate" and the path to the setup script written by 249# bootstrap.sh. 250pw_bootstrap() { 251 _pw_hello " BOOTSTRAP! Bootstrap may take a few minutes; please be patient.\n" 252 253 local _pw_alias_check=0 254 alias python > /dev/null 2> /dev/null || _pw_alias_check=$? 255 if [ "$_pw_alias_check" -eq 0 ]; then 256 pw_error "Error: 'python' is an alias" 257 pw_error_info "The shell has a 'python' alias set. This causes many obscure" 258 pw_error_info "Python-related issues both in and out of Pigweed. Please" 259 pw_error_info "remove the Python alias from your shell init file or at" 260 pw_error_info "least run the following command before bootstrapping" 261 pw_error_info "Pigweed." 262 pw_error_info 263 pw_error_info " unalias python" 264 pw_error_info 265 return 266 fi 267 268 # Allow forcing a specific version of Python for testing pursposes. 269 if [ -n "$PW_BOOTSTRAP_PYTHON" ]; then 270 _PW_PYTHON="$PW_BOOTSTRAP_PYTHON" 271 elif command -v python3 > /dev/null 2> /dev/null; then 272 _PW_PYTHON=python3 273 elif command -v python > /dev/null 2> /dev/null; then 274 _PW_PYTHON=python 275 else 276 pw_error "Error: No system Python present\n" 277 pw_error_info " Pigweed's bootstrap process requires a local system" 278 pw_error_info " Python. Please install Python on your system, add it to " 279 pw_error_info " your PATH and re-try running bootstrap." 280 return 281 fi 282 283 local _pw_python_major_version=$($_PW_PYTHON -c 'import sys; print(sys.version_info[0])') 284 if [ "$_pw_python_major_version" != "3" ]; then 285 pw_error "Error: System Python is not Python 3\n" 286 pw_error_info " The system Python is not Python 3. Please install Python 3" 287 pw_error_info " and rerun bootstrap. Note that you may need to open a new" 288 pw_error_info " terminal to see the newly installed Python." 289 return 290 fi 291 292 if [ -n "$_PW_ENV_SETUP" ]; then 293 "$_PW_ENV_SETUP" "$@" 294 _PW_ENV_SETUP_STATUS="$?" 295 else 296 "$_PW_PYTHON" "$PW_ROOT/pw_env_setup/py/pw_env_setup/env_setup.py" "$@" 297 _PW_ENV_SETUP_STATUS="$?" 298 fi 299 300 # Write the directory path at bootstrap time into the directory. This helps 301 # us double-check things are still in the same space when calling activate. 302 _PW_ENV_ROOT_TXT="$_PW_ACTUAL_ENVIRONMENT_ROOT/env_root.txt" 303 echo "$_PW_ACTUAL_ENVIRONMENT_ROOT" > "$_PW_ENV_ROOT_TXT" 2> /dev/null 304 305 # Create the environment README file. Use quotes to prevent alias expansion. 306 "cp" "$PW_ROOT/pw_env_setup/destination.md" "$_PW_ACTUAL_ENVIRONMENT_ROOT/README.md" &> /dev/null 307} 308 309pw_activate() { 310 _pw_hello " ACTIVATOR! This sets your shell environment variables.\n" 311 _PW_ENV_SETUP_STATUS=0 312} 313 314pw_finalize() { 315 _PW_NAME="$1" 316 _PW_SETUP_SH="$2" 317 318 # Check that the environment directory agrees that the path it's at matches 319 # where it thinks it should be. If not, bail. 320 _PW_ENV_ROOT_TXT="$_PW_ACTUAL_ENVIRONMENT_ROOT/env_root.txt" 321 if [ -f "$_PW_ENV_ROOT_TXT" ]; then 322 _PW_PREV_ENV_ROOT="$(cat $_PW_ENV_ROOT_TXT)" 323 if [ "$_PW_ACTUAL_ENVIRONMENT_ROOT" != "$_PW_PREV_ENV_ROOT" ]; then 324 pw_error "Error: Environment directory moved" 325 pw_error_info "This Pigweed environment was created at" 326 pw_error_info 327 pw_error_info " $_PW_PREV_ENV_ROOT" 328 pw_error_info 329 pw_error_info "But it is now being activated from" 330 pw_error_info 331 pw_error_info " $_PW_ACTUAL_ENVIRONMENT_ROOT" 332 pw_error_info 333 pw_error_info "This is likely because the checkout moved. After moving " 334 pw_error_info "the checkout a full '. ./bootstrap.sh' is required." 335 pw_error_info 336 _PW_ENV_SETUP_STATUS=1 337 fi 338 fi 339 340 if [ "$_PW_ENV_SETUP_STATUS" -ne 0 ]; then 341 return 342 fi 343 344 if [ -f "$_PW_SETUP_SH" ]; then 345 . "$_PW_SETUP_SH" 346 347 if [ "$?" -eq 0 ]; then 348 if [ "$_PW_NAME" = "bootstrap" ] && [ -z "$PW_ENVSETUP_QUIET" ]; then 349 echo "To reactivate this environment in the future, run this in your " 350 echo "terminal:" 351 echo 352 pw_green " source ./activate.sh" 353 echo 354 echo "To deactivate this environment, run this:" 355 echo 356 pw_green " deactivate" 357 echo 358 fi 359 else 360 pw_error "Error during $_PW_NAME--see messages above." 361 fi 362 else 363 pw_error "Error during $_PW_NAME--see messages above." 364 fi 365} 366 367pw_install_post_checkout_hook() { 368 cp "$PW_ROOT/pw_env_setup/post-checkout-hook.sh" "$PW_PROJECT_ROOT/.git/hooks/post-checkout" 369} 370 371pw_cleanup() { 372 unset _PW_BANNER 373 unset _PW_BANNER_FUNC 374 unset PW_BANNER_FUNC 375 unset _PW_ENV_SETUP 376 unset _PW_NAME 377 unset PW_ENVIRONMENT_ROOT 378 unset _PW_PYTHON 379 unset _PW_ENV_ROOT_TXT 380 unset _PW_PREV_ENV_ROOT 381 unset _PW_SETUP_SH 382 unset _PW_DEACTIVATE_SH 383 unset _NEW_PW_ROOT 384 unset _PW_ENV_SETUP_STATUS 385 unset _PW_ENV_PREFIX 386 unset _PW_ENV 387 unset _PW_DOTENV 388 389 unset -f pw_none 390 unset -f pw_red 391 unset -f pw_bold_red 392 unset -f pw_yellow 393 unset -f pw_bold_yellow 394 unset -f pw_green 395 unset -f pw_bold_green 396 unset -f pw_blue 397 unset -f pw_cyan 398 unset -f pw_magenta 399 unset -f pw_bold_white 400 unset -f pw_eval_sourced 401 unset -f pw_check_root 402 unset -f pw_get_env_root 403 unset -f _pw_banner 404 unset -f pw_bootstrap 405 unset -f pw_activate 406 unset -f pw_finalize 407 unset -f pw_install_post_checkout_hook 408 unset -f pw_cleanup 409 unset -f _pw_hello 410 unset -f pw_error 411 unset -f pw_error_info 412} 413