Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / chromite / cbuildbot / lkgm_manager.py
index f4c3792..8d011bf 100644 (file)
@@ -9,7 +9,6 @@ import logging
 import os
 import re
 import tempfile
-import time
 from xml.dom import minidom
 
 from chromite.cbuildbot import cbuildbot_config
@@ -17,6 +16,7 @@ from chromite.cbuildbot import constants
 from chromite.cbuildbot import manifest_version
 from chromite.lib import cros_build_lib
 from chromite.lib import git
+from chromite.lib import timeout_util
 
 
 # Paladin constants for manifest names.
@@ -35,6 +35,8 @@ PALADIN_FAIL_COUNT_ATTR = 'fail_count'
 PALADIN_PASS_COUNT_ATTR = 'pass_count'
 PALADIN_TOTAL_FAIL_COUNT_ATTR = 'total_fail_count'
 
+CHROME_ELEMENT = 'chrome'
+CHROME_VERSION_ATTR = 'version'
 
 MANIFEST_ELEMENT = 'manifest'
 DEFAULT_ELEMENT = 'default'
@@ -120,18 +122,6 @@ class LKGMManager(manifest_version.BuildSpecsManager):
   Vars:
     lkgm_subdir:  Subdirectory within manifest repo to store candidates.
   """
-  # Max timeout before assuming other builders have failed.
-  LONG_MAX_TIMEOUT_SECONDS = 1200
-
-  # Max timeout before assuming other builders have failed for Chrome PFQ.
-  # Longer as there is little to lose for Chrome PFQ waiting and arm
-  # has been slower often.
-  CHROME_LONG_MAX_TIMEOUT_SECONDS = 3 * 60 * 60
-  # Max timeout before assuming other builders have failed.
-  MAX_TIMEOUT_SECONDS = 300
-  # Polling timeout for checking git repo for other build statuses.
-  SLEEP_TIMEOUT = constants.SLEEP_TIMEOUT
-
   # Sub-directories for LKGM and Chrome LKGM's.
   LKGM_SUBDIR = 'LKGM-candidates'
   CHROME_PFQ_SUBDIR = 'chrome-LKGM-candidates'
@@ -177,45 +167,6 @@ class LKGMManager(manifest_version.BuildSpecsManager):
       assert cbuildbot_config.IsPFQType(self.build_type)
       self.rel_working_dir = self.LKGM_SUBDIR
 
-  def _GetMaxLongTimeout(self):
-    """Get the long "max timeout" for this builder.
-
-    Returns:
-      Timeout in seconds.
-    """
-    if self.build_type == constants.PFQ_TYPE:
-      return self.LONG_MAX_TIMEOUT_SECONDS
-    else:
-      return self.CHROME_LONG_MAX_TIMEOUT_SECONDS
-
-  def _RunLambdaWithTimeout(self, function_to_run, max_timeout):
-    """Runs function_to_run until it returns a value or timeout is reached.
-
-    function_to_run is called with one argument equal to the number of seconds
-    left until timing out.
-
-    Args:
-      function_to_run: Function to run until it returns a value or the timeout
-        is reached.
-      max_timeout: Time to wait for function_to_run to return a value.
-      use_long_timeout: Adjusts the timeout to use.  See logic below.
-    """
-    function_success = False
-    start_time = time.time()
-
-    # Monitor the repo until all builders report in or we've waited too long.
-    seconds_left = max_timeout - (time.time() - start_time)
-    while seconds_left > 0:
-      function_success = function_to_run(seconds_left)
-      if function_success:
-        break
-      else:
-        time.sleep(self.SLEEP_TIMEOUT)
-
-      seconds_left = max_timeout - (time.time() - start_time)
-
-    return function_success
-
   def GetCurrentVersionInfo(self):
     """Returns the lkgm version info from the version file."""
     version_info = super(LKGMManager, self).GetCurrentVersionInfo()
@@ -223,6 +174,24 @@ class LKGMManager(manifest_version.BuildSpecsManager):
                               chrome_branch=version_info.chrome_branch,
                               incr_type=self.incr_type)
 
+  def _AddChromeVersionToManifest(self, manifest, chrome_version):
+    """Adds the chrome element with version |chrome_version| to |manifest|.
+
+    The manifest file should contain the Chrome version to build for
+    PFQ slaves.
+
+    Args:
+      manifest: Path to the manifest
+      chrome_version: A string representing the version of Chrome
+        (e.g. 35.0.1863.0).
+    """
+    manifest_dom = minidom.parse(manifest)
+    chrome = manifest_dom.createElement(CHROME_ELEMENT)
+    chrome.setAttribute(CHROME_VERSION_ATTR, chrome_version)
+    manifest_dom.documentElement.appendChild(chrome)
+    with open(manifest, 'w+') as manifest_file:
+      manifest_dom.writexml(manifest_file)
+
   def _AddPatchesToManifest(self, manifest, patches):
     """Adds list of |patches| to given |manifest|.
 
