rebaseline_server: fix --editable mode

complete revert of https://skia.googlesource.com/skia/+/736be3527214ddbd3dd7e42a89a374c62d98f370

partial revert of https://skia.googlesource.com/skia/+/579942387bed9259b03419c593503022e1399931

and glue made necessary by the above.

(SkipBuildbotRuns)
BUG=skia:2319
NOTREECHECKS=True
NOTRY=True
R=senorblanco@google.com, senorblanco@chromium.org

Author: epoger@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@13893 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/rebaseline_server/server.py b/gm/rebaseline_server/server.py
index d88d399..bf9b125 100755
--- a/gm/rebaseline_server/server.py
+++ b/gm/rebaseline_server/server.py
@@ -28,20 +28,16 @@
 
 # Imports from within Skia
 #
-# We need to add the 'tools' directory for svn.py, and the 'gm' directory for
-# gm_json.py .
-# Make sure that these dirs are in the PYTHONPATH, but add them at the *end*
+# We need to add the 'tools' directory, so that we can import svn.py within
+# that directory.
+# Make sure that the 'tools' dir is in the PYTHONPATH, but add it at the *end*
 # so any dirs that are already in the PYTHONPATH will be preferred.
 PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
-GM_DIRECTORY = os.path.dirname(PARENT_DIRECTORY)
-TRUNK_DIRECTORY = os.path.dirname(GM_DIRECTORY)
+TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(PARENT_DIRECTORY))
 TOOLS_DIRECTORY = os.path.join(TRUNK_DIRECTORY, 'tools')
 if TOOLS_DIRECTORY not in sys.path:
   sys.path.append(TOOLS_DIRECTORY)
 import svn
-if GM_DIRECTORY not in sys.path:
-  sys.path.append(GM_DIRECTORY)
-import gm_json
 
 # Imports from local dir
 #
@@ -76,9 +72,8 @@
 DEFAULT_PORT = 8888
 
 # Directory within which the server will serve out static files.
-STATIC_CONTENTS_DIR = os.path.realpath(os.path.join(PARENT_DIRECTORY, 'static'))
-GENERATED_IMAGES_DIR = os.path.join(STATIC_CONTENTS_DIR, 'generated-images')
-GENERATED_JSON_DIR = os.path.join(STATIC_CONTENTS_DIR, 'generated-json')
+STATIC_CONTENTS_SUBDIR = 'static'  # within PARENT_DIR
+GENERATED_IMAGES_SUBDIR = 'generated-images'  # within STATIC_CONTENTS_SUBDIR
 
 # How often (in seconds) clients should reload while waiting for initial
 # results to load.
@@ -87,11 +82,6 @@
 _HTTP_HEADER_CONTENT_LENGTH = 'Content-Length'
 _HTTP_HEADER_CONTENT_TYPE = 'Content-Type'
 
-SUMMARY_TYPES = [
-    results_mod.KEY__HEADER__RESULTS_ALL,
-    results_mod.KEY__HEADER__RESULTS_FAILURES,
-]
-
 _SERVER = None   # This gets filled in by main()
 
 
@@ -177,25 +167,6 @@
     self._actuals_repo = _create_svn_checkout(
         dir_path=actuals_dir, repo_url=actuals_repo_url)
 
-    # Since we don't have any results ready yet, prepare a dummy results file
-    # telling any clients that we're still working on the results.
-    response_dict = {
-        results_mod.KEY__HEADER: {
-            results_mod.KEY__HEADER__SCHEMA_VERSION: (
-                results_mod.REBASELINE_SERVER_SCHEMA_VERSION_NUMBER),
-            results_mod.KEY__HEADER__IS_STILL_LOADING: True,
-            results_mod.KEY__HEADER__TIME_UPDATED: 0,
-            results_mod.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: (
-                RELOAD_INTERVAL_UNTIL_READY),
-        },
-    }
-    if not os.path.isdir(GENERATED_JSON_DIR):
-      os.makedirs(GENERATED_JSON_DIR)
-    for summary_type in SUMMARY_TYPES:
-      gm_json.WriteToFile(
-          response_dict,
-          os.path.join(GENERATED_JSON_DIR, '%s.json' % summary_type))
-
     # Reentrant lock that must be held whenever updating EITHER of:
     # 1. self._results
     # 2. the expected or actual results on local disk
@@ -265,20 +236,13 @@
             results_mod.DEFAULT_EXPECTATIONS_DIR)
         _run_command(['gclient', 'sync'], TRUNK_DIRECTORY)
 
