Preprocess remote patches together with other patches.

BUG=chromium-os:30710
TEST=Ran job submissions with local master.

Change-Id: I427ae415d3f402e798f0cff41f9a2b3352e74aad
Reviewed-on: https://gerrit.chromium.org/gerrit/22269
Commit-Ready: Ryan Cui <rcui@chromium.org>
Reviewed-by: Ryan Cui <rcui@chromium.org>
Tested-by: Ryan Cui <rcui@chromium.org>
diff --git a/scripts/cbuildbot.py b/scripts/cbuildbot.py
index 0b469e8..aed8a1d 100644
--- a/scripts/cbuildbot.py
+++ b/scripts/cbuildbot.py
@@ -31,6 +31,7 @@
 from chromite.buildbot import remote_try
 from chromite.buildbot import repository
 from chromite.buildbot import tee
+from chromite.buildbot import trybot_patch_pool
 
 from chromite.lib import cgroups
 from chromite.lib import cleanup
@@ -114,39 +115,37 @@
                  'Buildroot checked out to %s\n' % manifest_branch)
 
 
-def _PreProcessPatches(gerrit_patches, local_patches):
-  """Validate patches ASAP to catch user errors.  Also generate patch info.
+def AcquirePoolFromOptions(options, target_manifest_branch):
+  """Generate patch objects from passed in options.
 
   Args:
-    gerrit_patches: List of gerrit CL ID's passed in by user.
-    local_patches: List of local project branches to generate patches from.
+    options: The options object generated by optparse.
 
-  Returns:
-    A tuple containing a list of cros_patch.GerritPatch and a list of
-    cros_patch.LocalGitRepoPatch objects.
+  Raises:
+    gerrit_helper.GerritException, cros_patch.PatchException
   """
-  gerrit_patch_info = []
-  local_patch_info = []
+  gerrit_patches = []
+  local_patches = []
+  remote_patches = []
 
-  try:
-    if gerrit_patches:
-      gerrit_patch_info = gerrit_helper.GetGerritPatchInfo(gerrit_patches)
-      for patch in gerrit_patch_info:
-        if patch.IsAlreadyMerged():
-          cros_lib.Warning('Patch %s has already been merged.' % str(patch))
-  except gerrit_helper.GerritException as e:
-    cros_lib.Die(str(e))
+  if options.gerrit_patches:
+    gerrit_patches = gerrit_helper.GetGerritPatchInfo(
+        options.gerrit_patches)
+    for patch in gerrit_patches:
+      if patch.IsAlreadyMerged():
+        cros_lib.Warning('Patch %s has already been merged.' % str(patch))
 
-  try:
-    if local_patches:
-      local_patch_info = cros_patch.PrepareLocalPatches(
-          local_patches,
-          _GetChromiteTrackingBranch())
+  if options.local_patches:
+    local_patches = cros_patch.PrepareLocalPatches(
+        options.local_patches,
+        target_manifest_branch)
 
-  except cros_patch.PatchException as e:
-    cros_lib.Die(str(e))
+  if options.remote_patches:
+    remote_patches = cros_patch.PrepareRemotePatches(
+        options.remote_patches)
 
-  return gerrit_patch_info, local_patch_info
+  return trybot_patch_pool.TrybotPatchPool(gerrit_patches, local_patches,
+                                           remote_patches)
 
 
 def _IsIncrementalBuild(buildroot, clobber):
@@ -170,6 +169,7 @@
     release_tag:  The associated "chrome os version" of this build.
     gerrit_patches: Gerrit patches to be included in build.
     local_patches: Local patches to be included in build.
+    remote_patches: Uploaded local patches to be included in build.
   """
 
   def __init__(self, options, build_config):
@@ -187,8 +187,7 @@
     self.archive_urls = {}
     self.release_tag = None
     self.target_manifest_branch = _GetChromiteTrackingBranch()
-    self.gerrit_patches = None
-    self.local_patches = None
+    self.patch_pool = trybot_patch_pool.GetEmptyPool()
 
   def Initialize(self):
     """Runs through the initialization steps of an actual build."""
@@ -198,9 +197,9 @@
 
     # We only want to do this if we need to patch changes.
     if not results_lib.Results.GetPrevious().get(
-        self._GetStageInstance(stages.PatchChangesStage, None, None).name):
-      self.gerrit_patches, self.local_patches = _PreProcessPatches(
-          self.options.gerrit_patches, self.options.local_patches)
+        stages.PatchChangesStage.StageNamePrefix()):
+      self.patch_pool = AcquirePoolFromOptions(self.options,
+                                               self.target_manifest_branch)
 
     bs.BuilderStage.SetManifestBranch(self.target_manifest_branch)
 
@@ -309,10 +308,8 @@
       sync_instance.Run()
       self._SetReleaseTag()
 
-      if (self.gerrit_patches or self.local_patches
-          or self.options.remote_patches):
-        self._RunStage(stages.PatchChangesStage,
-                       self.gerrit_patches, self.local_patches)
+      if self.patch_pool:
+        self._RunStage(stages.PatchChangesStage, self.patch_pool)
 
       if self._ShouldReExecuteInBuildRoot():
         print_report = False
@@ -659,6 +656,7 @@
 
 
 def _CreateParser():
+  """Generate and return the parser with all the options."""
   class CustomParser(optparse.OptionParser):
     def add_remote_option(self, *args, **kwargs):
       """For arguments that are passed-through to remote trybot."""
@@ -693,7 +691,6 @@
         elif value:
           parser.values.pass_through_args.append(str(value))
 
-  """Generate and return the parser with all the options."""
   # Parse options
   usage = "usage: %prog [options] buildbot_config"
   parser = CustomParser(usage=usage, option_class=CustomOption)
@@ -1010,14 +1007,14 @@
 
     # Verify gerrit patches are valid.
     print 'Verifying patches...'
-    _, local_patches = _PreProcessPatches(options.gerrit_patches,
-                                          options.local_patches)
+    patch_pool = AcquirePoolFromOptions(options, _GetChromiteTrackingBranch())
+
     # --debug need to be explicitly passed through for remote invocations.
     if options.buildbot and '--debug' not in options.pass_through_args:
       _ConfirmRemoteBuildbotRun()
 
     print 'Submitting tryjob...'
-    tryjob = remote_try.RemoteTryJob(options, args, local_patches)
+    tryjob = remote_try.RemoteTryJob(options, args, patch_pool.local_patches)
     tryjob.Submit(testjob=options.test_tryjob, dryrun=options.debug)
     print 'Tryjob submitted!'
     print ('Go to %s to view the status of your job.'