OLD | NEW |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 | 2 |
epoger
2014/07/02 19:27:08
Reason for the change:
In https://codereview.chro
jcgregorio
2014/07/02 20:19:20
Can you move this up into the CL description?
On
epoger
2014/07/02 20:47:18
Done. (I originally put it here to make it easier
| |
3 """ | 3 """ |
4 Copyright 2013 Google Inc. | 4 Copyright 2013 Google Inc. |
5 | 5 |
6 Use of this source code is governed by a BSD-style license that can be | 6 Use of this source code is governed by a BSD-style license that can be |
7 found in the LICENSE file. | 7 found in the LICENSE file. |
8 | 8 |
9 HTTP server for our HTML rebaseline viewer. | 9 HTTP server for our HTML rebaseline viewer. |
10 """ | 10 """ |
11 | 11 |
12 # System-level imports | 12 # System-level imports |
13 import argparse | 13 import argparse |
14 import BaseHTTPServer | 14 import BaseHTTPServer |
15 import json | 15 import json |
16 import logging | 16 import logging |
17 import os | 17 import os |
18 import posixpath | 18 import posixpath |
19 import re | 19 import re |
20 import shutil | 20 import shutil |
21 import socket | 21 import socket |
22 import subprocess | 22 import subprocess |
23 import thread | 23 import thread |
24 import threading | 24 import threading |
25 import time | 25 import time |
26 import urlparse | 26 import urlparse |
27 | 27 |
28 # Must fix up PYTHONPATH before importing from within Skia | |
epoger
2014/07/02 19:27:08
Cleaned up this and various other pylint warnings/
| |
29 # pylint: disable=W0611 | |
30 import fix_pythonpath | |
31 # pylint: enable=W0611 | |
32 | |
28 # Imports from within Skia | 33 # Imports from within Skia |
29 import fix_pythonpath # must do this first | |
30 from pyutils import gs_utils | 34 from pyutils import gs_utils |
31 import gm_json | 35 import gm_json |
32 | 36 |
33 # Imports from local dir | 37 # Imports from local dir |
34 # | 38 # |
39 # pylint: disable=C0301 | |
35 # Note: we import results under a different name, to avoid confusion with the | 40 # Note: we import results under a different name, to avoid confusion with the |
36 # Server.results() property. See discussion at | 41 # Server.results() property. See discussion at |
37 # https://codereview.chromium.org/195943004/diff/1/gm/rebaseline_server/server.p y#newcode44 | 42 # https://codereview.chromium.org/195943004/diff/1/gm/rebaseline_server/server.p y#newcode44 |
43 # pylint: enable=C0301 | |
38 import compare_configs | 44 import compare_configs |
39 import compare_to_expectations | 45 import compare_to_expectations |
40 import download_actuals | 46 import download_actuals |
41 import imagepairset | 47 import imagepairset |
42 import results as results_mod | 48 import results as results_mod |
43 | 49 |
44 PATHSPLIT_RE = re.compile('/([^/]+)/(.+)') | 50 PATHSPLIT_RE = re.compile('/([^/]+)/(.+)') |
45 | 51 |
46 # A simple dictionary of file name extensions to MIME types. The empty string | 52 # A simple dictionary of file name extensions to MIME types. The empty string |
47 # entry is used as the default when no extension was given or if the extension | 53 # entry is used as the default when no extension was given or if the extension |
48 # has no entry in this dictionary. | 54 # has no entry in this dictionary. |
49 MIME_TYPE_MAP = {'': 'application/octet-stream', | 55 MIME_TYPE_MAP = {'': 'application/octet-stream', |
50 'html': 'text/html', | 56 'html': 'text/html', |
51 'css': 'text/css', | 57 'css': 'text/css', |
52 'png': 'image/png', | 58 'png': 'image/png', |
53 'js': 'application/javascript', | 59 'js': 'application/javascript', |
54 'json': 'application/json' | 60 'json': 'application/json' |
55 } | 61 } |
56 | 62 |
57 # Keys that server.py uses to create the toplevel content header. | 63 # Keys that server.py uses to create the toplevel content header. |
58 # NOTE: Keep these in sync with static/constants.js | 64 # NOTE: Keep these in sync with static/constants.js |
59 KEY__EDITS__MODIFICATIONS = 'modifications' | 65 KEY__EDITS__MODIFICATIONS = 'modifications' |
60 KEY__EDITS__OLD_RESULTS_HASH = 'oldResultsHash' | 66 KEY__EDITS__OLD_RESULTS_HASH = 'oldResultsHash' |
61 KEY__EDITS__OLD_RESULTS_TYPE = 'oldResultsType' | 67 KEY__EDITS__OLD_RESULTS_TYPE = 'oldResultsType' |
68 URL_KEY__SCHEMA_VERSION = 'urlSchemaVersion' | |
69 URL_VALUE__SCHEMA_VERSION__CURRENT = 0 | |
70 # always interpret as then-current schema version; | |
71 # used for toplevel links on index page | |
72 URL_VALUE__SCHEMA_VERSION__ALWAYS_CURRENT = 'current' | |
62 | 73 |
63 DEFAULT_ACTUALS_DIR = results_mod.DEFAULT_ACTUALS_DIR | 74 DEFAULT_ACTUALS_DIR = results_mod.DEFAULT_ACTUALS_DIR |
64 DEFAULT_GM_SUMMARIES_BUCKET = download_actuals.GM_SUMMARIES_BUCKET | 75 DEFAULT_GM_SUMMARIES_BUCKET = download_actuals.GM_SUMMARIES_BUCKET |
65 DEFAULT_JSON_FILENAME = download_actuals.DEFAULT_JSON_FILENAME | 76 DEFAULT_JSON_FILENAME = download_actuals.DEFAULT_JSON_FILENAME |
66 DEFAULT_PORT = 8888 | 77 DEFAULT_PORT = 8888 |
67 | 78 |
68 PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) | 79 PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) |
69 TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(PARENT_DIRECTORY)) | 80 TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(PARENT_DIRECTORY)) |
70 # Directory, relative to PARENT_DIRECTORY, within which the server will serve | 81 # Directory, relative to PARENT_DIRECTORY, within which the server will serve |
71 # out live results (not static files). | 82 # out live results (not static files). |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
151 with open(file_path, 'w') as file_handle: | 162 with open(file_path, 'w') as file_handle: |
152 file_handle.write( | 163 file_handle.write( |
153 '<!DOCTYPE html><html>' | 164 '<!DOCTYPE html><html>' |
154 '<head><title>rebaseline_server</title></head>' | 165 '<head><title>rebaseline_server</title></head>' |
155 '<body><ul>') | 166 '<body><ul>') |
156 if SUMMARY_TYPES: | 167 if SUMMARY_TYPES: |
157 file_handle.write('<li>Expectations vs Actuals</li><ul>') | 168 file_handle.write('<li>Expectations vs Actuals</li><ul>') |
158 for summary_type in SUMMARY_TYPES: | 169 for summary_type in SUMMARY_TYPES: |
159 file_handle.write( | 170 file_handle.write( |
160 '<li>' | 171 '<li>' |
161 '<a href="/%s/view.html#/view.html?resultsToLoad=/%s/%s">' | 172 '<a href="/%s/view.html#/view.html?%s=%s&resultsToLoad=/%s/%s">' |
jcgregorio
2014/07/02 20:19:20
What's the upper limit for number of % parameters
epoger
2014/07/02 20:47:18
I dunno. Do you like this better? I think it's b
jcgregorio
2014/07/02 20:48:54
Yes, I like that much better.
On 2014/07/02 20:47
| |
162 '%s</a></li>' % ( | 173 '%s</a></li>' % ( |
163 STATIC_CONTENTS_SUBDIR, RESULTS_SUBDIR, | 174 STATIC_CONTENTS_SUBDIR, |
164 summary_type, summary_type)) | 175 URL_KEY__SCHEMA_VERSION, |
176 URL_VALUE__SCHEMA_VERSION__ALWAYS_CURRENT, | |
177 RESULTS_SUBDIR, summary_type, | |
178 summary_type)) | |
165 file_handle.write('</ul>') | 179 file_handle.write('</ul>') |
166 if config_pairs: | 180 if config_pairs: |
167 file_handle.write('<li>Comparing configs within actual results</li><ul>') | 181 file_handle.write('<li>Comparing configs within actual results</li><ul>') |
168 for config_pair in config_pairs: | 182 for config_pair in config_pairs: |
169 file_handle.write('<li>%s vs %s:' % config_pair) | 183 file_handle.write('<li>%s vs %s:' % config_pair) |
170 for summary_type in SUMMARY_TYPES: | 184 for summary_type in SUMMARY_TYPES: |
171 file_handle.write( | 185 file_handle.write( |
172 ' <a href="/%s/view.html#/view.html?' | 186 ' <a href="/%s/view.html#/view.html?' |
173 'resultsToLoad=/%s/%s/%s-vs-%s_%s.json">%s</a>' % ( | 187 'resultsToLoad=/%s/%s/%s-vs-%s_%s.json">%s</a>' % ( |
174 STATIC_CONTENTS_SUBDIR, STATIC_CONTENTS_SUBDIR, | 188 STATIC_CONTENTS_SUBDIR, STATIC_CONTENTS_SUBDIR, |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
339 generated_images_root=os.path.join( | 353 generated_images_root=os.path.join( |
340 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, | 354 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, |
341 GENERATED_IMAGES_SUBDIR), | 355 GENERATED_IMAGES_SUBDIR), |
342 diff_base_url=posixpath.join( | 356 diff_base_url=posixpath.join( |
343 os.pardir, STATIC_CONTENTS_SUBDIR, GENERATED_IMAGES_SUBDIR), | 357 os.pardir, STATIC_CONTENTS_SUBDIR, GENERATED_IMAGES_SUBDIR), |
344 builder_regex_list=self._builder_regex_list) | 358 builder_regex_list=self._builder_regex_list) |
345 | 359 |
346 json_dir = os.path.join( | 360 json_dir = os.path.join( |
347 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_JSON_SUBDIR) | 361 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_JSON_SUBDIR) |
348 if not os.path.isdir(json_dir): | 362 if not os.path.isdir(json_dir): |
349 os.makedirs(json_dir) | 363 os.makedirs(json_dir) |
350 | 364 |
351 for config_pair in self._config_pairs: | 365 for config_pair in self._config_pairs: |
352 config_comparisons = compare_configs.ConfigComparisons( | 366 config_comparisons = compare_configs.ConfigComparisons( |
353 configs=config_pair, | 367 configs=config_pair, |
354 actuals_root=self._actuals_dir, | 368 actuals_root=self._actuals_dir, |
355 generated_images_root=os.path.join( | 369 generated_images_root=os.path.join( |
356 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, | 370 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, |
357 GENERATED_IMAGES_SUBDIR), | 371 GENERATED_IMAGES_SUBDIR), |
358 diff_base_url=posixpath.join( | 372 diff_base_url=posixpath.join( |
359 os.pardir, GENERATED_IMAGES_SUBDIR), | 373 os.pardir, GENERATED_IMAGES_SUBDIR), |
(...skipping 28 matching lines...) Expand all Loading... | |
388 if self._export: | 402 if self._export: |
389 server_address = ('', self._port) | 403 server_address = ('', self._port) |
390 host = _get_routable_ip_address() | 404 host = _get_routable_ip_address() |
391 if self._editable: | 405 if self._editable: |
392 logging.warning('Running with combination of "export" and "editable" ' | 406 logging.warning('Running with combination of "export" and "editable" ' |
393 'flags. Users on other machines will ' | 407 'flags. Users on other machines will ' |
394 'be able to modify your GM expectations!') | 408 'be able to modify your GM expectations!') |
395 else: | 409 else: |
396 host = '127.0.0.1' | 410 host = '127.0.0.1' |
397 server_address = (host, self._port) | 411 server_address = (host, self._port) |
412 # pylint: disable=W0201 | |
398 http_server = BaseHTTPServer.HTTPServer(server_address, HTTPRequestHandler) | 413 http_server = BaseHTTPServer.HTTPServer(server_address, HTTPRequestHandler) |
399 self._url = 'http://%s:%d' % (host, http_server.server_port) | 414 self._url = 'http://%s:%d' % (host, http_server.server_port) |
400 logging.info('Listening for requests on %s' % self._url) | 415 logging.info('Listening for requests on %s' % self._url) |
401 http_server.serve_forever() | 416 http_server.serve_forever() |
402 | 417 |
403 | 418 |
404 class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | 419 class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
405 """ HTTP request handlers for various types of queries this server knows | 420 """ HTTP request handlers for various types of queries this server knows |
406 how to handle (static HTML and Javascript, expected/actual results, etc.) | 421 how to handle (static HTML and Javascript, expected/actual results, etc.) |
407 """ | 422 """ |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
685 json_filename=args.json_filename, | 700 json_filename=args.json_filename, |
686 gm_summaries_bucket=args.gm_summaries_bucket, | 701 gm_summaries_bucket=args.gm_summaries_bucket, |
687 port=args.port, export=args.export, editable=args.editable, | 702 port=args.port, export=args.export, editable=args.editable, |
688 reload_seconds=args.reload, config_pairs=config_pairs, | 703 reload_seconds=args.reload, config_pairs=config_pairs, |
689 builder_regex_list=args.builders) | 704 builder_regex_list=args.builders) |
690 _SERVER.run() | 705 _SERVER.run() |
691 | 706 |
692 | 707 |
693 if __name__ == '__main__': | 708 if __name__ == '__main__': |
694 main() | 709 main() |
OLD | NEW |