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"