Index: gm/rebaseline_server/server.py |
diff --git a/gm/rebaseline_server/server.py b/gm/rebaseline_server/server.py |
index d88d3992d780a5a570f811433a9a169468a487fd..bf9b125e1f70082e1eef54260750021439b0dcef 100755 |
--- a/gm/rebaseline_server/server.py |
+++ b/gm/rebaseline_server/server.py |
@@ -28,20 +28,16 @@ import urlparse |
# 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_ACTUALS_REPO_URL = 'http://skia-autogen.googlecode.com/svn/gm-actual' |
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 @@ RELOAD_INTERVAL_UNTIL_READY = 10 |
_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 @@ class Server(object): |
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 @@ class Server(object): |
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 @@ class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
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 @@ class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
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 @@ class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
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 @@ class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
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', |