Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: gm/rebaseline_server/server.py

Issue 317783004: Revert "rebaseline_server: download actual-results.json files from GCS instead of SVN" (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gm/rebaseline_server/results.py ('k') | tools/pyutils/__init__.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
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 sys
23 import thread 24 import thread
24 import threading 25 import threading
25 import time 26 import time
26 import urlparse 27 import urlparse
27 28
28 # Imports from within Skia 29 # Imports from within Skia
29 import fix_pythonpath # must do this first 30 #
30 from pyutils import gs_utils 31 # We need to add the 'tools' directory for svn.py, and the 'gm' directory for
32 # gm_json.py .
33 # that directory.
34 # Make sure that the 'tools' dir is in the PYTHONPATH, but add it at the *end*
35 # so any dirs that are already in the PYTHONPATH will be preferred.
36 PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
37 GM_DIRECTORY = os.path.dirname(PARENT_DIRECTORY)
38 TRUNK_DIRECTORY = os.path.dirname(GM_DIRECTORY)
39 TOOLS_DIRECTORY = os.path.join(TRUNK_DIRECTORY, 'tools')
40 if TOOLS_DIRECTORY not in sys.path:
41 sys.path.append(TOOLS_DIRECTORY)
42 import svn
43 if GM_DIRECTORY not in sys.path:
44 sys.path.append(GM_DIRECTORY)
31 import gm_json 45 import gm_json
32 46
33 # Imports from local dir 47 # Imports from local dir
34 # 48 #
35 # Note: we import results under a different name, to avoid confusion with the 49 # Note: we import results under a different name, to avoid confusion with the
36 # Server.results() property. See discussion at 50 # Server.results() property. See discussion at
37 # https://codereview.chromium.org/195943004/diff/1/gm/rebaseline_server/server.p y#newcode44 51 # https://codereview.chromium.org/195943004/diff/1/gm/rebaseline_server/server.p y#newcode44
38 import compare_configs 52 import compare_configs
39 import compare_to_expectations 53 import compare_to_expectations
40 import download_actuals
41 import imagepairset 54 import imagepairset
42 import results as results_mod 55 import results as results_mod
43 56
44 PATHSPLIT_RE = re.compile('/([^/]+)/(.+)') 57 PATHSPLIT_RE = re.compile('/([^/]+)/(.+)')
45 58
46 # A simple dictionary of file name extensions to MIME types. The empty string 59 # 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 60 # entry is used as the default when no extension was given or if the extension
48 # has no entry in this dictionary. 61 # has no entry in this dictionary.
49 MIME_TYPE_MAP = {'': 'application/octet-stream', 62 MIME_TYPE_MAP = {'': 'application/octet-stream',
50 'html': 'text/html', 63 'html': 'text/html',
51 'css': 'text/css', 64 'css': 'text/css',
52 'png': 'image/png', 65 'png': 'image/png',
53 'js': 'application/javascript', 66 'js': 'application/javascript',
54 'json': 'application/json' 67 'json': 'application/json'
55 } 68 }
56 69
57 # Keys that server.py uses to create the toplevel content header. 70 # Keys that server.py uses to create the toplevel content header.
58 # NOTE: Keep these in sync with static/constants.js 71 # NOTE: Keep these in sync with static/constants.js
59 KEY__EDITS__MODIFICATIONS = 'modifications' 72 KEY__EDITS__MODIFICATIONS = 'modifications'
60 KEY__EDITS__OLD_RESULTS_HASH = 'oldResultsHash' 73 KEY__EDITS__OLD_RESULTS_HASH = 'oldResultsHash'
61 KEY__EDITS__OLD_RESULTS_TYPE = 'oldResultsType' 74 KEY__EDITS__OLD_RESULTS_TYPE = 'oldResultsType'
62 75
63 DEFAULT_ACTUALS_DIR = results_mod.DEFAULT_ACTUALS_DIR 76 DEFAULT_ACTUALS_DIR = results_mod.DEFAULT_ACTUALS_DIR
64 DEFAULT_GM_SUMMARIES_BUCKET = download_actuals.GM_SUMMARIES_BUCKET 77 DEFAULT_ACTUALS_REPO_REVISION = 'HEAD'
65 DEFAULT_JSON_FILENAME = download_actuals.DEFAULT_JSON_FILENAME 78 DEFAULT_ACTUALS_REPO_URL = 'http://skia-autogen.googlecode.com/svn/gm-actual'
66 DEFAULT_PORT = 8888 79 DEFAULT_PORT = 8888
67 80
68 PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
69 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).
72 RESULTS_SUBDIR = 'results' 83 RESULTS_SUBDIR = 'results'
73 # Directory, relative to PARENT_DIRECTORY, within which the server will serve 84 # Directory, relative to PARENT_DIRECTORY, within which the server will serve
74 # out static files. 85 # out static files.
75 STATIC_CONTENTS_SUBDIR = 'static' 86 STATIC_CONTENTS_SUBDIR = 'static'
76 # All of the GENERATED_*_SUBDIRS are relative to STATIC_CONTENTS_SUBDIR 87 # All of the GENERATED_*_SUBDIRS are relative to STATIC_CONTENTS_SUBDIR
77 GENERATED_HTML_SUBDIR = 'generated-html' 88 GENERATED_HTML_SUBDIR = 'generated-html'
78 GENERATED_IMAGES_SUBDIR = 'generated-images' 89 GENERATED_IMAGES_SUBDIR = 'generated-images'
79 GENERATED_JSON_SUBDIR = 'generated-json' 90 GENERATED_JSON_SUBDIR = 'generated-json'
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 """Returns routable IP address of this host (the IP address of its network 132 """Returns routable IP address of this host (the IP address of its network
122 interface that would be used for most traffic, not its localhost 133 interface that would be used for most traffic, not its localhost
123 interface). See http://stackoverflow.com/a/166589 """ 134 interface). See http://stackoverflow.com/a/166589 """
124 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 135 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
125 sock.connect(('8.8.8.8', 80)) 136 sock.connect(('8.8.8.8', 80))
126 host = sock.getsockname()[0] 137 host = sock.getsockname()[0]
127 sock.close() 138 sock.close()
128 return host 139 return host
129 140
130 141
142 def _create_svn_checkout(dir_path, repo_url):
143 """Creates local checkout of an SVN repository at the specified directory
144 path, returning an svn.Svn object referring to the local checkout.
145
146 Args:
147 dir_path: path to the local checkout; if this directory does not yet exist,
148 it will be created and the repo will be checked out into it
149 repo_url: URL of SVN repo to check out into dir_path (unless the local
150 checkout already exists)
151 Returns: an svn.Svn object referring to the local checkout.
152 """
153 local_checkout = svn.Svn(dir_path)
154 if not os.path.isdir(dir_path):
155 os.makedirs(dir_path)
156 local_checkout.Checkout(repo_url, '.')
157 return local_checkout
158
159
131 def _create_index(file_path, config_pairs): 160 def _create_index(file_path, config_pairs):
132 """Creates an index file linking to all results available from this server. 161 """Creates an index file linking to all results available from this server.
133 162
134 Prior to https://codereview.chromium.org/215503002 , we had a static 163 Prior to https://codereview.chromium.org/215503002 , we had a static
135 index.html within our repo. But now that the results may or may not include 164 index.html within our repo. But now that the results may or may not include
136 config comparisons, index.html needs to be generated differently depending 165 config comparisons, index.html needs to be generated differently depending
137 on which results are included. 166 on which results are included.
138 167
139 TODO(epoger): Instead of including raw HTML within the Python code, 168 TODO(epoger): Instead of including raw HTML within the Python code,
140 consider restoring the index.html file as a template and using django (or 169 consider restoring the index.html file as a template and using django (or
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 file_handle.write('</li>') 206 file_handle.write('</li>')
178 file_handle.write('</ul>') 207 file_handle.write('</ul>')
179 file_handle.write('</ul></body></html>') 208 file_handle.write('</ul></body></html>')
180 209
181 210
182 class Server(object): 211 class Server(object):
183 """ HTTP server for our HTML rebaseline viewer. """ 212 """ HTTP server for our HTML rebaseline viewer. """
184 213
185 def __init__(self, 214 def __init__(self,
186 actuals_dir=DEFAULT_ACTUALS_DIR, 215 actuals_dir=DEFAULT_ACTUALS_DIR,
187 json_filename=DEFAULT_JSON_FILENAME, 216 actuals_repo_revision=DEFAULT_ACTUALS_REPO_REVISION,
188 gm_summaries_bucket=DEFAULT_GM_SUMMARIES_BUCKET, 217 actuals_repo_url=DEFAULT_ACTUALS_REPO_URL,
189 port=DEFAULT_PORT, export=False, editable=True, 218 port=DEFAULT_PORT, export=False, editable=True,
190 reload_seconds=0, config_pairs=None, builder_regex_list=None): 219 reload_seconds=0, config_pairs=None, builder_regex_list=None):
191 """ 220 """
192 Args: 221 Args:
193 actuals_dir: directory under which we will check out the latest actual 222 actuals_dir: directory under which we will check out the latest actual
194 GM results 223 GM results
195 json_filename: basename of the JSON summary file to load for each builder 224 actuals_repo_revision: revision of actual-results.json files to process
196 gm_summaries_bucket: Google Storage bucket to download json_filename 225 actuals_repo_url: SVN repo to download actual-results.json files from;
197 files from; if None or '', don't fetch new actual-results files 226 if None or '', don't fetch new actual-results files at all,
198 at all, just compare to whatever files are already in actuals_dir 227 just compare to whatever files are already in actuals_dir
199 port: which TCP port to listen on for HTTP requests 228 port: which TCP port to listen on for HTTP requests
200 export: whether to allow HTTP clients on other hosts to access this server 229 export: whether to allow HTTP clients on other hosts to access this server
201 editable: whether HTTP clients are allowed to submit new baselines 230 editable: whether HTTP clients are allowed to submit new baselines
202 reload_seconds: polling interval with which to check for new results; 231 reload_seconds: polling interval with which to check for new results;
203 if 0, don't check for new results at all 232 if 0, don't check for new results at all
204 config_pairs: List of (string, string) tuples; for each tuple, compare 233 config_pairs: List of (string, string) tuples; for each tuple, compare
205 actual results of these two configs. If None or empty, 234 actual results of these two configs. If None or empty,
206 don't compare configs at all. 235 don't compare configs at all.
207 builder_regex_list: List of regular expressions specifying which builders 236 builder_regex_list: List of regular expressions specifying which builders
208 we will process. If None, process all builders. 237 we will process. If None, process all builders.
209 """ 238 """
210 self._actuals_dir = actuals_dir 239 self._actuals_dir = actuals_dir
211 self._json_filename = json_filename 240 self._actuals_repo_revision = actuals_repo_revision
212 self._gm_summaries_bucket = gm_summaries_bucket 241 self._actuals_repo_url = actuals_repo_url
213 self._port = port 242 self._port = port
214 self._export = export 243 self._export = export
215 self._editable = editable 244 self._editable = editable
216 self._reload_seconds = reload_seconds 245 self._reload_seconds = reload_seconds
217 self._config_pairs = config_pairs or [] 246 self._config_pairs = config_pairs or []
218 self._builder_regex_list = builder_regex_list 247 self._builder_regex_list = builder_regex_list
219 _create_index( 248 _create_index(
220 file_path=os.path.join( 249 file_path=os.path.join(
221 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_HTML_SUBDIR, 250 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_HTML_SUBDIR,
222 "index.html"), 251 "index.html"),
223 config_pairs=config_pairs) 252 config_pairs=config_pairs)
253 # TODO(epoger): Create shareable functions within download_actuals.py that
254 # we can use both there and here to download the actual image results.
255 if actuals_repo_url:
256 self._actuals_repo = _create_svn_checkout(
257 dir_path=actuals_dir, repo_url=actuals_repo_url)
224 258
225 # Reentrant lock that must be held whenever updating EITHER of: 259 # Reentrant lock that must be held whenever updating EITHER of:
226 # 1. self._results 260 # 1. self._results
227 # 2. the expected or actual results on local disk 261 # 2. the expected or actual results on local disk
228 self.results_rlock = threading.RLock() 262 self.results_rlock = threading.RLock()
229 # self._results will be filled in by calls to update_results() 263 # self._results will be filled in by calls to update_results()
230 self._results = None 264 self._results = None
231 265
232 @property 266 @property
233 def results(self): 267 def results(self):
(...skipping 27 matching lines...) Expand all
261 the same time. 295 the same time.
262 296
263 Args: 297 Args:
264 invalidate: if True, invalidate self._results immediately upon entry; 298 invalidate: if True, invalidate self._results immediately upon entry;
265 otherwise, we will let readers see those results until we 299 otherwise, we will let readers see those results until we
266 replace them 300 replace them
267 """ 301 """
268 with self.results_rlock: 302 with self.results_rlock:
269 if invalidate: 303 if invalidate:
270 self._results = None 304 self._results = None
271 if self._gm_summaries_bucket: 305 if self._actuals_repo_url:
272 logging.info( 306 logging.info(
273 'Updating GM result summaries in %s from gm_summaries_bucket %s ...' 307 'Updating actual GM results in %s to revision %s from repo %s ...'
274 % (self._actuals_dir, self._gm_summaries_bucket)) 308 % (
275 309 self._actuals_dir, self._actuals_repo_revision,
276 # Clean out actuals_dir first, in case some builders have gone away 310 self._actuals_repo_url))
277 # since we last ran. 311 self._actuals_repo.Update(
278 if os.path.isdir(self._actuals_dir): 312 path='.', revision=self._actuals_repo_revision)
279 shutil.rmtree(self._actuals_dir)
280
281 # Get the list of builders we care about.
282 all_builders = download_actuals.get_builders_list(
283 summaries_bucket=self._gm_summaries_bucket)
284 if self._builder_regex_list:
285 matching_builders = []
286 for builder in all_builders:
287 for regex in self._builder_regex_list:
288 if re.match(regex, builder):
289 matching_builders.append(builder)
290 break # go on to the next builder, no need to try more regexes
291 else:
292 matching_builders = all_builders
293
294 # Download the JSON file for each builder we care about.
295 #
296 # TODO(epoger): When this is a large number of builders, we would be
297 # better off downloading them in parallel!
298 for builder in matching_builders:
299 gs_utils.download_file(
300 source_bucket=self._gm_summaries_bucket,
301 source_path=posixpath.join(builder, self._json_filename),
302 dest_path=os.path.join(self._actuals_dir, builder,
303 self._json_filename),
304 create_subdirs_if_needed=True)
305 313
306 # We only update the expectations dir if the server was run with a 314 # We only update the expectations dir if the server was run with a
307 # nonzero --reload argument; otherwise, we expect the user to maintain 315 # nonzero --reload argument; otherwise, we expect the user to maintain
308 # her own expectations as she sees fit. 316 # her own expectations as she sees fit.
309 # 317 #
310 # Because the Skia repo is hosted using git, and git does not 318 # Because the Skia repo is moving from SVN to git, and git does not
311 # support updating a single directory tree, we have to update the entire 319 # support updating a single directory tree, we have to update the entire
312 # repo checkout. 320 # repo checkout.
313 # 321 #
314 # Because Skia uses depot_tools, we have to update using "gclient sync" 322 # Because Skia uses depot_tools, we have to update using "gclient sync"
315 # instead of raw git commands. 323 # instead of raw git (or SVN) update. Happily, this will work whether
316 # 324 # the checkout was created using git or SVN.
317 # TODO(epoger): Fetch latest expectations in some other way.
318 # Eric points out that our official documentation recommends an
319 # unmanaged Skia checkout, so "gclient sync" will not bring down updated
320 # expectations from origin/master-- you'd have to do a "git pull" of
321 # some sort instead.
322 # However, the live rebaseline_server at
323 # http://skia-tree-status.appspot.com/redirect/rebaseline-server (which
324 # is probably the only user of the --reload flag!) uses a managed
325 # checkout, so "gclient sync" works in that case.
326 # Probably the best idea is to avoid all of this nonsense by fetching
327 # updated expectations into a temp directory, and leaving the rest of
328 # the checkout alone. This could be done using "git show", or by
329 # downloading individual expectation JSON files from
330 # skia.googlesource.com .
331 if self._reload_seconds: 325 if self._reload_seconds:
332 logging.info( 326 logging.info(
333 'Updating expected GM results in %s by syncing Skia repo ...' % 327 'Updating expected GM results in %s by syncing Skia repo ...' %
334 compare_to_expectations.DEFAULT_EXPECTATIONS_DIR) 328 compare_to_expectations.DEFAULT_EXPECTATIONS_DIR)
335 _run_command(['gclient', 'sync'], TRUNK_DIRECTORY) 329 _run_command(['gclient', 'sync'], TRUNK_DIRECTORY)
336 330
337 self._results = compare_to_expectations.ExpectationComparisons( 331 self._results = compare_to_expectations.ExpectationComparisons(
338 actuals_root=self._actuals_dir, 332 actuals_root=self._actuals_dir,
339 generated_images_root=os.path.join( 333 generated_images_root=os.path.join(
340 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, 334 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR,
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 def main(): 616 def main():
623 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', 617 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
624 datefmt='%m/%d/%Y %H:%M:%S', 618 datefmt='%m/%d/%Y %H:%M:%S',
625 level=logging.INFO) 619 level=logging.INFO)
626 parser = argparse.ArgumentParser() 620 parser = argparse.ArgumentParser()
627 parser.add_argument('--actuals-dir', 621 parser.add_argument('--actuals-dir',
628 help=('Directory into which we will check out the latest ' 622 help=('Directory into which we will check out the latest '
629 'actual GM results. If this directory does not ' 623 'actual GM results. If this directory does not '
630 'exist, it will be created. Defaults to %(default)s'), 624 'exist, it will be created. Defaults to %(default)s'),
631 default=DEFAULT_ACTUALS_DIR) 625 default=DEFAULT_ACTUALS_DIR)
632 # TODO(epoger): Before https://codereview.chromium.org/310093003 , 626 parser.add_argument('--actuals-repo',
633 # when this tool downloaded the JSON summaries from skia-autogen, 627 help=('URL of SVN repo to download actual-results.json '
634 # it had an --actuals-revision the caller could specify to download 628 'files from. Defaults to %(default)s ; if set to '
635 # actual results as of a specific point in time. We should add similar 629 'empty string, just compare to actual-results '
636 # functionality when retrieving the summaries from Google Storage. 630 'already found in ACTUALS_DIR.'),
631 default=DEFAULT_ACTUALS_REPO_URL)
632 parser.add_argument('--actuals-revision',
633 help=('revision of actual-results.json files to process. '
634 'Defaults to %(default)s . Beware of setting this '
635 'argument in conjunction with --editable; you '
636 'probably only want to edit results at HEAD.'),
637 default=DEFAULT_ACTUALS_REPO_REVISION)
637 parser.add_argument('--builders', metavar='BUILDER_REGEX', nargs='+', 638 parser.add_argument('--builders', metavar='BUILDER_REGEX', nargs='+',
638 help=('Only process builders matching these regular ' 639 help=('Only process builders matching these regular '
639 'expressions. If unspecified, process all ' 640 'expressions. If unspecified, process all '
640 'builders.')) 641 'builders.'))
641 parser.add_argument('--compare-configs', action='store_true', 642 parser.add_argument('--compare-configs', action='store_true',
642 help=('In addition to generating differences between ' 643 help=('In addition to generating differences between '
643 'expectations and actuals, also generate ' 644 'expectations and actuals, also generate '
644 'differences between these config pairs: ' 645 'differences between these config pairs: '
645 + str(CONFIG_PAIRS_TO_COMPARE))) 646 + str(CONFIG_PAIRS_TO_COMPARE)))
646 parser.add_argument('--editable', action='store_true', 647 parser.add_argument('--editable', action='store_true',
647 help=('Allow HTTP clients to submit new baselines.')) 648 help=('Allow HTTP clients to submit new baselines.'))
648 parser.add_argument('--export', action='store_true', 649 parser.add_argument('--export', action='store_true',
649 help=('Instead of only allowing access from HTTP clients ' 650 help=('Instead of only allowing access from HTTP clients '
650 'on localhost, allow HTTP clients on other hosts ' 651 'on localhost, allow HTTP clients on other hosts '
651 'to access this server. WARNING: doing so will ' 652 'to access this server. WARNING: doing so will '
652 'allow users on other hosts to modify your ' 653 'allow users on other hosts to modify your '
653 'GM expectations, if combined with --editable.')) 654 'GM expectations, if combined with --editable.'))
654 parser.add_argument('--gm-summaries-bucket',
655 help=('Google Cloud Storage bucket to download '
656 'JSON_FILENAME files from. '
657 'Defaults to %(default)s ; if set to '
658 'empty string, just compare to actual-results '
659 'already found in ACTUALS_DIR.'),
660 default=DEFAULT_GM_SUMMARIES_BUCKET)
661 parser.add_argument('--json-filename',
662 help=('JSON summary filename to read for each builder; '
663 'defaults to %(default)s.'),
664 default=DEFAULT_JSON_FILENAME)
665 parser.add_argument('--port', type=int, 655 parser.add_argument('--port', type=int,
666 help=('Which TCP port to listen on for HTTP requests; ' 656 help=('Which TCP port to listen on for HTTP requests; '
667 'defaults to %(default)s'), 657 'defaults to %(default)s'),
668 default=DEFAULT_PORT) 658 default=DEFAULT_PORT)
669 parser.add_argument('--reload', type=int, 659 parser.add_argument('--reload', type=int,
670 help=('How often (a period in seconds) to update the ' 660 help=('How often (a period in seconds) to update the '
671 'results. If specified, both expected and actual ' 661 'results. If specified, both expected and actual '
672 'results will be updated by running "gclient sync" ' 662 'results will be updated by running "gclient sync" '
673 'on your Skia checkout as a whole. ' 663 'on your Skia checkout as a whole. '
674 'By default, we do not reload at all, and you ' 664 'By default, we do not reload at all, and you '
675 'must restart the server to pick up new data.'), 665 'must restart the server to pick up new data.'),
676 default=0) 666 default=0)
677 args = parser.parse_args() 667 args = parser.parse_args()
678 if args.compare_configs: 668 if args.compare_configs:
679 config_pairs = CONFIG_PAIRS_TO_COMPARE 669 config_pairs = CONFIG_PAIRS_TO_COMPARE
680 else: 670 else:
681 config_pairs = None 671 config_pairs = None
682 672
683 global _SERVER 673 global _SERVER
684 _SERVER = Server(actuals_dir=args.actuals_dir, 674 _SERVER = Server(actuals_dir=args.actuals_dir,
685 json_filename=args.json_filename, 675 actuals_repo_revision=args.actuals_revision,
686 gm_summaries_bucket=args.gm_summaries_bucket, 676 actuals_repo_url=args.actuals_repo,
687 port=args.port, export=args.export, editable=args.editable, 677 port=args.port, export=args.export, editable=args.editable,
688 reload_seconds=args.reload, config_pairs=config_pairs, 678 reload_seconds=args.reload, config_pairs=config_pairs,
689 builder_regex_list=args.builders) 679 builder_regex_list=args.builders)
690 _SERVER.run() 680 _SERVER.run()
691 681
692 682
693 if __name__ == '__main__': 683 if __name__ == '__main__':
694 main() 684 main()
OLDNEW
« no previous file with comments | « gm/rebaseline_server/results.py ('k') | tools/pyutils/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698