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 python2 > /dev/null 2> /dev/null; then 274 _PW_PYTHON=python2 275 elif command -v python > /dev/null 2> /dev/null; then 276 _PW_PYTHON=python 277 else 278 pw_error "Error: No system Python present\n" 279 pw_error_info " Pigweed's bootstrap process requires a local system" 280 pw_error_info " Python. Please install Python on your system, add it to " 281 pw_error_info " your PATH and re-try running bootstrap." 282 return 283 fi 284 285 if [ -n "$_PW_ENV_SETUP" ]; then 286 "$_PW_ENV_SETUP" "$@" 287 _PW_ENV_SETUP_STATUS="$?" 288 else 289 "$_PW_PYTHON" "$PW_ROOT/pw_env_setup/py/pw_env_setup/env_setup.py" "$@" 290 _PW_ENV_SETUP_STATUS="$?" 291 fi 292 293 # Write the directory path at bootstrap time into the directory. This helps 294 # us double-check things are still in the same space when calling activate. 295 _PW_ENV_ROOT_TXT="$_PW_ACTUAL_ENVIRONMENT_ROOT/env_root.txt" 296 echo "$_PW_ACTUAL_ENVIRONMENT_ROOT" > "$_PW_ENV_ROOT_TXT" 2> /dev/null 297 298 # Create the environment README file. Use quotes to prevent alias expansion. 299 "cp" "$PW_ROOT/pw_env_setup/destination.md" "$_PW_ACTUAL_ENVIRONMENT_ROOT/README.md" &> /dev/null 300} 301 302pw_activate() { 303 _pw_hello " ACTIVATOR! This sets your shell environment variables.\n" 304 _PW_ENV_SETUP_STATUS=0 305} 306 307pw_finalize() { 308 _PW_NAME="$1" 309 _PW_SETUP_SH="$2" 310 311 # Check that the environment directory agrees that the path it's at matches 312 # where it thinks it should be. If not, bail. 313 _PW_ENV_ROOT_TXT="$_PW_ACTUAL_ENVIRONMENT_ROOT/env_root.txt" 314 if [ -f "$_PW_ENV_ROOT_TXT" ]; then 315 _PW_PREV_ENV_ROOT="$(cat $_PW_ENV_ROOT_TXT)" 316 if [ "$_PW_ACTUAL_ENVIRONMENT_ROOT" != "$_PW_PREV_ENV_ROOT" ]; then 317 pw_error "Error: Environment directory moved" 318 pw_error_info "This Pigweed environment was created at" 319 pw_error_info 320 pw_error_info " $_PW_PREV_ENV_ROOT" 321 pw_error_info 322 pw_error_info "But it is now being activated from" 323 pw_error_info 324 pw_error_info " $_PW_ACTUAL_ENVIRONMENT_ROOT" 325 pw_error_info 326 pw_error_info "This is likely because the checkout moved. After moving " 327 pw_error_info "the checkout a full '. ./bootstrap.sh' is required." 328 pw_error_info 329 _PW_ENV_SETUP_STATUS=1 330 fi 331 fi 332 333 if [ "$_PW_ENV_SETUP_STATUS" -ne 0 ]; then 334 return 335 fi 336 337 if [ -f "$_PW_SETUP_SH" ]; then 338 . "$_PW_SETUP_SH" 339 340 if [ "$?" -eq 0 ]; then 341 if [ "$_PW_NAME" = "bootstrap" ] && [ -z "$PW_ENVSETUP_QUIET" ]; then 342 echo "To reactivate this environment in the future, run this in your " 343 echo "terminal:" 344 echo 345 pw_green " source ./activate.sh" 346 echo 347 echo "To deactivate this environment, run this:" 348 echo 349 pw_green " deactivate" 350 echo 351 fi 352 else 353 pw_error "Error during $_PW_NAME--see messages above." 354 fi 355 else 356 pw_error "Error during $_PW_NAME--see messages above." 357 fi 358} 359 360pw_install_post_checkout_hook() { 361 cp "$PW_ROOT/pw_env_setup/post-checkout-hook.sh" "$PW_PROJECT_ROOT/.git/hooks/post-checkout" 362} 363 364pw_cleanup() { 365 unset _PW_BANNER 366 unset _PW_BANNER_FUNC 367 unset PW_BANNER_FUNC 368 unset _PW_ENV_SETUP 369 unset _PW_NAME 370 unset PW_ENVIRONMENT_ROOT 371 unset _PW_PYTHON 372 unset _PW_ENV_ROOT_TXT 373 unset _PW_PREV_ENV_ROOT 374 unset _PW_SETUP_SH 375 unset _PW_DEACTIVATE_SH 376 unset _NEW_PW_ROOT 377 unset _PW_ENV_SETUP_STATUS 378 unset _PW_ENV_PREFIX 379 unset _PW_ENV 380 unset _PW_DOTENV 381 382 unset -f pw_none 383 unset -f pw_red 384 unset -f pw_bold_red 385 unset -f pw_yellow 386 unset -f pw_bold_yellow 387 unset -f pw_green 388 unset -f pw_bold_green 389 unset -f pw_blue 390 unset -f pw_cyan 391 unset -f pw_magenta 392 unset -f pw_bold_white 393 unset -f pw_eval_sourced 394 unset -f pw_check_root 395 unset -f pw_get_env_root 396 unset -f _pw_banner 397 unset -f pw_bootstrap 398 unset -f pw_activate 399 unset -f pw_finalize 400 unset -f pw_install_post_checkout_hook 401 unset -f pw_cleanup 402 unset -f _pw_hello 403 unset -f pw_error 404 unset -f pw_error_info 405} 406