rebaseline_server: add urlSchemaVersion parameter

In https://codereview.chromium.org/369473005 ('rebaseline_server: handle category filtering more generically'), I am changing the meaning of some URL parameters.  If a user pastes an old URL into an updated rebaseline_server instance, they may get unexpected results.  Adding a urlSchemaVersion parameter allows us to automatically convert the URL, or at least warn the user.

BUG=skia:2230
NOTRY=True
R=jcgregorio@google.com

Author: epoger@google.com

Review URL: https://codereview.chromium.org/368933002
diff --git a/gm/rebaseline_server/server.py b/gm/rebaseline_server/server.py
index 0079ec5..a10bc8c 100755
--- a/gm/rebaseline_server/server.py
+++ b/gm/rebaseline_server/server.py
@@ -25,16 +25,22 @@
 import time
 import urlparse
 
+# Must fix up PYTHONPATH before importing from within Skia
+# pylint: disable=W0611
+import fix_pythonpath
+# pylint: enable=W0611
+
 # Imports from within Skia
-import fix_pythonpath  # must do this first
 from pyutils import gs_utils
 import gm_json
 
 # Imports from local dir
 #
+# pylint: disable=C0301
 # Note: we import results under a different name, to avoid confusion with the
 # Server.results() property. See discussion at
 # https://codereview.chromium.org/195943004/diff/1/gm/rebaseline_server/server.py#newcode44
+# pylint: enable=C0301
 import compare_configs
 import compare_to_expectations
 import download_actuals
@@ -59,6 +65,11 @@
 KEY__EDITS__MODIFICATIONS = 'modifications'
 KEY__EDITS__OLD_RESULTS_HASH = 'oldResultsHash'
 KEY__EDITS__OLD_RESULTS_TYPE = 'oldResultsType'
+URL_KEY__SCHEMA_VERSION = 'urlSchemaVersion'
+URL_VALUE__SCHEMA_VERSION__CURRENT = 0
+# always interpret as then-current schema version;
+# used for toplevel links on index page
+URL_VALUE__SCHEMA_VERSION__ALWAYS_CURRENT = 'current'
 
 DEFAULT_ACTUALS_DIR = results_mod.DEFAULT_ACTUALS_DIR
 DEFAULT_GM_SUMMARIES_BUCKET = download_actuals.GM_SUMMARIES_BUCKET
@@ -157,11 +168,15 @@
       file_handle.write('<li>Expectations vs Actuals</li><ul>')
       for summary_type in SUMMARY_TYPES:
         file_handle.write(
-            '<li>'
-            '<a href="/%s/view.html#/view.html?resultsToLoad=/%s/%s">'
-            '%s</a></li>' % (
-                STATIC_CONTENTS_SUBDIR, RESULTS_SUBDIR,
-                summary_type, summary_type))
+            '<li><a href="/{static_subdir}/view.html#/view.html?'
+            '{version_key}={version_value}&'
+            'resultsToLoad=/{results_subdir}/{summary_type}">'
+            '{summary_type}</a></li>'.format(
+                results_subdir=RESULTS_SUBDIR,
+                static_subdir=STATIC_CONTENTS_SUBDIR,
+                summary_type=summary_type,
+                version_key=URL_KEY__SCHEMA_VERSION,
+                version_value=URL_VALUE__SCHEMA_VERSION__ALWAYS_CURRENT))
       file_handle.write('</ul>')
     if config_pairs:
       file_handle.write('<li>Comparing configs within actual results</li><ul>')
@@ -346,7 +361,7 @@
       json_dir = os.path.join(
           PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_JSON_SUBDIR)
       if not os.path.isdir(json_dir):
