| Index: gm/rebaseline_server/server.py
|
| diff --git a/gm/rebaseline_server/server.py b/gm/rebaseline_server/server.py
|
| index 50367f6f35eab16fc045b4d4433db01e6adb145b..6271f97dd2fa97dbd0da68456b24f5f1fd255e57 100755
|
| --- a/gm/rebaseline_server/server.py
|
| +++ b/gm/rebaseline_server/server.py
|
| @@ -40,6 +40,7 @@ import gm_json
|
| # https://codereview.chromium.org/195943004/diff/1/gm/rebaseline_server/server.py#newcode44
|
| # pylint: enable=C0301
|
| import compare_configs
|
| +import compare_rendered_pictures
|
| import compare_to_expectations
|
| import download_actuals
|
| import imagediffdb
|
| @@ -73,8 +74,11 @@ DEFAULT_PORT = 8888
|
| PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
|
| TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(PARENT_DIRECTORY))
|
| # Directory, relative to PARENT_DIRECTORY, within which the server will serve
|
| -# out live results (not static files).
|
| -RESULTS_SUBDIR = 'results'
|
| +# out image diff data from within the precomputed _SERVER.results .
|
| +PRECOMPUTED_RESULTS_SUBDIR = 'results'
|
| +# Directory, relative to PARENT_DIRECTORY, within which the server will serve
|
| +# out live-generated image diff data.
|
| +LIVE_RESULTS_SUBDIR = 'live-results'
|
| # Directory, relative to PARENT_DIRECTORY, within which the server will serve
|
| # out static files.
|
| STATIC_CONTENTS_SUBDIR = 'static'
|
| @@ -83,6 +87,10 @@ GENERATED_HTML_SUBDIR = 'generated-html'
|
| GENERATED_IMAGES_SUBDIR = 'generated-images'
|
| GENERATED_JSON_SUBDIR = 'generated-json'
|
|
|
| +# Parameters we use within do_GET_live_results()
|
| +LIVE_PARAM__SET_A_DIR = 'setADir'
|
| +LIVE_PARAM__SET_B_DIR = 'setBDir'
|
| +
|
| # How often (in seconds) clients should reload while waiting for initial
|
| # results to load.
|
| RELOAD_INTERVAL_UNTIL_READY = 10
|
| @@ -165,7 +173,7 @@ def _create_index(file_path, config_pairs):
|
| '<li><a href="/{static_subdir}/view.html#/view.html?'
|
| 'resultsToLoad=/{results_subdir}/{summary_type}">'
|
| '{summary_type}</a></li>'.format(
|
| - results_subdir=RESULTS_SUBDIR,
|
| + results_subdir=PRECOMPUTED_RESULTS_SUBDIR,
|
| static_subdir=STATIC_CONTENTS_SUBDIR,
|
| summary_type=summary_type))
|
| file_handle.write('</ul>')
|
| @@ -193,7 +201,9 @@ class Server(object):
|
| json_filename=DEFAULT_JSON_FILENAME,
|
| gm_summaries_bucket=DEFAULT_GM_SUMMARIES_BUCKET,
|
| port=DEFAULT_PORT, export=False, editable=True,
|
| - reload_seconds=0, config_pairs=None, builder_regex_list=None):
|
| + reload_seconds=0, config_pairs=None, builder_regex_list=None,
|
| + boto_file_path=None,
|
| + imagediffdb_threads=imagediffdb.DEFAULT_NUM_WORKER_THREADS):
|
| """
|
| Args:
|
| actuals_dir: directory under which we will check out the latest actual
|
| @@ -212,6 +222,10 @@ class Server(object):
|
| don't compare configs at all.
|
| builder_regex_list: List of regular expressions specifying which builders
|
| we will process. If None, process all builders.
|
| + boto_file_path: Path to .boto file giving us credentials to access
|
| + Google Storage buckets; if None, we will only be able to access
|
| + public GS buckets.
|
| + imagediffdb_threads: How many threads to spin up within imagediffdb.
|
| """
|
| self._actuals_dir = actuals_dir
|
| self._json_filename = json_filename
|
| @@ -222,7 +236,13 @@ class Server(object):
|
| self._reload_seconds = reload_seconds
|
| self._config_pairs = config_pairs or []
|
| self._builder_regex_list = builder_regex_list
|
| - self._gs = gs_utils.GSUtils()
|
| + self.truncate_results = False
|
| +
|
| + if boto_file_path:
|
| + self._gs = gs_utils.GSUtils(boto_file_path=boto_file_path)
|
| + else:
|
| + self._gs = gs_utils.GSUtils()
|
| +
|
| _create_index(
|
| file_path=os.path.join(
|
| PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_HTML_SUBDIR,
|
| @@ -234,9 +254,16 @@ class Server(object):
|
| # 2. the expected or actual results on local disk
|
| self.results_rlock = threading.RLock()
|
|
|
| - # These will be filled in by calls to update_results()
|
| + # Create a single ImageDiffDB instance that is used by all our differs.
|
| + self._image_diff_db = imagediffdb.ImageDiffDB(
|
| + gs=self._gs,
|
| + storage_root=os.path.join(
|
| + PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR,
|
| + GENERATED_IMAGES_SUBDIR),
|
| + num_worker_threads=imagediffdb_threads)
|
| +
|
| + # This will be filled in by calls to update_results()
|
| self._results = None
|
| - self._image_diff_db = None
|
|
|
| @property
|
| def results(self):
|
| @@ -245,6 +272,16 @@ class Server(object):
|
| return self._results
|
|
|
| @property
|
| + def image_diff_db(self):
|
| + """ Returns reference to our ImageDiffDB object."""
|
| + return self._image_diff_db
|
| +
|
| + @property
|
| + def gs(self):
|
| + """ Returns reference to our GSUtils object."""
|
| + return self._gs
|
| +
|
| + @property
|
| def is_exported(self):
|
| """ Returns true iff HTTP clients on other hosts are allowed to access
|
| this server. """
|
| @@ -343,12 +380,6 @@ class Server(object):
|
| compare_to_expectations.DEFAULT_EXPECTATIONS_DIR)
|
| _run_command(['gclient', 'sync'], TRUNK_DIRECTORY)
|
|
|
| - if not self._image_diff_db:
|
| - self._image_diff_db = imagediffdb.ImageDiffDB(
|
| - storage_root=os.path.join(
|
| - PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR,
|
| - GENERATED_IMAGES_SUBDIR))
|
| -
|
| self._results = compare_to_expectations.ExpectationComparisons(
|
| image_diff_db=self._image_diff_db,
|
| actuals_root=self._actuals_dir,
|
| @@ -443,7 +474,8 @@ class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
| normpath = posixpath.normpath(self.path)
|
| (dispatcher_name, remainder) = PATHSPLIT_RE.match(normpath).groups()
|
| dispatchers = {
|
| - RESULTS_SUBDIR: self.do_GET_results,
|
| + PRECOMPUTED_RESULTS_SUBDIR: self.do_GET_precomputed_results,
|
| + LIVE_RESULTS_SUBDIR: self.do_GET_live_results,
|
| STATIC_CONTENTS_SUBDIR: self.do_GET_static,
|
| }
|
| dispatcher = dispatchers[dispatcher_name]
|
| @@ -452,14 +484,15 @@ class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
| self.send_error(404)
|
| raise
|
|
|
| - def do_GET_results(self, results_type):
|
| - """ Handle a GET request for GM results.
|
| + def do_GET_precomputed_results(self, results_type):
|
| + """ Handle a GET request for part of the precomputed _SERVER.results object.
|
|
|
| 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)
|
| + logging.debug('do_GET_precomputed_results: sending results of type "%s"' %
|
| + results_type)
|
| # Since we must make multiple calls to the ExpectationComparisons object,
|
| # grab a reference to it in case it is updated to point at a new
|
| # ExpectationComparisons object within another thread.
|
| @@ -487,6 +520,23 @@ class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
| }
|
| self.send_json_dict(response_dict)
|
|
|
| + def do_GET_live_results(self, url_remainder):
|
| + """ Handle a GET request for live-generated image diff data.
|
| +
|
| + Args:
|
| + url_remainder: string indicating which image diffs to generate
|
| + """
|
| + logging.debug('do_GET_live_results: url_remainder="%s"' % url_remainder)
|
| + param_dict = urlparse.parse_qs(url_remainder)
|
| + results_obj = compare_rendered_pictures.RenderedPicturesComparisons(
|
| + setA_dirs=param_dict[LIVE_PARAM__SET_A_DIR],
|
| + setB_dirs=param_dict[LIVE_PARAM__SET_B_DIR],
|
| + image_diff_db=_SERVER.image_diff_db,
|
| + diff_base_url='/static/generated-images',
|
| + gs=_SERVER.gs, truncate_results=_SERVER.truncate_results)
|
| + self.send_json_dict(results_obj.get_packaged_results_of_type(
|
| + results_mod.KEY__HEADER__RESULTS_ALL))
|
| +
|
| def do_GET_static(self, path):
|
| """ Handle a GET request for a file under STATIC_CONTENTS_SUBDIR .
|
| Only allow serving of files within STATIC_CONTENTS_SUBDIR that is a
|
| @@ -643,6 +693,12 @@ def main():
|
| 'actual GM results. If this directory does not '
|
| 'exist, it will be created. Defaults to %(default)s'),
|
| default=DEFAULT_ACTUALS_DIR)
|
| + parser.add_argument('--boto',
|
| + help=('Path to .boto file giving us credentials to access '
|
| + 'Google Storage buckets. If not specified, we will '
|
| + 'only be able to access public GS buckets (and thus '
|
| + 'won\'t be able to download SKP images).'),
|
| + default='')
|
| # TODO(epoger): Before https://codereview.chromium.org/310093003 ,
|
| # when this tool downloaded the JSON summaries from skia-autogen,
|
| # it had an --actuals-revision the caller could specify to download
|
| @@ -688,6 +744,14 @@ def main():
|
| 'By default, we do not reload at all, and you '
|
| 'must restart the server to pick up new data.'),
|
| default=0)
|
| + parser.add_argument('--threads', type=int,
|
| + help=('How many parallel threads we use to download '
|
| + 'images and generate diffs; defaults to '
|
| + '%(default)s'),
|
| + default=imagediffdb.DEFAULT_NUM_WORKER_THREADS)
|
| + parser.add_argument('--truncate', action='store_true',
|
| + help=('FOR TESTING ONLY: truncate the set of images we '
|
| + 'process, to speed up testing.'))
|
| args = parser.parse_args()
|
| if args.compare_configs:
|
| config_pairs = CONFIG_PAIRS_TO_COMPARE
|
| @@ -700,7 +764,10 @@ def main():
|
| gm_summaries_bucket=args.gm_summaries_bucket,
|
| port=args.port, export=args.export, editable=args.editable,
|
| reload_seconds=args.reload, config_pairs=config_pairs,
|
| - builder_regex_list=args.builders)
|
| + builder_regex_list=args.builders, boto_file_path=args.boto,
|
| + imagediffdb_threads=args.threads)
|
| + if args.truncate:
|
| + _SERVER.truncate_results = True
|
| _SERVER.run()
|
|
|
|
|
|
|