-      new_results = results_mod.Results(
+      self._results = results_mod.Results(
           actuals_root=self._actuals_dir,
-          generated_images_root=GENERATED_IMAGES_DIR,
-          diff_base_url=os.path.relpath(
-              GENERATED_IMAGES_DIR, GENERATED_JSON_DIR))
-
-      if not os.path.isdir(GENERATED_JSON_DIR):
-        os.makedirs(GENERATED_JSON_DIR)
-      for summary_type in SUMMARY_TYPES:
-        gm_json.WriteToFile(
-            new_results.get_packaged_results_of_type(results_type=summary_type),
-            os.path.join(GENERATED_JSON_DIR, '%s.json' % summary_type))
-
-      self._results = new_results
+          generated_images_root=os.path.join(
+              PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR,
+              GENERATED_IMAGES_SUBDIR),
+          diff_base_url=posixpath.join(
+              os.pardir, STATIC_CONTENTS_SUBDIR, GENERATED_IMAGES_SUBDIR))
 
   def _result_loader(self, reload_seconds=0):
     """ Call self.update_results(), either once or periodically.
@@ -329,10 +293,10 @@
     try:
       logging.debug('do_GET: path="%s"' % self.path)
       if self.path == '' or self.path == '/' or self.path == '/index.html' :
-        self.redirect_to('/static/index.html')
+        self.redirect_to('/%s/index.html' % STATIC_CONTENTS_SUBDIR)
         return
       if self.path == '/favicon.ico' :
-        self.redirect_to('/static/favicon.ico')
+        self.redirect_to('/%s/favicon.ico' % STATIC_CONTENTS_SUBDIR)
         return
 
       # All requests must be of this form:
@@ -342,7 +306,8 @@
       normpath = posixpath.normpath(self.path)
       (dispatcher_name, remainder) = PATHSPLIT_RE.match(normpath).groups()
       dispatchers = {
-          'static': self.do_GET_static,
+          'results': self.do_GET_results,
+           STATIC_CONTENTS_SUBDIR: self.do_GET_static,
       }
       dispatcher = dispatchers[dispatcher_name]
       dispatcher(remainder)
@@ -350,25 +315,62 @@
       self.send_error(404)
       raise
 
+  def do_GET_results(self, results_type):
+    """ Handle a GET request for GM results.
+
+    Args:
+      results_type: string indicating which set of results to return;
+            must be one of the results_mod.RESULTS_* constants
+    """
+    logging.debug('do_GET_results: sending results of type "%s"' % results_type)
+    # Since we must make multiple calls to the Results object, grab a
+    # reference to it in case it is updated to point at a new Results
+    # object within another thread.
+    #
+    # TODO(epoger): Rather than using a global variable for the handler
+    # to refer to the Server object, make Server a subclass of
+    # HTTPServer, and then it could be available to the handler via
+    # the handler's .server instance variable.
+    results_obj = _SERVER.results
+    if results_obj:
+      response_dict = results_obj.get_packaged_results_of_type(
+          results_type=results_type, reload_seconds=_SERVER.reload_seconds,
+          is_editable=_SERVER.is_editable, is_exported=_SERVER.is_exported)
+    else:
+      now = int(time.time())
+      response_dict = {
+          results_mod.KEY__HEADER: {
+              results_mod.KEY__HEADER__SCHEMA_VERSION: (
+                  results_mod.REBASELINE_SERVER_SCHEMA_VERSION_NUMBER),
+              results_mod.KEY__HEADER__IS_STILL_LOADING: True,
+              results_mod.KEY__HEADER__TIME_UPDATED: now,
+              results_mod.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: (
+                  now + RELOAD_INTERVAL_UNTIL_READY),
+          },
+      }
+    self.send_json_dict(response_dict)
+
   def do_GET_static(self, path):
-    """ Handle a GET request for a file under the 'static' directory.
-    Only allow serving of files within the 'static' directory that is a
+    """ Handle a GET request for a file under STATIC_CONTENTS_SUBDIR .
+    Only allow serving of files within STATIC_CONTENTS_SUBDIR that is a
     filesystem sibling of this script.
 
     Args:
-      path: path to file (under static directory) to retrieve
+      path: path to file (within STATIC_CONTENTS_SUBDIR) to retrieve
     """
     # Strip arguments ('?resultsToLoad=all') from the path
     path = urlparse.urlparse(path).path
 
     logging.debug('do_GET_static: sending file "%s"' % path)
-    full_path = os.path.realpath(os.path.join(STATIC_CONTENTS_DIR, path))
-    if full_path.startswith(STATIC_CONTENTS_DIR):
+    static_dir = os.path.realpath(os.path.join(
+        PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR))
+    full_path = os.path.realpath(os.path.join(static_dir, path))
+    if full_path.startswith(static_dir):
       self.send_file(full_path)
     else:
       logging.error(
           'Attempted do_GET_static() of path [%s] outside of static dir [%s]'
-          % (full_path, STATIC_CONTENTS_DIR))
+          % (full_path, static_dir))
       self.send_error(404)
 
   def do_POST(self):
@@ -480,6 +482,18 @@
     else:
       self.send_error(404)
 
+  def send_json_dict(self, json_dict):
+    """ Send the contents of this dictionary in JSON format, with a JSON
+        mimetype.
+
+    Args:
+      json_dict: dictionary to send
+    """
+    self.send_response(200)
+    self.send_header('Content-type', 'application/json')
+    self.end_headers()
+    json.dump(json_dict, self.wfile)
+
 
 def main():
   logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',