-         os.makedirs(json_dir)
+        os.makedirs(json_dir)
 
       for config_pair in self._config_pairs:
         config_comparisons = compare_configs.ConfigComparisons(
@@ -395,6 +410,7 @@
     else:
       host = '127.0.0.1'
       server_address = (host, self._port)
+    # pylint: disable=W0201
     http_server = BaseHTTPServer.HTTPServer(server_address, HTTPRequestHandler)
     self._url = 'http://%s:%d' % (host, http_server.server_port)
     logging.info('Listening for requests on %s' % self._url)
diff --git a/gm/rebaseline_server/static/constants.js b/gm/rebaseline_server/static/constants.js
index 7db245d..55751d1 100644
--- a/gm/rebaseline_server/static/constants.js
+++ b/gm/rebaseline_server/static/constants.js
@@ -73,6 +73,11 @@
     KEY__EDITS__MODIFICATIONS: 'modifications',
     KEY__EDITS__OLD_RESULTS_HASH: 'oldResultsHash',
     KEY__EDITS__OLD_RESULTS_TYPE: 'oldResultsType',
+    URL_KEY__SCHEMA_VERSION: 'urlSchemaVersion',
+    URL_VALUE__SCHEMA_VERSION__CURRENT: 0,
+    // always interpret as then-current schema version;
+    // used for toplevel links on index page
+    URL_VALUE__SCHEMA_VERSION__ALWAYS_CURRENT: 'current',
 
     // These are just used on the client side, no need to sync with server code.
     KEY__IMAGEPAIRS__ROWSPAN: 'rowspan',
diff --git a/gm/rebaseline_server/static/loader.js b/gm/rebaseline_server/static/loader.js
index 296689b..dbded05 100644
--- a/gm/rebaseline_server/static/loader.js
+++ b/gm/rebaseline_server/static/loader.js
@@ -426,6 +426,16 @@
     // any which are not found within the URL will keep their current value.
     $scope.queryParameters.load = function() {
       var nameValuePairs = $location.search();
+
+      var urlSchemaVersion = nameValuePairs[constants.URL_KEY__SCHEMA_VERSION];
+      if (!urlSchemaVersion) {
+        $scope.urlSchemaVersionLoaded = 0;
+      } else if (urlSchemaVersion == constants.URL_VALUE__SCHEMA_VERSION__ALWAYS_CURRENT) {
+        $scope.urlSchemaVersionLoaded = constants.URL_VALUE__SCHEMA_VERSION__CURRENT;
+      } else {
+        $scope.urlSchemaVersionLoaded = urlSchemaVersion;
+      }
+
       angular.forEach($scope.queryParameters.map,
                       function(copier, paramName) {
                         copier.load(nameValuePairs, paramName);
@@ -436,6 +446,7 @@
     // Saves all parameters from $scope into the URL query string.
     $scope.queryParameters.save = function() {
       var nameValuePairs = {};
+      nameValuePairs[constants.URL_KEY__SCHEMA_VERSION] = constants.URL_VALUE__SCHEMA_VERSION__CURRENT;
       angular.forEach($scope.queryParameters.map,
                       function(copier, paramName) {
                         copier.save(nameValuePairs, paramName);
diff --git a/gm/rebaseline_server/static/view.html b/gm/rebaseline_server/static/view.html
index fda767c..94dc9ba 100644
--- a/gm/rebaseline_server/static/view.html
+++ b/gm/rebaseline_server/static/view.html
@@ -26,6 +26,14 @@
   <div ng-show="extraColumnHeaders"><!-- everything: hide until data is loaded -->
 
     <div class="warning-div"
+         ng-show="urlSchemaVersionLoaded != constants.URL_VALUE__SCHEMA_VERSION__CURRENT">
+      WARNING!  The URL you loaded used schema version {{urlSchemaVersionLoaded}}, rather than
+      the most recent version {{constants.URL_VALUE__SCHEMA_VERSION__CURRENT}}.  It has been
+      converted to the most recent version on a best-effort basis; you may wish to double-check
+      which records are displayed.
+    </div>
+
+    <div class="warning-div"
          ng-show="header[constants.KEY__HEADER__IS_EDITABLE] && header[constants.KEY__HEADER__IS_EXPORTED]">
       WARNING!  These results are editable and exported, so any user
       who can connect to this server over the network can modify them.