diff --git a/activate.fish b/activate.fish new file mode 120000 index 000000000..07bfcce50 --- /dev/null +++ b/activate.fish @@ -0,0 +1 @@ +bootstrap.fish \ No newline at end of file diff --git a/bootstrap.fish b/bootstrap.fish new file mode 100644 index 000000000..97eb75796 --- /dev/null +++ b/bootstrap.fish @@ -0,0 +1,90 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +# This script must be tested on fish 3.6.0 + +# Get the absolute path of the bootstrap script. +set _PW_BOOTSTRAP_PATH (path resolve (status current-filename)) + +# Check if this file is being executed or sourced. +set _pw_sourced 0 +if string match --quiet '*from sourcing file*' (status) + set _pw_sourced 1 +end + +# Downstream projects need to set something other than PW_ROOT here, like +# YOUR_PROJECT_ROOT. Please also set PW_PROJECT_ROOT and PW_ROOT before +# invoking pw_bootstrap or pw_activate. +######### BEGIN PROJECT-SPECIFIC CODE ######### +set --export PW_ROOT (path resolve (dirname $_PW_BOOTSTRAP_PATH)) + +# Please also set PW_PROJECT_ROOT to YOUR_PROJECT_ROOT. +set --export PW_PROJECT_ROOT $PW_ROOT + +# Downstream projects may wish to set PW_BANNER_FUNC to a function that prints +# an ASCII art banner here. For example: +# +# set --export PW_BANNER_FUNC banner_function_name +# +########## END PROJECT-SPECIFIC CODE ########## + +source $PW_ROOT/pw_env_setup/util.fish + +# Check environment properties +pw_deactivate +pw_eval_sourced $_pw_sourced $_PW_BOOTSTRAP_PATH +if not pw_check_root $PW_ROOT + return +end + +set --export _PW_ACTUAL_ENVIRONMENT_ROOT (pw_get_env_root) + +set SETUP_SH "$_PW_ACTUAL_ENVIRONMENT_ROOT/activate.fish" + +# Run full bootstrap when invoked as bootstrap, or env file is missing/empty. +if test (status basename) = "bootstrap.fish" + or not test -e $SETUP_SH + or not test -s $SETUP_SH + ######### BEGIN PROJECT-SPECIFIC CODE ######### + pw_bootstrap --shell-file "$SETUP_SH" --install-dir "$_PW_ACTUAL_ENVIRONMENT_ROOT" + ########## END PROJECT-SPECIFIC CODE ########## + set finalize_mode bootstrap +else + pw_activate_message + set finalize_mode activate +end +# NOTE: Sourced scripts in fish cannot be sourced within a fuction if +# variables should be exported to the calling shell. So activate.fish +# must be sourced here instead of within pw_finalize or another +# function. +pw_finalize_pre_check $finalize_mode "$SETUP_SH" +source $SETUP_SH +pw_finalize_post_check $finalize_mode "$SETUP_SH" + +if set --query _PW_ENV_SETUP_STATUS; and test "$_PW_ENV_SETUP_STATUS" -eq 0 + # This is where any additional checks about the environment should go. + ######### BEGIN PROJECT-SPECIFIC CODE ######### + echo -n + ########## END PROJECT-SPECIFIC CODE ########## +end + +set -e _pw_sourced +set -e _PW_BOOTSTRAP_PATH +set -e SETUP_SH + +# TODO(tonymd): Source fish pw_cli shell completion. + +pw_cleanup + +git -C "$PW_ROOT" config blame.ignoreRevsFile .git-blame-ignore-revs diff --git a/docs/get_started/upstream.rst b/docs/get_started/upstream.rst index 2a6327f9d..9437a1789 100644 --- a/docs/get_started/upstream.rst +++ b/docs/get_started/upstream.rst @@ -45,6 +45,11 @@ To get setup: $ bootstrap.bat (On Windows) ... + .. tip:: + + If you use the `Fish shell `_ run `source + ./bootstrap.fish` instead. + #. Configure the GN build. .. code-block:: bash diff --git a/pw_env_setup/docs.rst b/pw_env_setup/docs.rst index 2aa540262..366a8a6c8 100644 --- a/pw_env_setup/docs.rst +++ b/pw_env_setup/docs.rst @@ -40,8 +40,13 @@ runs bootstrap. .. note:: On Windows the scripts used to set up the environment are ``bootstrap.bat`` - and ``activate.bat``. For simplicity they will be referred to with the - ``.sh`` endings unless the distinction is relevant. + and ``activate.bat``. + + ``bootstrap.fish`` and ``activate.fish`` are also available for `Fish shell + `_ users. + + For simplicity they will be referred to with the ``.sh`` endings unless the + distinction is relevant. On POSIX systems, the environment can be deactivated by running ``deactivate``. diff --git a/pw_env_setup/py/environment_test.py b/pw_env_setup/py/environment_test.py index 54627a4cd..b51bc1eca 100644 --- a/pw_env_setup/py/environment_test.py +++ b/pw_env_setup/py/environment_test.py @@ -60,8 +60,8 @@ def _evaluate_env_in_shell(env): delete=False, mode='w+', ) as temp: - env.write(temp) temp_name = temp.name + env.write(temp, shell_file=temp_name) # Evaluate env sourcing script and capture output of 'env'. if os.name == 'nt': @@ -164,7 +164,7 @@ class EnvironmentTest(unittest.TestCase): self.env.set(self.var_not_set, '/foo/bar/baz') self.env.add_replacement('FOOBAR', '/foo/bar') buf = six.StringIO() - self.env.write(buf) + self.env.write(buf, shell_file='test.sh') assert '/foo/bar' not in buf.getvalue() def test_variable_replacement(self): @@ -172,7 +172,7 @@ class EnvironmentTest(unittest.TestCase): self.env.set(self.var_not_set, '/foo/bar/baz') self.env.add_replacement('FOOBAR') buf = six.StringIO() - self.env.write(buf) + self.env.write(buf, shell_file='test.sh') print(buf.getvalue()) assert '/foo/bar/baz' not in buf.getvalue() diff --git a/pw_env_setup/py/pw_env_setup/env_setup.py b/pw_env_setup/py/pw_env_setup/env_setup.py index 3daff581f..7df2c1a8a 100755 --- a/pw_env_setup/py/pw_env_setup/env_setup.py +++ b/pw_env_setup/py/pw_env_setup/env_setup.py @@ -200,6 +200,7 @@ class EnvSetup(object): ) self._cipd_cache_dir = cipd_cache_dir self._shell_file = shell_file + self._env._shell_file = shell_file self._is_windows = os.name == 'nt' self._quiet = quiet self._install_dir = install_dir @@ -628,14 +629,14 @@ Then use `set +x` to go back to normal. return 0 with open(self._shell_file, 'w') as outs: - self._env.write(outs) + self._env.write(outs, shell_file=self._shell_file) deactivate = os.path.join( self._install_dir, 'deactivate{}'.format(os.path.splitext(self._shell_file)[1]), ) with open(deactivate, 'w') as outs: - self._env.write_deactivate(outs) + self._env.write_deactivate(outs, shell_file=deactivate) config = { # Skipping sysname and nodename in os.uname(). nodename could change diff --git a/pw_env_setup/py/pw_env_setup/environment.py b/pw_env_setup/py/pw_env_setup/environment.py index a624d1550..4c379089f 100644 --- a/pw_env_setup/py/pw_env_setup/environment.py +++ b/pw_env_setup/py/pw_env_setup/environment.py @@ -333,6 +333,7 @@ class Environment(object): self.replacements = [] self._join = Join(pathsep) self._finalized = False + self._shell_file = '' def add_replacement(self, variable, value=None): self.replacements.append((variable, value)) @@ -440,7 +441,7 @@ class Environment(object): if not self._windows: buf = StringIO() - self.write_deactivate(buf) + self.write_deactivate(buf, shell_file=self._shell_file) self._actions.append(Function('_pw_deactivate', buf.getvalue())) self._blankline() @@ -457,17 +458,27 @@ class Environment(object): def json(self, outs): json_visitor.JSONVisitor().serialize(self, outs) - def write(self, outs): + def write(self, outs, shell_file): if self._windows: visitor = batch_visitor.BatchVisitor(pathsep=self._pathsep) else: - visitor = shell_visitor.ShellVisitor(pathsep=self._pathsep) + if shell_file.endswith('.fish'): + visitor = shell_visitor.FishShellVisitor() + else: + visitor = shell_visitor.ShellVisitor(pathsep=self._pathsep) visitor.serialize(self, outs) - def write_deactivate(self, outs): + def write_deactivate(self, outs, shell_file): if self._windows: return - visitor = shell_visitor.DeactivateShellVisitor(pathsep=self._pathsep) + if shell_file.endswith('.fish'): + visitor = shell_visitor.DeactivateFishShellVisitor( + pathsep=self._pathsep + ) + else: + visitor = shell_visitor.DeactivateShellVisitor( + pathsep=self._pathsep + ) visitor.serialize(self, outs) @contextlib.contextmanager diff --git a/pw_env_setup/py/pw_env_setup/shell_visitor.py b/pw_env_setup/py/pw_env_setup/shell_visitor.py index c76653c6b..341f81cc9 100644 --- a/pw_env_setup/py/pw_env_setup/shell_visitor.py +++ b/pw_env_setup/py/pw_env_setup/shell_visitor.py @@ -54,7 +54,7 @@ class _BaseShellVisitor(object): # pylint: disable=useless-object-inheritance class ShellVisitor(_BaseShellVisitor): - """Serializes an Environment into a shell file.""" + """Serializes an Environment into a bash-like shell file.""" def __init__(self, *args, **kwargs): super(ShellVisitor, self).__init__(*args, **kwargs) @@ -174,7 +174,7 @@ class ShellVisitor(_BaseShellVisitor): class DeactivateShellVisitor(_BaseShellVisitor): - """Removes values from an Environment.""" + """Removes values from a bash-like shell environment.""" def __init__(self, *args, **kwargs): pathsep = kwargs.pop('pathsep', ':') @@ -227,3 +227,132 @@ class DeactivateShellVisitor(_BaseShellVisitor): def visit_function(self, function): pass # Not relevant. + + +class FishShellVisitor(ShellVisitor): + """Serializes an Environment into a fish shell file.""" + + def __init__(self, *args, **kwargs): + super(FishShellVisitor, self).__init__(*args, **kwargs) + self._pathsep = ' ' + + def _remove_value_from_path(self, variable, value): + return 'set PATH (string match -v {value} ${variable})\n'.format( + variable=variable, value=value + ) + + def visit_set(self, set): # pylint: disable=redefined-builtin + value = self._apply_replacements(set) + self._outs.write( + 'set -x {name} {value}\n'.format(name=set.name, value=value) + ) + + def visit_clear(self, clear): + self._outs.write('set -e {name}\n'.format(**vars(clear))) + + def visit_remove(self, remove): + value = self._apply_replacements(remove) + self._remove_value_from_path(remove.name, value) + + def visit_prepend(self, prepend): + value = self._apply_replacements(prepend) + self._outs.write( + 'set -x --prepend {name} {value}\n'.format( + name=prepend.name, value=value + ) + ) + + def visit_append(self, append): + value = self._apply_replacements(append) + self._outs.write( + 'set -x --append {name} {value}\n'.format( + name=append.name, value=value + ) + ) + + def visit_echo(self, echo): + self._outs.write('if not set -q PW_ENVSETUP_QUIET\n') + if echo.newline: + self._outs.write(' echo "{}"\n'.format(echo.value)) + else: + self._outs.write(' echo -n "{}"\n'.format(echo.value)) + self._outs.write('end\n') + + def visit_hash(self, hash): # pylint: disable=redefined-builtin + del hash + + def visit_function(self, function): + self._outs.write( + 'function {name}\n{body}\nend\n'.format( + name=function.name, body=function.body + ) + ) + + def visit_command(self, command): + self._outs.write('{}\n'.format(' '.join(command.command))) + if not command.exit_on_error: + return + + # Assume failing command produced relevant output. + self._outs.write('if test $status -ne 0\n return 1\nend\n') + + def visit_doctor(self, doctor): + self._outs.write('if not set -q PW_ACTIVATE_SKIP_CHECKS\n') + self.visit_command(doctor) + self._outs.write('else\n') + self._outs.write( + 'echo Skipping environment check because ' + 'PW_ACTIVATE_SKIP_CHECKS is set\n' + ) + self._outs.write('end\n') + + +class DeactivateFishShellVisitor(FishShellVisitor): + """Removes values from a fish shell environment.""" + + def serialize(self, env, outs): + try: + self._outs = outs + + env.accept(self) + + finally: + self._outs = None + + def visit_set(self, set): # pylint: disable=redefined-builtin + if set.deactivate: + self._outs.write('set -e {name}\n'.format(name=set.name)) + + def visit_clear(self, clear): + pass # Not relevant. + + def visit_remove(self, remove): + pass # Not relevant. + + def visit_prepend(self, prepend): + self._outs.write( + self._remove_value_from_path(prepend.name, prepend.value) + ) + + def visit_append(self, append): + self._outs.write( + self._remove_value_from_path(append.name, append.value) + ) + + def visit_echo(self, echo): + pass # Not relevant. + + def visit_comment(self, comment): + pass # Not relevant. + + def visit_command(self, command): + pass # Not relevant. + + def visit_doctor(self, doctor): + pass # Not relevant. + + def visit_blank_line(self, blank_line): + pass # Not relevant. + + def visit_function(self, function): + pass # Not relevant. diff --git a/pw_env_setup/util.fish b/pw_env_setup/util.fish new file mode 100644 index 000000000..20ee6da42 --- /dev/null +++ b/pw_env_setup/util.fish @@ -0,0 +1,410 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +# This script must be tested on fish 3.6.0 + +# Note: Colors are unfortunately duplicated in several places; and removing the +# duplication is not easy. Their locations are: +# +# - bootstrap.sh +# - pw_cli/color.py +# - pw_env_setup/py/pw_env_setup/colors.py +# - pw_env_setup/util.fish +# - pw_env_setup/util.sh +# +# So please keep them matching then modifying them. +function pw_none + set_color normal + echo -e $argv +end + +function pw_red + set_color red + echo -e $argv + set_color normal +end + +function pw_bold_red + set_color --bold red + echo -e $argv + set_color normal +end + +function pw_yellow + set_color yellow + echo -e $argv + set_color normal +end + +function pw_bold_yellow + set_color --bold yellow + echo -e $argv + set_color normal +end + +function pw_green + set_color green + echo -e $argv + set_color normal +end + +function pw_bold_green + set_color --bold green + echo -e $argv + set_color normal +end + +function pw_blue + set_color blue + echo -e $argv + set_color normal +end + +function pw_cyan + set_color cyan + echo -e $argv + set_color normal +end + +function pw_magenta + set_color magenta + echo -e $argv + set_color normal +end + +function pw_bold_white + set_color --bold white + echo -e $argv + set_color normal +end + +function pw_error + set_color --bold brred + echo -e $argv 1>&2 + set_color normal +end + +function pw_error_info + set_color red + echo -e $argv 1>&2 + set_color normal +end + +# Print an error and exit if $is_sourced == 0 (the first argument). +function pw_eval_sourced --argument-names is_sourced bootstrap_path + if test $is_sourced -eq 0 + set _PW_NAME (basename $bootstrap_path) + pw_error "Error: Attempting to $_PW_NAME in a subshell" + pw_error_info " Since $_PW_NAME modifies your shell's environment" + pw_error_info " variables, it must be sourced rather than executed. In" + pw_error_info " particular, 'fish $_PW_NAME' will not work since the " + pw_error_info " modified environment will get destroyed at the end of the" + pw_error_info " script. Instead, source the script's contents in your" + pw_error_info " shell:" + pw_error_info "" + pw_error_info " \$ source $_PW_NAME" + exit 1 + end +end + +# Check for spaces in $_PW_ROOT (the first argument). +function pw_check_root --argument-names _PW_ROOT + if string match --quiet '* *' $_PW_ROOT + pw_error "Error: The Pigweed path contains spaces" + pw_error_info " The path '$_PW_ROOT' contains spaces. " + pw_error_info " Pigweed's Python environment currently requires Pigweed to" + pw_error_info " be at a path without spaces. Please checkout Pigweed in a" + pw_error_info " directory without spaces and retry running bootstrap." + return -1 + end +end + +# Check for and return the environment directory location. +function pw_get_env_root + # PW_ENVIRONMENT_ROOT allows callers to specify where the environment should + # be installed. bootstrap.sh scripts should not use that variable to store the + # result of this function. This separation allows scripts to assume + # PW_ENVIRONMENT_ROOT came from the caller and not from a previous bootstrap + # possibly from another workspace. PW_ENVIRONMENT_ROOT will be cleared after + # environment setup completes. + if set --query PW_ENVIRONMENT_ROOT + echo $PW_ENVIRONMENT_ROOT + return + end + + # Determine project-level root directory. + if set --query PW_PROJECT_ROOT + set _PW_ENV_PREFIX $PW_PROJECT_ROOT + else + set _PW_ENV_PREFIX $PW_ROOT + end + + # If /environment exists, use it. Otherwise, if /.environment + # exists, use it. Finally, use /environment. + set _PW_DOTENV $_PW_ENV_PREFIX/.environment + set _PW_ENV $_PW_ENV_PREFIX/environment + + if test -d $_PW_DOTENV + if test -d $_PW_ENV + pw_error "Error: both possible environment directories exist." + pw_error_info " $_PW_DOTENV" + pw_error_info " $_PW_ENV" + pw_error_info " If only one of these folders exists it will be used for" + pw_error_info " the Pigweed environment. If neither exists" + pw_error_info " '<...>/environment' will be used. Since both exist," + pw_error_info " bootstrap doesn't know which to use. Please delete one" + pw_error_info " or both and rerun bootstrap." + exit 1 + end + end + + if test -d $_PW_ENV + echo $_PW_ENV + else if test -d $_PW_DOTENV + echo $_PW_DOTENV + else + echo $_PW_ENV + end +end + + +set --export _PW_BANNER "\ + ▒█████▄ █▓ ▄███▒ ▒█ ▒█ ░▓████▒ ░▓████▒ ▒▓████▄ + ▒█░ █░ ░█▒ ██▒ ▀█▒ ▒█░ █ ▒█ ▒█ ▀ ▒█ ▀ ▒█ ▀█▌ + ▒█▄▄▄█░ ░█▒ █▓░ ▄▄░ ▒█░ █ ▒█ ▒███ ▒███ ░█ █▌ + ▒█▀ ░█░ ▓█ █▓ ░█░ █ ▒█ ▒█ ▄ ▒█ ▄ ░█ ▄█▌ + ▒█ ░█░ ░▓███▀ ▒█▓▀▓█░ ░▓████▒ ░▓████▒ ▒▓████▀ +" + +function _default_pw_banner_func + pw_magenta $_PW_BANNER +end + +set --export _PW_BANNER_FUNC _default_pw_banner_func + +function _pw_hello --argument-names _PW_TEXT + # If $PW_BANNER_FUNC is defined, use that as the banner function + # instead of the default. + if set --query PW_BANNER_FUNC + set _PW_BANNER_FUNC $PW_BANNER_FUNC + end + # Display the banner unless PW_ENVSETUP_QUIET or + # PW_ENVSETUP_NO_BANNER is set. + if test -z "$PW_ENVSETUP_QUIET" && test -z "$PW_ENVSETUP_NO_BANNER" + pw_green "\n WELCOME TO...\n" + set_color normal + $_PW_BANNER_FUNC + set_color normal + pw_green $_PW_TEXT + end +end + +function pw_deactivate + # Assume PW_ROOT and PW_PROJECT_ROOT have already been set and we need to + # preserve their values. + set _NEW_PW_ROOT $PW_ROOT + set _NEW_PW_PROJECT_ROOT $PW_PROJECT_ROOT + + # Find deactivate script, run it, and then delete it. This way if the + # deactivate script is doing something wrong subsequent bootstraps still + # have a chance to pass. + set _PW_DEACTIVATE_SH $_PW_ACTUAL_ENVIRONMENT_ROOT/deactivate.fish + if test -f $_PW_DEACTIVATE_SH + . $_PW_DEACTIVATE_SH + rm -f $_PW_DEACTIVATE_SH &>/dev/null + end + + # If there's a _pw_deactivate function run it. Redirect output to /dev/null + # in case _pw_deactivate doesn't exist. Remove _pw_deactivate when complete. + if functions --query _pw_deactivate + _pw_deactivate >/dev/null 2>/dev/null + functions -e _pw_deactivate + end + + # Restore. + set --export PW_ROOT $_NEW_PW_ROOT + set --export PW_PROJECT_ROOT $_NEW_PW_PROJECT_ROOT +end + +function deactivate + pw_deactivate + functions -e pw_deactivate + functions -e deactivate + set -e PW_ROOT + set -e PW_PROJECT_ROOT + set -e PW_BRANDING_BANNER + set -e PW_BRANDING_BANNER_COLOR +end + +# The next three functions use the following variables. +# * PW_BANNER_FUNC: function to print banner +# * PW_BOOTSTRAP_PYTHON: specific Python interpreter to use for bootstrap +# * PW_ROOT: path to Pigweed root +# * PW_ENVSETUP_QUIET: limit output if "true" +# +# All arguments passed in are passed on to env_setup.py in pw_bootstrap, +# pw_activate takes no arguments, and pw_finalize takes the name of the script +# "bootstrap" or "activate" and the path to the setup script written by +# bootstrap.fish. +function pw_bootstrap + _pw_hello " BOOTSTRAP! Bootstrap may take a few minutes; please be patient.\n" + + if functions --query python + pw_error "Error: 'python' is an alias" + pw_error_info "The shell has a 'python' alias set. This causes many obscure" + pw_error_info "Python-related issues both in and out of Pigweed. Please" + pw_error_info "remove the Python alias from your shell init file or at" + pw_error_info "least run the following command before bootstrapping" + pw_error_info "Pigweed." + pw_error_info + pw_error_info " functions --erase python" + pw_error_info + return + end + + # Allow forcing a specific version of Python for testing pursposes. + if test -n "$PW_BOOTSTRAP_PYTHON" + set _PW_PYTHON "$PW_BOOTSTRAP_PYTHON" + else if command -v python3 >/dev/null 2>/dev/null + set _PW_PYTHON python3 + else if command -v python2 >/dev/null 2>/dev/null + set _PW_PYTHON python2 + else if command -v python >/dev/null 2>/dev/null + set _PW_PYTHON python + else + pw_error "Error: No system Python present\n" + pw_error_info " Pigweed's bootstrap process requires a local system" + pw_error_info " Python. Please install Python on your system, add it to " + pw_error_info " your PATH and re-try running bootstrap." + return + end + + if test -n "$_PW_ENV_SETUP" + $_PW_ENV_SETUP $argv + set _PW_ENV_SETUP_STATUS $status + else + $_PW_PYTHON $PW_ROOT/pw_env_setup/py/pw_env_setup/env_setup.py $argv + set _PW_ENV_SETUP_STATUS $status + end + + # Write the directory path at bootstrap time into the directory. This helps + # us double-check things are still in the same space when calling activate. + set _PW_ENV_ROOT_TXT $_PW_ACTUAL_ENVIRONMENT_ROOT/env_root.txt + echo $_PW_ACTUAL_ENVIRONMENT_ROOT >$_PW_ENV_ROOT_TXT 2>/dev/null + + # Create the environment README file. Use quotes to prevent alias expansion. + cp $PW_ROOT/pw_env_setup/destination.md $_PW_ACTUAL_ENVIRONMENT_ROOT/README.md &>/dev/null +end + +function pw_activate_message + _pw_hello " ACTIVATOR! This sets your shell environment variables.\n" + set _PW_ENV_SETUP_STATUS 0 +end + +function pw_finalize_pre_check --argument-names _PW_NAME _PW_SETUP_SH + # Check that the environment directory agrees that the path it's at matches + # where it thinks it should be. If not, bail. + set _PW_ENV_ROOT_TXT "$_PW_ACTUAL_ENVIRONMENT_ROOT/env_root.txt" + if test -f $_PW_ENV_ROOT_TXT + set _PW_PREV_ENV_ROOT (cat $_PW_ENV_ROOT_TXT) + if test "$_PW_ACTUAL_ENVIRONMENT_ROOT" != "$_PW_PREV_ENV_ROOT" + pw_error "Error: Environment directory moved" + pw_error_info "This Pigweed environment was created at" + pw_error_info + pw_error_info " $_PW_PREV_ENV_ROOT" + pw_error_info + pw_error_info "But it is now being activated from" + pw_error_info + pw_error_info " $_PW_ACTUAL_ENVIRONMENT_ROOT" + pw_error_info + pw_error_info "This is likely because the checkout moved. After moving " + pw_error_info "the checkout a full '. ./bootstrap.fish' is required." + pw_error_info + set _PW_ENV_SETUP_STATUS 1 + end + end + + if test -n "$_PW_ENV_SETUP_STATUS" && test "$_PW_ENV_SETUP_STATUS" -ne 0 + return + end + + if not test -f "$_PW_SETUP_SH" + pw_error "Error during $_PW_NAME--see messages above." + end +end + +function pw_finalize_post_check --argument-names _PW_NAME _PW_SETUP_SH + if test "$status" -eq 0 + if test "$_PW_NAME" = bootstrap && test -z "$PW_ENVSETUP_QUIET" + echo "To reactivate this environment in the future, run this in your " + echo "terminal:" + echo + pw_green " source ./activate.fish" + echo + echo "To deactivate this environment, run this:" + echo + pw_green " deactivate" + echo + end + else + pw_error "Error during $_PW_NAME--see messages above." + end +end + +function pw_install_post_checkout_hook + cp $PW_ROOT/pw_env_setup/post-checkout-hook.sh $PW_PROJECT_ROOT/.git/hooks/post-checkout +end + +function pw_cleanup + set -e _PW_BANNER + set -e _PW_BANNER_FUNC + set -e PW_BANNER_FUNC + set -e _PW_ENV_SETUP + set -e _PW_NAME + set -e PW_ENVIRONMENT_ROOT + set -e _PW_PYTHON + set -e _PW_ENV_ROOT_TXT + set -e _PW_PREV_ENV_ROOT + set -e _PW_SETUP_SH + set -e _PW_DEACTIVATE_SH + set -e _NEW_PW_ROOT + set -e _PW_ENV_SETUP_STATUS + set -e _PW_ENV_PREFIX + set -e _PW_ENV + set -e _PW_DOTENV + + functions -e pw_none + functions -e pw_red + functions -e pw_bold_red + functions -e pw_yellow + functions -e pw_bold_yellow + functions -e pw_green + functions -e pw_bold_green + functions -e pw_blue + functions -e pw_cyan + functions -e pw_magenta + functions -e pw_bold_white + functions -e pw_eval_sourced + functions -e pw_check_root + functions -e pw_get_env_root + functions -e _pw_banner + functions -e pw_bootstrap + functions -e pw_activate + functions -e pw_finalize + functions -e pw_install_post_checkout_hook + functions -e pw_cleanup + functions -e _pw_hello + functions -e pw_error + functions -e pw_error_info +end diff --git a/pw_env_setup/util.sh b/pw_env_setup/util.sh index c8e1bf2f8..0fb667566 100644 --- a/pw_env_setup/util.sh +++ b/pw_env_setup/util.sh @@ -21,6 +21,8 @@ export PATH # - bootstrap.sh # - pw_cli/color.py # - pw_env_setup/py/pw_env_setup/colors.py +# - pw_env_setup/util.fish +# - pw_env_setup/util.sh # # So please keep them matching then modifying them. pw_none() { @@ -160,6 +162,7 @@ pw_get_env_root() { # the contortions that would be needed to share this snippet across shell, # batch, and Python. Locations: # +# - pw_env_setup/util.fish # - pw_env_setup/util.sh # - pw_cli/branding.py # - pw_env_setup/py/pw_env_setup/windows_env_start.py @@ -181,9 +184,13 @@ _PW_BANNER_FUNC="_pw_banner" _pw_hello() { _PW_TEXT="$1" + # If $PW_BANNER_FUNC is defined, use that as the banner function + # instead of the default. if [ -n "$PW_BANNER_FUNC" ]; then _PW_BANNER_FUNC="$PW_BANNER_FUNC" fi + # Display the banner unless PW_ENVSETUP_QUIET or + # PW_ENVSETUP_NO_BANNER is set. if [ -z "$PW_ENVSETUP_QUIET" ] && [ -z "$PW_ENVSETUP_NO_BANNER" ]; then pw_green "\n WELCOME TO...\n" "$_PW_BANNER_FUNC"