pw_env_setup: smarter checks for cipd auth

Only complain about not being logged into CIPD if we're actually
having trouble accessing things in CIPD.

Change-Id: I469aa0370572b1e596d99e691b21d6fa66a4f62e
diff --git a/bootstrap.sh b/bootstrap.sh
index 89e887b..c2b8028 100644
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -109,13 +109,18 @@
   fi
 fi
 
-. $SETUP_SH
+if [ -f $SETUP_SH ]; then
+  . $SETUP_SH
 
-if [ $_PW_IS_BOOTSTRAP -eq 0 ] && [ -z "$PW_ENVSETUP_QUIET" ]; then
-  echo
-  echo "To activate this environment in the future, run this in your terminal:"
-  echo
-  _pw_green "  . activate.sh\n"
+  if [ $_PW_IS_BOOTSTRAP -eq 0 ] && [ -z "$PW_ENVSETUP_QUIET" ]; then
+    echo
+    echo "To activate this environment in the future, run this in your "
+    echo "terminal:"
+    echo
+    _pw_green "  . activate.sh\n"
+  fi
+else
+  _pw_red "Error during bootstrap--see messages above."
 fi
 
 unset _PW_IS_BOOTSTRAP
diff --git a/pw_env_setup/py/pw_env_setup/cargo_setup/__init__.py b/pw_env_setup/py/pw_env_setup/cargo_setup/__init__.py
index ddb0da6..73b8c0f 100644
--- a/pw_env_setup/py/pw_env_setup/cargo_setup/__init__.py
+++ b/pw_env_setup/py/pw_env_setup/cargo_setup/__init__.py
@@ -51,3 +51,5 @@
             ]  # yapf: disable
 
             subprocess.check_call(cmd)
+
+    return True
diff --git a/pw_env_setup/py/pw_env_setup/cipd_setup/update.py b/pw_env_setup/py/pw_env_setup/cipd_setup/update.py
index e64b3a8..fb19c3c 100755
--- a/pw_env_setup/py/pw_env_setup/cipd_setup/update.py
+++ b/pw_env_setup/py/pw_env_setup/cipd_setup/update.py
@@ -60,20 +60,35 @@
     return parser.parse_args(argv)
 
 
-def check_auth(cipd):
-    """Check logged into CIPD."""
+def check_auth(cipd, paths=('pigweed', )):
+    """Check have access to CIPD pigweed directory."""
+
     try:
         subprocess.check_output([cipd, 'auth-info'], stderr=subprocess.STDOUT)
-        return True
-
+        logged_in = True
     except subprocess.CalledProcessError:
-        print('=' * 60, file=sys.stderr)
-        print('ERROR: not logged into CIPD--please run this command:',
-              file=sys.stderr)
-        print(cipd, 'auth-login', file=sys.stderr)
-        print('=' * 60, file=sys.stderr)
+        logged_in = False
 
-        return False
+    for path in paths:
+        # Not catching CalledProcessError because 'cipd ls' seems to never
+        # return an error code.
+        output = subprocess.check_output([cipd, 'ls', path],
+                                         stderr=subprocess.STDOUT).decode()
+        if 'No matching packages' in output:
+            print()
+            print('=' * 60, file=sys.stderr)
+            if logged_in:
+                print('ERROR: no access to CIPD path "{}":'.format(path),
+                      file=sys.stderr)
+            else:
+                print('ERROR: no access to CIPD path "{}", try logging in '
+                      'with this command:'.format(path),
+                      file=sys.stderr)
+                print(cipd, 'auth-login', file=sys.stderr)
+            print('=' * 60, file=sys.stderr)
+            return False
+
+    return True
 
 
 def write_ensure_file(package_file, ensure_file):
@@ -104,7 +119,7 @@
     """Grab the tools listed in ensure_files."""
 
     if not check_auth(cipd):
-        return
+        return False
 
     # TODO(mohrr) use os.makedirs(..., exist_ok=True).
     if not os.path.isdir(root_install_dir):
