devserver: Add support for downloading multiple artifacts for a target.

BUG=chromium:779870
TEST=curl "http://${ds}/stage?archive_url=gs://chromeos-image-archive/${build}&artifacts=quick_provision"

Change-Id: I3a39897e2f274b875c26592dd06a653adb6da5e0
Reviewed-on: https://chromium-review.googlesource.com/751790
Commit-Ready: David Riley <davidriley@chromium.org>
Tested-by: David Riley <davidriley@chromium.org>
Reviewed-by: Xixuan Wu <xixuan@chromium.org>
diff --git a/build_artifact.py b/build_artifact.py
index 85426f1..6b5739c 100755
--- a/build_artifact.py
+++ b/build_artifact.py
@@ -337,8 +337,11 @@
                 self.name, self.is_regex_name, timeout)
             self._UpdateName(new_names)
 
-          self._Log('Downloading file %s', self.name)
-          self.install_path = downloader.Fetch(self.name, real_install_dir)
+
+          files = self.name if isinstance(self.name, list) else [self.name]
+          for filename in files:
+            self._Log('Downloading file %s', filename)
+            self.install_path = downloader.Fetch(filename, real_install_dir)
           self._Setup()
           self._MarkArtifactStaged()
         except Exception as e:
@@ -379,6 +382,29 @@
     self.installed_files = [new_install_path]
 
 
+class MultiArtifact(Artifact):
+  """Wrapper for artifacts where name matches multiple items.."""
+
+  def __init__(self, *args, **kwargs):
+    """Takes Artifact args.
+
+    Args:
+      *args: See Artifact documentation.
+      **kwargs: See Artifact documentation.
+    """
+    super(MultiArtifact, self).__init__(*args, **kwargs)
+    self.single_name = False
+
+  def _UpdateName(self, names):
+    self.name = names if isinstance(names, list) else [names]
+
+  def _Setup(self):
+    super(MultiArtifact, self)._Setup()
+
+    self.installed_files = [os.path.join(self.install_dir, self.install_subdir,
+                                         name) for name in self.name]
+
+
 class DeltaPayloadBase(AUTestPayload):
   """Delta payloads from the archive_url.