bootstrap.sh: Abort if PW_ROOT has spaces

- The scripts in .python3-env/bin use a shebang line to point to
  Python. If the Python path has spaces, this line will not work
  correctly. Until this can be fixed, abort bootstrap.sh if Pigweed's
  path has spaces.
- Quote expansions in environment setup to prepare for eventually
  allowing paths with spaces.

Change-Id: I85333bd930e03731e5ae093c5f63b6a2a26c6316
diff --git a/bootstrap.sh b/bootstrap.sh
index dfc13ac..e455958 100644
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -51,24 +51,34 @@
 # variable set.
 # TODO(mohrr) find out a way to do this without PW_CHECKOUT_ROOT.
 if test -n "$PW_CHECKOUT_ROOT"; then
-  PW_SETUP_SCRIPT_PATH=$(_pw_abspath "$PW_CHECKOUT_ROOT/bootstrap.sh")
+  PW_SETUP_SCRIPT_PATH="$(_pw_abspath "$PW_CHECKOUT_ROOT/bootstrap.sh")"
   unset PW_CHECKOUT_ROOT
 # Shell: bash.
 elif test -n "$BASH"; then
-  PW_SETUP_SCRIPT_PATH=$(_pw_abspath $BASH_SOURCE)
+  PW_SETUP_SCRIPT_PATH="$(_pw_abspath "$BASH_SOURCE")"
 # Shell: zsh.
 elif test -n "$ZSH_NAME"; then
-  PW_SETUP_SCRIPT_PATH=$(_pw_abspath ${(%):-%N})
+  PW_SETUP_SCRIPT_PATH="$(_pw_abspath "${(%):-%N}")"
 # Shell: dash.
 elif test ${0##*/} = dash; then
-  PW_SETUP_SCRIPT_PATH=$(_pw_abspath \
-    $(lsof -p $$ -Fn0 | tail -1 | sed 's#^[^/]*##;'))
+  PW_SETUP_SCRIPT_PATH="$(_pw_abspath \
+    "$(lsof -p $$ -Fn0 | tail -1 | sed 's#^[^/]*##;')")"
 # If everything else fails, try $0. It could work.
 else
-  PW_SETUP_SCRIPT_PATH=$(_pw_abspath $0)
+  PW_SETUP_SCRIPT_PATH="$(_pw_abspath "$0")"
 fi
 
-PW_ROOT=$(dirname $PW_SETUP_SCRIPT_PATH)
+PW_ROOT="$(dirname "$PW_SETUP_SCRIPT_PATH")"
+
+if [[ "$PW_ROOT" = *" "* ]]; then
+  _pw_bold_red "Error: The Pigweed path contains spaces\n"
+  _pw_red "  The path '$PW_ROOT' contains spaces. "
+  _pw_red "  Pigweed's Python environment currently requires Pigweed to be "
+  _pw_red "  at a path without spaces. Please checkout Pigweed in a directory "
+  _pw_red "  without spaces and retry running bootstrap."
+  return
+fi
+
 export PW_ROOT
 
 SETUP_SH="$PW_ROOT/pw_env_setup/.env_setup.sh"
@@ -79,12 +89,12 @@
 fi
 
 # Run full bootstrap when invoked as bootstrap, or env file is missing/empty.
-[ $(basename $PW_SETUP_SCRIPT_PATH) = "bootstrap.sh" ] || \
-  [ ! -f $SETUP_SH ] || \
-  [ ! -s $SETUP_SH ]
-_PW_IS_BOOTSTRAP=$?
+[ "$(basename "$PW_SETUP_SCRIPT_PATH")" = "bootstrap.sh" ] || \
+  [ ! -f "$SETUP_SH" ] || \
+  [ ! -s "$SETUP_SH" ]
+_PW_IS_BOOTSTRAP="$?"
 
-if [ $_PW_IS_BOOTSTRAP -eq 0 ]; then
+if [ "$_PW_IS_BOOTSTRAP" -eq 0 ]; then
   _PW_NAME="bootstrap"
 
   if [ -z "$PW_ENVSETUP_QUIET" ]; then
@@ -104,7 +114,7 @@
     return
   fi
 
-  $PYTHON $PW_ROOT/pw_env_setup/py/pw_env_setup/env_setup.py --shell-file $SETUP_SH
+  "$PYTHON" "$PW_ROOT/pw_env_setup/py/pw_env_setup/env_setup.py" --shell-file "$SETUP_SH"
 else
   _PW_NAME="activate"
 
@@ -113,11 +123,11 @@
   fi
 fi
 
-if [ -f $SETUP_SH ]; then
-  . $SETUP_SH
+if [ -f "$SETUP_SH" ]; then
+  . "$SETUP_SH"
 
-  if [ $? -eq 0 ]; then
-    if [ $_PW_IS_BOOTSTRAP -eq 0 ] && [ -z "$PW_ENVSETUP_QUIET" ]; then
+  if [ "$?" -eq 0 ]; then
+    if [ "$_PW_IS_BOOTSTRAP" -eq 0 ] && [ -z "$PW_ENVSETUP_QUIET" ]; then
       echo "To activate this environment in the future, run this in your "
       echo "terminal:"
       echo
diff --git a/pw_env_setup/py/pw_env_setup/environment.py b/pw_env_setup/py/pw_env_setup/environment.py
index f1f7143..1c4e5d0 100644
--- a/pw_env_setup/py/pw_env_setup/environment.py
+++ b/pw_env_setup/py/pw_env_setup/environment.py
@@ -146,15 +146,15 @@
         else:
             outs.write('# Remove \n#   {value}\n# from\n#   {name}\n# before '
                        'adding it back.\n'
-                       '{name}=$(echo "${name}"'
+                       '{name}="$(echo "${name}"'
                        ' | sed "s/{pathsep}{escvalue}{pathsep}/{pathsep}/g;"'
                        ' | sed "s/^{escvalue}{pathsep}//g;"'
                        ' | sed "s/{pathsep}{escvalue}$//g;"'
-                       ')\nexport {name}\n'.format(name=self.name,
-                                                   value=self.value,
-                                                   escvalue=self.value.replace(
-                                                       '/', '\\/'),
-                                                   pathsep=self._pathsep))
+                       ')"\nexport {name}\n'.format(
+                           name=self.name,
+                           value=self.value,
+                           escvalue=self.value.replace('/', '\\/'),
+                           pathsep=self._pathsep))
 
     def apply(self, env):
         env[self.name] = env[self.name].replace(
@@ -291,7 +291,7 @@
                 'if %ERRORLEVEL% neq 0 goto {}\n'.format(_SCRIPT_END_LABEL))
         else:
             # Assume failing command produced relevant output.
-            outs.write('if [ $? != 0 ]; then\n  return 1\nfi\n')
+            outs.write('if [ "$?" -ne 0 ]; then\n  return 1\nfi\n')
 
 
 class BlankLine(_Action):
diff --git a/targets/host/run_test b/targets/host/run_test
index 09aef1a..5e8eca6 100755
--- a/targets/host/run_test
+++ b/targets/host/run_test
@@ -15,4 +15,4 @@
 
 # Test runner for host Linux/macOS systems.
 # Called with the path to a test binary and directly executes it.
-$*
+"$@"