Fix devserver with handling custom labels and add preference to always use cached image.

Change-Id: I701cba5bb9ad91a2574e8b309e8fafda528d7bc5

BUG=7152 5924
TEST=Tested with archive_dir and label set using example from dale.  Also tested with factory options that are archive_build with dir and updater using default options.  Url's are correct in both places

Review URL: http://codereview.chromium.org/3533003
diff --git a/autoupdate.py b/autoupdate.py
index ddd0178..917e268 100644
--- a/autoupdate.py
+++ b/autoupdate.py
@@ -27,14 +27,21 @@
 
   def __init__(self, serve_only=None, test_image=False, urlbase=None,
                factory_config_path=None, client_prefix=None, forced_image=None,
-               *args, **kwargs):
+               use_cached=False, *args, **kwargs):
     super(Autoupdate, self).__init__(*args, **kwargs)
     self.serve_only = serve_only
     self.factory_config = factory_config_path
     self.use_test_image = test_image
-    self.static_urlbase = urlbase
+    if urlbase:
+      self.static_urlbase = urlbase
+    elif self.serve_only:
+      self.static_urlbase = 'http://%(host)s/static/archive'
+    else:
+      self.static_urlbase = 'http://%(host)s/static'
+
     self.client_prefix = client_prefix
     self.forced_image = forced_image
+    self.use_cached = use_cached
 
   def _GetSecondsSinceMidnight(self):
     """Returns the seconds since midnight as a decimal value."""
@@ -109,7 +116,7 @@
   def _IsImageNewerThanCached(self, image_path, cached_file_path):
     """Returns true if the image is newer than the cached image."""
     if os.path.exists(cached_file_path) and os.path.exists(image_path):
-      web.debug('Usable cached image found.')
+      web.debug('Usable cached image found at %s.' % cached_file_path)
       return os.path.getmtime(image_path) > os.path.getmtime(cached_file_path)
     elif not os.path.exists(cached_file_path) and not os.path.exists(image_path):
       raise Exception('Image does not exist and cached image missing')
@@ -119,7 +126,7 @@
         web.debug('No cached image found - image generation required.')
         return True
       else:
-        web.debug('Only cached image found to serve.')
+        web.debug('Cached image found to serve at %s.' % cached_file_path)
         return False
 
   def _GetSize(self, update_path):
@@ -440,6 +447,10 @@
     update_dom = minidom.parseString(data)
     root = update_dom.firstChild
 
+    # Parse host if not done yet.
+    if '%(host)' in self.static_urlbase:
+      self.static_urlbase = self.static_urlbase % {'host' : web.ctx.host}
+
     # Check the client prefix to make sure you can support this type of update.
     if (root.hasAttribute('updaterversion') and
         not root.getAttribute('updaterversion').startswith(self.client_prefix)):
@@ -472,31 +483,36 @@
       if label:
         static_image_dir = os.path.join(static_image_dir, label)
 
-      # Not for factory, find and serve the correct image given the options.
-      if self.forced_image:
-        has_built_image = self.GenerateUpdateImage(
-            self.forced_image, move_to_static_dir=True,
-            static_image_dir=static_image_dir)
-        # Now that we've generated it, clear out so that other pings of same
-        # devserver instance do not generate new images.
-        self.forced_image = None
-      elif self.serve_only:
-        has_built_image = self.GenerateImageFromZip(static_image_dir)
+      # Prefer cached image if it exists.
+      if self.use_cached and os.path.exists(os.path.join(static_image_dir,
+                                                         'update.gz')):
+        web.debug('Using cached image regardless of timestamps.')
+        has_built_image = True
       else:
-        has_built_image = self.GenerateLatestUpdateImage(board_id,
-                                                         client_version,
-                                                         static_image_dir)
+        if self.forced_image:
+          has_built_image = self.GenerateUpdateImage(
+              self.forced_image, move_to_static_dir=True,
+              static_image_dir=static_image_dir)
+          # Now that we've generated it, clear out so that other pings of same
+          # devserver instance do not generate new images.
+          self.forced_image = None
+        elif self.serve_only:
+          has_built_image = self.GenerateImageFromZip(static_image_dir)
+        else:
+          has_built_image = self.GenerateLatestUpdateImage(board_id,
+                                                           client_version,
+                                                           static_image_dir)
 
       if has_built_image:
         hash = self._GetHash(os.path.join(static_image_dir, 'update.gz'))
         sha256 = self._GetSHA256(os.path.join(static_image_dir, 'update.gz'))
         size = self._GetSize(os.path.join(static_image_dir, 'update.gz'))
-        if self.static_urlbase and label:
+        if label:
           url = '%s/%s/update.gz' % (self.static_urlbase, label)
-        elif self.serve_only:
-          url = 'http://%s/static/archive/update.gz' % hostname
         else:
-          url = 'http://%s/static/update.gz' % hostname
+          url = '%s/update.gz' % self.static_urlbase
+
+        web.debug('Responding to client to use url %s to get image.' % url)
         return self.GetUpdatePayload(hash, sha256, size, url)
       else:
         return self.GetNoUpdatePayload()
diff --git a/devserver.py b/devserver.py
index eecab04..e4516a8 100644
--- a/devserver.py
+++ b/devserver.py
@@ -93,6 +93,8 @@
   parser.add_option('-t', action='store_true', dest='test_image')
   parser.add_option('-u', '--urlbase', dest='urlbase',
                     help='base URL, other than devserver, for update images.')
+  parser.add_option('--use_cached', action="store_true", default=False,
+                    help='Prefer cached image regardless of timestamps.')
   parser.add_option('--validate_factory_config', action="store_true",
                     dest='validate_factory_config',
                     help='Validate factory config file, then exit.')
@@ -124,7 +126,8 @@
       test_image=options.test_image,
       factory_config_path=options.factory_config,
       client_prefix=options.client_prefix,
-      forced_image=options.image)
+      forced_image=options.image,
+      use_cached=options.use_cached)
 
   if options.factory_config:
      updater.ImportFactoryConfigFile(options.factory_config,