@@ -330,13 +299,20 @@ class LKGMManager(manifest_version.BuildSpecsManager):
     return new_path
 
   def CreateNewCandidate(self, validation_pool=None,
-                         retries=manifest_version.NUM_RETRIES):
+                         chrome_version=None,
+                         retries=manifest_version.NUM_RETRIES,
+                         build_id=None):
     """Creates, syncs to, and returns the next candidate manifest.
 
     Args:
       validation_pool: Validation pool to apply to the manifest before
         publishing.
-      retries: Number of retries for updating the status.
+      chrome_version: The Chrome version to write in the manifest. Defaults
+        to None, in which case no version is written.
+      retries: Number of retries for updating the status. Defaults to
+        manifest_version.NUM_RETRIES.
+      build_id: Optional integer cidb id of the build that is creating
+                this candidate.
 
     Raises:
       GenerateBuildSpecException in case of failure to generate a buildspec
@@ -351,6 +327,11 @@ class LKGMManager(manifest_version.BuildSpecsManager):
 
     self._GenerateBlameListSinceLKGM()
     new_manifest = self.CreateManifest()
+
+    # For Chrome PFQ, add the version of Chrome to use.
+    if chrome_version:
+      self._AddChromeVersionToManifest(new_manifest, chrome_version)
+
     # For the Commit Queue, apply the validation pool as part of checkout.
     if validation_pool:
       # If we have nothing that could apply from the validation pool and
@@ -391,7 +372,7 @@ class LKGMManager(manifest_version.BuildSpecsManager):
         git.CreatePushBranch(manifest_version.PUSH_BRANCH, self.manifest_dir,
                              sync=False)
         version = self.GetNextVersion(version_info)
-        self.PublishManifest(new_manifest, version)
+        self.PublishManifest(new_manifest, version, build_id=build_id)
         self.current_version = version
         return self.GetLocalManifest(version)
       except cros_build_lib.RunCommandError as e:
@@ -402,7 +383,7 @@ class LKGMManager(manifest_version.BuildSpecsManager):
       raise manifest_version.GenerateBuildSpecException(last_error)
 
   def CreateFromManifest(self, manifest, retries=manifest_version.NUM_RETRIES,
-                         dashboard_url=None):
+                         dashboard_url=None, build_id=None):
     """Sets up an lkgm_manager from the given manifest.
 
     This method sets up an LKGM manager and publishes a new manifest to the
@@ -415,6 +396,8 @@ class LKGMManager(manifest_version.BuildSpecsManager):
         i.e R20-1920.0.1-rc7.xml where R20-1920.0.1-rc7 is the version.
       retries: Number of retries for updating the status.
       dashboard_url: Optional url linking to builder dashboard for this build.
+      build_id: Optional integer cidb build id of the build publishing the
+                manifest.
 
     Raises:
       GenerateBuildSpecException in case of failure to check-in the new
@@ -432,7 +415,7 @@ class LKGMManager(manifest_version.BuildSpecsManager):
                              sync=False)
         version = os.path.splitext(os.path.basename(manifest))[0]
         logging.info('Publishing filtered build spec')
-        self.PublishManifest(new_manifest, version)
+        self.PublishManifest(new_manifest, version, build_id=build_id)
         self.SetInFlight(version, dashboard_url=dashboard_url)
         self.current_version = version
         return self.GetLocalManifest(version)
@@ -443,12 +426,13 @@ class LKGMManager(manifest_version.BuildSpecsManager):
     else:
       raise manifest_version.GenerateBuildSpecException(last_error)
 
-  def GetLatestCandidate(self, dashboard_url=None):
+  def GetLatestCandidate(self, dashboard_url=None, timeout=3 * 60):
     """Gets and syncs to the next candiate manifest.
 
     Args:
       retries: Number of retries for updating the status
       dashboard_url: Optional url linking to builder dashboard for this build.
+      timeout: The timeout in seconds.
 
     Returns:
       Local path to manifest to build or None in case of no need to build.
@@ -456,7 +440,7 @@ class LKGMManager(manifest_version.BuildSpecsManager):
     Raises:
       GenerateBuildSpecException in case of failure to generate a buildspec
     """
