add some clearer failure messages

This CL adds clearer failure messages, for a number of failure modes
encountered while tracing the referenced bug. It does not change any
build behavior.

BUG=chromium:308203
TEST=unit tests pass

Change-Id: I5c54fadce801cc3ce86ab934be9189a34360d60a
Reviewed-on: https://chromium-review.googlesource.com/173617
Reviewed-by: Aviv Keshet <akeshet@chromium.org>
Commit-Queue: Aviv Keshet <akeshet@chromium.org>
Tested-by: Aviv Keshet <akeshet@chromium.org>
Reviewed-by: Matt Tennant <mtennant@chromium.org>
diff --git a/buildbot/manifest_version.py b/buildbot/manifest_version.py
index 305e46f..fb0f3ea 100644
--- a/buildbot/manifest_version.py
+++ b/buildbot/manifest_version.py
@@ -29,17 +29,18 @@
 
 class VersionUpdateException(Exception):
   """Exception gets thrown for failing to update the version file"""
-  pass
 
 
 class StatusUpdateException(Exception):
   """Exception gets thrown for failure to update the status"""
-  pass
 
 
 class GenerateBuildSpecException(Exception):
   """Exception gets thrown for failure to Generate a buildspec for the build"""
-  pass
+
+
+class BuildSpecsValueError(Exception):
+  """Exception gets thrown when a encountering invalid values."""
 
 
 def RefreshManifestCheckout(manifest_dir, manifest_repo):
@@ -566,6 +567,10 @@
     Returns path of version.  By default if version is not set, returns the path
     of the current version.
     """
+    if not self.all_specs_dir:
+      raise BuildSpecsValueError('GetLocalManifest failed, BuildSpecsManager '
+                                 'instance not yet initialized by call to '
+                                 'InitializeManifestVariables.')
     if version:
       return os.path.join(self.all_specs_dir, version + '.xml')
     elif self.current_version:
@@ -579,7 +584,11 @@
     # Only refresh the manifest checkout if needed.
     if not self.InitializeManifestVariables(version=version):
       self.RefreshManifestCheckout()
-      self.InitializeManifestVariables(version=version)
+      if not self.InitializeManifestVariables(version=version):
+        raise BuildSpecsValueError('Failure in BootstrapFromVersion. '
+                                   'InitializeManifestVariables failed after '
+                                   'RefreshManifestCheckout for version '
+                                   '%s.' % version)
 
     # Return the current manifest.
     self.current_version = version
diff --git a/lib/cros_build_lib.py b/lib/cros_build_lib.py
index a01f03d..3e67f1d 100644
--- a/lib/cros_build_lib.py
+++ b/lib/cros_build_lib.py
@@ -295,7 +295,8 @@
                  coming from subprocess as well.
     error_code_ok: Does not raise an exception when command returns a non-zero
                    exit code.  Instead, returns the CommandResult object
-                   containing the exit code.
+                   containing the exit code. Note: will still raise an
+                   exception if the cmd file does not exist.
     kill_timeout: If we're interrupted, how long should we give the invoked
                   process to shutdown from a SIGTERM before we SIGKILL it.
                   Specified in seconds.
@@ -1265,7 +1266,10 @@
 
 class ApiMismatchError(Exception):
   """Raised by GetTargetChromiteApiVersion."""
-  pass
+
+
+class NoChromiteError(Exception):
+  """Raised when an expected chromite installation was missing."""
 
 
 def GetTargetChromiteApiVersion(buildroot, validate_version=True):
@@ -1282,9 +1286,19 @@
 
   Returns the version number in (major, minor) tuple.
   """
-  api = RunCommandCaptureOutput(
-      [constants.PATH_TO_CBUILDBOT, '--reexec-api-version'],
-      cwd=buildroot, error_code_ok=True)
+  try:
+    api = RunCommandCaptureOutput(
+        [constants.PATH_TO_CBUILDBOT, '--reexec-api-version'],
+        cwd=buildroot, error_code_ok=True)
+  except RunCommandError:
+    # Although error_code_ok=True was used, this exception will still be raised
+    # if the executible did not exist.
+    full_cbuildbot_path = os.path.join(buildroot, constants.PATH_TO_CBUILDBOT)
+    if not os.path.exists(full_cbuildbot_path):
+      raise NoChromiteError('No cbuildbot found in buildroot %s, expected to '
+                            'find %s. ' % (buildroot, full_cbuildbot_path))
+    raise
+
   # If the command failed, then we're targeting a cbuildbot that lacks the
   # option; assume 0:0 (ie, initial state).
   major = minor = 0