(firmware-1299B) buildbot: Archive experimental firmware images.

Cherry-picked from: https://gerrit.chromium.org/gerrit/21742
With proper changes for firmware branch.

BUG=chromium-os:30452
TEST=cbuildbot

Change-Id: I32ef56b008a6d4d0f08cfc6b0bc4c0b52fe1bff7
Reviewed-on: https://gerrit.chromium.org/gerrit/21961
Tested-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-by: David James <davidjames@chromium.org>
diff --git a/buildbot/cbuildbot_commands.py b/buildbot/cbuildbot_commands.py
index 6c4097b..7a74dd5 100644
--- a/buildbot/cbuildbot_commands.py
+++ b/buildbot/cbuildbot_commands.py
@@ -895,6 +895,24 @@
                       cwd=scripts_dir)
 
 
+def BuildTarball(buildroot, input_list, tarball_output, cwd=None):
+  """Tars files and directories from input_list to tarball_output.
+
+  Args:
+    buildroot: Root directory where build occurs.
+    input_list: A list of files and directories to be archived.
+    tarball_output: Path of output tar archive file.
+    cwd: Current working directory when tar command is executed.
+  """
+  pbzip2 = os.path.join(buildroot, 'chroot', 'usr', 'bin', 'pbzip2')
+  cmd = ['tar',
+         '--use-compress-program=%s' % pbzip2,
+         '--checkpoint=10000',
+         '-cf', tarball_output]
+  cmd += input_list
+  cros_lib.RunCommand(cmd, cwd=cwd)
+
+
 def BuildAutotestTarball(buildroot, board, image_dir):
   """Tar up the autotest artifacts into image_dir.
 
@@ -905,17 +923,11 @@
 
   Returns the basename of the autotest tarball.
   """
-  filename = 'autotest.tar.bz2'
+  autotest_tarball = os.path.join(image_dir, 'autotest.tar.bz2')
   cwd = os.path.join(buildroot, 'chroot', 'build', board, 'usr', 'local')
-  pbzip2 = os.path.join(buildroot, 'chroot', 'usr', 'bin', 'pbzip2')
-  cmd = ['tar',
-         'cf',
-         os.path.join(image_dir, filename),
-         '--checkpoint=10000',
-         '--use-compress-program=%s' % pbzip2,
-         'autotest']
-  cros_lib.RunCommand(cmd, cwd=cwd)
-  return filename
+
+  BuildTarball(buildroot, ['autotest'], autotest_tarball, cwd=cwd)
+  return autotest_tarball
 
 
 def BuildImageZip(archive_dir, image_dir):
@@ -936,6 +948,31 @@
   return filename
 
 
+def BuildFirmwareArchive(buildroot, board, archive_dir):
+  """Build firmware_from_source.tar.bz2 in archive_dir from build root.
+
+  Args:
+    buildroot: Root directory where build occurs.
+    board: Board name of build target.
+    archive_dir: Directory to store output file.
+
+  Returns the basename of the archived file, or None if the target board does
+  not have firmware from source.
+  """
+  files = ['image.bin', 'ec.bin']
+  firmware_root = os.path.join(buildroot, 'chroot', 'build', board, 'firmware')
+  source_list = [image_file
+                 for image_file in files
+                 if os.path.exists(os.path.join(firmware_root, image_file))]
+  if not source_list:
+    return None
+
+  archive_name = 'firmware_from_source.tar.bz2'
+  archive_file = os.path.join(archive_dir, archive_name)
+  BuildTarball(buildroot, source_list, archive_file, cwd=firmware_root)
+  return archive_name
+
+
 def BuildFactoryZip(archive_dir, image_root):
   """Build factory_image.zip in archive_dir.
 
diff --git a/buildbot/cbuildbot_stages.py b/buildbot/cbuildbot_stages.py
index 5c0d5be..6af591c 100644
--- a/buildbot/cbuildbot_stages.py
+++ b/buildbot/cbuildbot_stages.py
@@ -953,6 +953,12 @@
       shutil.copy(os.path.join(image_dir, filename), archive_path)
       commands.UploadArchivedFile(archive_path, upload_url, filename, debug)
 
+    def ArchiveFirmwareImages():
+      """Archive firmware images built from source if available."""
+      filename = commands.BuildFirmwareArchive(buildroot, board, archive_path)
+      if filename:
+        commands.UploadArchivedFile(archive_path, upload_url, filename, debug)
+
     def BuildAndArchiveAllImages():
       # If we're an official build, generate the recovery image. To conserve
       # loop devices, we try to only run one instance of build_image at a
@@ -962,6 +968,7 @@
         commands.BuildRecoveryImage(buildroot, board, image_dir, extra_env)
 
       background.RunParallelSteps([BuildAndArchiveFactoryImages,
+                                   ArchiveFirmwareImages,
                                    ArchiveRegularImages])
 
     background.RunParallelSteps([