-    def _AttemptToGetLatestCandidate(seconds_left):
+    def _AttemptToGetLatestCandidate():
       """Attempts to acquire latest candidate using manifest repo."""
       self.RefreshManifestCheckout()
       self.InitializeManifestVariables(self.GetCurrentVersionInfo())
@@ -464,19 +448,25 @@ class LKGMManager(manifest_version.BuildSpecsManager):
         return self.latest_unprocessed
       elif self.dry_run and self.latest:
         return self.latest
-      else:
-        minutes_left = int((seconds_left / 60) + 0.5)
-        logging.info('Found nothing new to build, will keep trying for %d more'
-                     ' minutes.', minutes_left)
-        logging.info('If this is a PFQ, then you should have forced the master'
-                     ', which runs cbuildbot_master')
-        return None
+
+    def _PrintRemainingTime(minutes_left):
+      logging.info('Found nothing new to build, will keep trying for %d more'
+                   ' minutes.', minutes_left)
+      logging.info('If this is a PFQ, then you should have forced the master'
+                   ', which runs cbuildbot_master')
 
     # TODO(sosa):  We only really need the overlay for the version info but we
     # do a full checkout here because we have no way of refining it currently.
     self.CheckoutSourceCode()
-    version_to_build = self._RunLambdaWithTimeout(
-        _AttemptToGetLatestCandidate, self._GetMaxLongTimeout())
+    try:
+      version_to_build = timeout_util.WaitForSuccess(
+          lambda x: x is None,
+          _AttemptToGetLatestCandidate,
+          timeout,
+          period=self.SLEEP_TIMEOUT,
+          side_effect_func=_PrintRemainingTime)
+    except timeout_util.TimeoutError:
+      version_to_build = None
 
     if version_to_build:
       logging.info('Starting build spec: %s', version_to_build)
@@ -491,55 +481,6 @@ class LKGMManager(manifest_version.BuildSpecsManager):
     else:
       return None
 
-  def GetBuildersStatus(self, builders_array, wait_for_results=True):
-    """Returns a build-names->status dictionary of build statuses.
-
-    Args:
-      builders_array: A list of the names of the builders to check.
-      wait_for_results: If True, keep trying until all builder statuses are
-        available or until timeout is reached.
-    """
-    builders_completed = set()
-    builder_statuses = {}
-
-    def _CheckStatusOfBuildersArray(seconds_left):
-      """Helper function that iterates through current statuses."""
-      for builder_name in builders_array:
-        cached_status = builder_statuses.get(builder_name)
-        if not cached_status or not cached_status.Completed():
-          logging.debug("Checking for builder %s's status", builder_name)
-          builder_status = self.GetBuildStatus(builder_name,
-                                               self.current_version)
-          builder_statuses[builder_name] = builder_status
-          if builder_status.Missing():
-            logging.warn('No status found for builder %s.', builder_name)
-          elif builder_status.Completed():
-            builders_completed.add(builder_name)
-            logging.info('Builder %s completed with status "%s".',
-                         builder_name, builder_status.status)
-
-      if len(builders_completed) < len(builders_array):
-        minutes_left = int((seconds_left / 60) + 0.5)
-        logging.info('Still waiting (up to %d more minutes) for the following'
-                     ' builds to complete: %r', minutes_left,
-                     sorted(set(builders_array).difference(builders_completed)))
-        return None
-      else:
-        return 'Builds completed.'
-
-    # Even if we do not want to wait for results long, wait a little bit
-    # just to exercise the same code.
-    max_timeout = self._GetMaxLongTimeout() if wait_for_results else 3 * 60
-
-    # Check for build completion until all builders report in.
-    builds_succeeded = self._RunLambdaWithTimeout(
-        _CheckStatusOfBuildersArray, max_timeout)
-    if not builds_succeeded:
-      logging.error('Not all builds finished before timeout (%d minutes)'
-                    ' reached.', int((max_timeout / 60) + 0.5))
-
-    return builder_statuses
-
   def PromoteCandidate(self, retries=manifest_version.NUM_RETRIES):
     """Promotes the current LKGM candidate to be a real versioned LKGM."""
     assert self.current_version, 'No current manifest exists.'