@@ -171,6 +186,8 @@
                 env_vars.prepend('PATH',
                                  os.path.join(install_dir, 'mingw64', 'bin'))
 
+    return True
+
 
 if __name__ == '__main__':
     update(**vars(parse()))
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 4fc4211..f734be2 100755
--- a/pw_env_setup/py/pw_env_setup/env_setup.py
+++ b/pw_env_setup/py/pw_env_setup/env_setup.py
@@ -79,11 +79,15 @@
     class Status:  # pylint: disable=too-few-public-methods
         DONE = 'done'
         SKIPPED = 'skipped'
+        FAILED = 'failed'
 
     def __init__(self, status, *messages):
         self._status = status
         self._messages = list(messages)
 
+    def ok(self):
+        return self._status in {_Result.Status.DONE, _Result.Status.SKIPPED}
+
     def status_str(self):
         return self._status
 
@@ -172,6 +176,9 @@
             for message in result.messages():
                 self._env.echo(message)
 
+            if not result.ok():
+                return -1
+
             self._log('done')
 
         self._log('')
@@ -182,6 +189,8 @@
             self._env.write(outs)
             self.write_sanity_check(outs)
 
+        return 0
+
     def cipd(self):
         install_dir = os.path.join(self._pw_root, '.cipd')
 
@@ -189,13 +198,14 @@
 
         package_files = glob.glob(
             os.path.join(self._setup_root, 'cipd_setup', '*.json'))
-        cipd_update.update(
-            cipd=cipd_client,
-            root_install_dir=install_dir,
-            package_files=package_files,
-            cache_dir=self._cipd_cache_dir,
-            env_vars=self._env,
-        )
+        if not cipd_update.update(
+                cipd=cipd_client,
+                root_install_dir=install_dir,
+                package_files=package_files,
+                cache_dir=self._cipd_cache_dir,
+                env_vars=self._env,
+        ):
+            return _Result(_Result.Status.FAILED)
 
         return _Result(_Result.Status.DONE)
 
@@ -228,12 +238,13 @@
 
         python = os.path.join(cipd_bin, py_executable)
 
-        virtualenv_setup.install(
-            venv_path=venv_path,
-            requirements=[requirements],
-            python=python,
-            env=self._env,
-        )
+        if not virtualenv_setup.install(
+                venv_path=venv_path,
+                requirements=[requirements],
+                python=python,
+                env=self._env,
+        ):
+            return _Result(_Result.Status.FAILED)
 
         return _Result(_Result.Status.DONE)
 
@@ -253,7 +264,9 @@
                 '          to enable Rust.',
             )
 
-        cargo_setup.install(pw_root=self._pw_root, env=self._env)
+        if not cargo_setup.install(pw_root=self._pw_root, env=self._env):
+            return _Result(_Result.Status.FAILED)
+
         return _Result(_Result.Status.DONE)
 
     def write_preamble(self, fd):
diff --git a/pw_env_setup/py/pw_env_setup/virtualenv_setup/install.py b/pw_env_setup/py/pw_env_setup/virtualenv_setup/install.py
index eed4e10..768f241 100644
--- a/pw_env_setup/py/pw_env_setup/virtualenv_setup/install.py
+++ b/pw_env_setup/py/pw_env_setup/virtualenv_setup/install.py
@@ -95,7 +95,7 @@
         print('=' * 60, file=sys.stderr)
         print('Unexpected Python version:', version, file=sys.stderr)
         print('=' * 60, file=sys.stderr)
-        return
+        return False
 
     pyvenv_cfg = os.path.join(venv_path, 'pyvenv.cfg')
     if full_envsetup or not os.path.exists(pyvenv_cfg):
@@ -154,3 +154,5 @@
         env.set('VIRTUAL_ENV', venv_path)
         env.prepend('PATH', venv_bin)
         env.clear('PYTHONHOME')
+
+    return True