cbuildbot_launch: Only fixup crcmod when required.

A previous hack started installing crcmod on every build, but that's
often not needed. This change only installs if there is a system
crcmod that doesn't contain a required extension.

BUG=chromium:763438
TEST=cbuildbot_launch_unittest

Change-Id: I0043a2c1a71ea4191371ccd387546490adca1a3e
Reviewed-on: https://chromium-review.googlesource.com/664055
Reviewed-by: Don Garrett <dgarrett@chromium.org>
Tested-by: Don Garrett <dgarrett@chromium.org>
Trybot-Ready: Don Garrett <dgarrett@chromium.org>
diff --git a/scripts/cbuildbot_launch.py b/scripts/cbuildbot_launch.py
index ff37ea4..cb132c4 100644
--- a/scripts/cbuildbot_launch.py
+++ b/scripts/cbuildbot_launch.py
@@ -250,6 +250,40 @@
   return result.returncode
 
 
+def _InstallSystemCrcmodIfNeeded():
+  """Install Crcmod binary extension if needed.
+
+  If the build host has python-crcmod installed without the binary extension,
+  that breaks some versions of gsutil. In that case, this function installs
+  a new copy of the module with the extension.
+
+  Newer branches workaround this in gs.py, and hopefully future versions of
+  gsutil will work around this in gsutil, however, older branches will always
+  have this problem.
+
+  So... this method will always be required unless/until we chose to solve this
+  through configuration management of hosts.
+
+  http://crbug.com/763438 covers this in detail.
+  """
+  try:
+    import crcmod
+    # If crcmod exists on the system, but doesn't have the binary extension,
+    # gsutil behaves badly. Override the system module with one that contains
+    # the binary extension. This depends on /usr/local/lib overridding /usr/lib.
+    if not (getattr(crcmod, 'crcmod', None) and
+            getattr(crcmod.crcmod, '_usingExtension', None)):
+      logging.warn('FORCING CRCMOD INSTALL to workaround crbug.com/763438.')
+      cmd = ['pip', 'install', '--ignore-installed', 'crcmod']
+      result = cros_build_lib.SudoRunCommand(
+          cmd, error_code_ok=True, mute_output=True)
+      logging.warn('CRCMOD INSTALL RETURNED :%d', result.returncode)
+  except ImportError:
+    # If crcmod doesn't exist on the system, gs.py will properly use its
+    # version in the cache.
+    pass
+
+
 def ConfigureGlobalEnvironment():
   """Setup process wide environmental changes."""
   # Set umask to 022 so files created by buildbot are readable.
@@ -267,12 +301,7 @@
   # This variable is required for repo sync's to work in all cases.
   os.environ['LANG'] = 'en_US.UTF-8'
 
-  # TODO(dgarrett): Super ugly, super temporary hack to fix release builds.
-  logging.warn('FORCING CRCMOD INSTALL to workaround crbug.com/763438.')
-  cmd = ['pip', 'install', '--ignore-installed', 'crcmod']
-  result = cros_build_lib.SudoRunCommand(
-      cmd, error_code_ok=True, mute_output=True)
-  logging.warn('CRCMOD INSTALL RETURNED: %d', result.returncode)
+  _InstallSystemCrcmodIfNeeded()
 
 
 def _main(argv):