Devtools: add ServeLocalDirectories().

This takes a list of mappings, instead of single directory path, and
will be used to configure development servers defined in a config file.

R=qsr@chromium.org

Review URL: https://codereview.chromium.org/1259763013 .

Cr-Mirrored-From: https://github.com/domokit/mojo
Cr-Mirrored-Commit: 4b0acc5be3e218b59a47a267525d845eaeb2a2cb
diff --git a/devtoolslib/android_shell.py b/devtoolslib/android_shell.py
index 7a7436f..2d87f4e 100644
--- a/devtoolslib/android_shell.py
+++ b/devtoolslib/android_shell.py
@@ -370,8 +370,7 @@
     logcat_watch_thread = threading.Thread(target=_ForwardObservatoriesAsNeeded)
     logcat_watch_thread.start()
 
-  def ServeLocalDirectory(self, local_dir_path, port=0,
-                          additional_mappings=None):
+  def ServeLocalDirectory(self, local_dir_path, port=0):
     """Serves the content of the local (host) directory, making it available to
     the shell under the url returned by the function.
 
@@ -381,16 +380,36 @@
     Args:
       local_dir_path: path to the directory to be served
       port: port at which the server will be available to the shell
-      additional_mappings: List of tuples (prefix, local_base_path) mapping
-          URLs that start with |prefix| to local directory at |local_base_path|.
-          The prefixes should skip the leading slash.
 
     Returns:
       The url that the shell can use to access the content of |local_dir_path|.
     """
     assert local_dir_path
-    server_address = start_http_server(local_dir_path, host_port=port,
-                                       additional_mappings=additional_mappings)
+    mappings = [('', local_dir_path)]
+    server_address = start_http_server(mappings, host_port=port)
+
+    return 'http://127.0.0.1:%d/' % self._ForwardDevicePortToHost(
+        port, server_address[1])
+
+  def ServeLocalDirectories(self, mappings, port=0):
+    """Serves the content of the local (host) directories, making it available
+    to the shell under the url returned by the function.
+
+    The server will run on a separate thread until the program terminates. The
+    call returns immediately.
+
+    Args:
+      mappings: List of tuples (prefix, local_base_path) mapping URLs that start
+          with |prefix| to local directory at |local_base_path|. The prefixes
+          should skip the leading slash. The first matching prefix will be used
+          each time.
+      port: port at which the server will be available to the shell
+
+    Returns:
+      The url that the shell can use to access the content of |local_dir_path|.
+    """
+    assert mappings
+    server_address = start_http_server(mappings, host_port=port)
 
     return 'http://127.0.0.1:%d/' % self._ForwardDevicePortToHost(
         port, server_address[1])
diff --git a/devtoolslib/http_server.py b/devtoolslib/http_server.py
index 67bb402..386b356 100644
--- a/devtoolslib/http_server.py
+++ b/devtoolslib/http_server.py
@@ -173,24 +173,21 @@
   return RequestHandler
 
 
-def start_http_server(local_dir_path, host_port=0, additional_mappings=None):
+def start_http_server(mappings, host_port=0):
   """Starts an http server serving files from |local_dir_path| on |host_port|.
 
   Args:
-    local_dir_path: Path to the local filesystem directory to be served over
-        http under.
+    mappings: List of tuples (prefix, local_base_path) mapping
+        URLs that start with |prefix| to local directory at |local_base_path|.
+        The prefixes should skip the leading slash. The first matching prefix
+        will be used each time.
     host_port: Port on the host machine to run the server on. Pass 0 to use a
         system-assigned port.
-    additional_mappings: List of tuples (prefix, local_base_path) mapping
-        URLs that start with |prefix| to local directory at |local_base_path|.
-        The prefixes should skip the leading slash.
 
   Returns:
     Tuple of the server address and the port on which it runs.
   """
-  assert local_dir_path
-  mappings = additional_mappings if additional_mappings else []
-  mappings.append(('', local_dir_path))
+  assert mappings
   handler_class = _GetHandlerClassForPath(mappings)
 
   try:
@@ -202,12 +199,12 @@
     http_thread.start()
     print 'Started http://%s:%d to host %s.' % (httpd.server_address[0],
                                                 httpd.server_address[1],
-                                                local_dir_path)
+                                                str(mappings))
     return httpd.server_address
   except socket.error as v:
     error_code = v[0]
     print 'Failed to start http server for %s on port %d: %s.' % (
-        local_dir_path, host_port, os.strerror(error_code))
+        str(mappings), host_port, os.strerror(error_code))
     if error_code == errno.EADDRINUSE:
       print ('  Run `fuser %d/tcp` to find out which process is using the port.'
              % host_port)
diff --git a/devtoolslib/linux_shell.py b/devtoolslib/linux_shell.py
index a8c25df..fff21a7 100644
--- a/devtoolslib/linux_shell.py
+++ b/devtoolslib/linux_shell.py
@@ -22,8 +22,7 @@
     self.executable_path = executable_path
     self.command_prefix = command_prefix if command_prefix else []
 
-  def ServeLocalDirectory(self, local_dir_path, port=0,
-                          additional_mappings=None):
+  def ServeLocalDirectory(self, local_dir_path, port=0):
     """Serves the content of the local (host) directory, making it available to
     the shell under the url returned by the function.
 
@@ -33,15 +32,31 @@
     Args:
       local_dir_path: path to the directory to be served
       port: port at which the server will be available to the shell
-      additional_mappings: List of tuples (prefix, local_base_path) mapping
-          URLs that start with |prefix| to local directory at |local_base_path|.
-          The prefixes should skip the leading slash.
 
     Returns:
       The url that the shell can use to access the content of |local_dir_path|.
     """
-    return 'http://%s:%d/' % http_server.start_http_server(local_dir_path, port,
-                                                           additional_mappings)
+    mappings = [('', local_dir_path)]
+    return 'http://%s:%d/' % http_server.start_http_server(mappings, port)
+
+  def ServeLocalDirectories(self, mappings, port=0):
+    """Serves the content of the local (host) directories, making it available
+    to the shell under the url returned by the function.
+
+    The server will run on a separate thread until the program terminates. The
+    call returns immediately.
+
+    Args:
+      mappings: List of tuples (prefix, local_base_path) mapping URLs that start
+          with |prefix| to local directory at |local_base_path|. The prefixes
+          should skip the leading slash. The first matching prefix will be used
+          each time.
+      port: port at which the server will be available to the shell
+
+    Returns:
+      The url that the shell can use to access the content of |local_dir_path|.
+    """
+    return 'http://%s:%d/' % http_server.start_http_server(mappings, port)
 
   def ForwardHostPortToShell(self, host_port):
     """Forwards a port on the host machine to the same port wherever the shell
diff --git a/devtoolslib/shell.py b/devtoolslib/shell.py
index 16f4669..798208d 100644
--- a/devtoolslib/shell.py
+++ b/devtoolslib/shell.py
@@ -6,8 +6,7 @@
 class Shell(object):
   """Represents an abstract Mojo shell."""
 
-  def ServeLocalDirectory(self, local_dir_path, port=0,
-                          additional_mappings=None):
+  def ServeLocalDirectory(self, local_dir_path, port=0):
     """Serves the content of the local (host) directory, making it available to
     the shell under the url returned by the function.
 
@@ -17,9 +16,25 @@
     Args:
       local_dir_path: path to the directory to be served
       port: port at which the server will be available to the shell
-      additional_mappings: List of tuples (prefix, local_base_path) mapping
-          URLs that start with |prefix| to local directory at |local_base_path|.
-          The prefixes should skip the leading slash.
+
+    Returns:
+      The url that the shell can use to access the content of |local_dir_path|.
+    """
+    raise NotImplementedError()
+
+  def ServeLocalDirectories(self, mappings, port=0):
+    """Serves the content of the local (host) directories, making it available
+    to the shell under the url returned by the function.
+
+    The server will run on a separate thread until the program terminates. The
+    call returns immediately.
+
+    Args:
+      mappings: List of tuples (prefix, local_base_path) mapping URLs that start
+          with |prefix| to local directory at |local_base_path|. The prefixes
+          should skip the leading slash. The first matching prefix will be used
+          each time.
+      port: port at which the server will be available to the shell
 
     Returns:
       The url that the shell can use to access the content of |local_dir_path|.