Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
| 3 | 3 |
| 4 from __future__ import print_function | 4 from __future__ import print_function |
| 5 import argparse | 5 import argparse |
| 6 import BaseHTTPServer | 6 import BaseHTTPServer |
| 7 import json | 7 import json |
| 8 import os | 8 import os |
| 9 import os.path | 9 import os.path |
| 10 import re | 10 import re |
| 11 import subprocess | |
| 11 import sys | 12 import sys |
| 12 import tempfile | 13 import tempfile |
| 13 import urllib2 | 14 import urllib2 |
| 14 | 15 |
| 15 # Grab the script path because that is where all the static assets are | 16 # Grab the script path because that is where all the static assets are |
| 16 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) | 17 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| 17 | 18 |
| 18 # Find the tools directory for python imports | 19 # Find the tools directory for python imports |
| 19 TOOLS_DIR = os.path.dirname(SCRIPT_DIR) | 20 TOOLS_DIR = os.path.dirname(SCRIPT_DIR) |
| 20 | 21 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 92 | 93 |
| 93 | 94 |
| 94 def download_gm_image(image_name, image_path, hash_val): | 95 def download_gm_image(image_name, image_path, hash_val): |
| 95 """Download the gm result into the given path. | 96 """Download the gm result into the given path. |
| 96 | 97 |
| 97 @param image_name The GM file name, for example imageblur_gpu.png. | 98 @param image_name The GM file name, for example imageblur_gpu.png. |
| 98 @param image_path Path to place the image. | 99 @param image_path Path to place the image. |
| 99 @param hash_val The hash value of the image. | 100 @param hash_val The hash value of the image. |
| 100 """ | 101 """ |
| 101 | 102 |
| 102 # Seperate the test name from a image name | 103 # Separate the test name from a image name |
| 103 image_match = IMAGE_FILENAME_RE.match(image_name) | 104 image_match = IMAGE_FILENAME_RE.match(image_name) |
| 104 test_name = image_match.group(1) | 105 test_name = image_match.group(1) |
| 105 | 106 |
| 106 # Calculate the URL of the requested image | 107 # Calculate the URL of the requested image |
| 107 image_url = gm_json.CreateGmActualUrl( | 108 image_url = gm_json.CreateGmActualUrl( |
| 108 test_name, gm_json.JSONKEY_HASHTYPE_BITMAP_64BITMD5, hash_val) | 109 test_name, gm_json.JSONKEY_HASHTYPE_BITMAP_64BITMD5, hash_val) |
| 109 | 110 |
| 110 # Download the image as requested | 111 # Download the image as requested |
| 111 download_file(image_url, image_path) | 112 download_file(image_url, image_path) |
| 112 | 113 |
| 113 | 114 |
| 114 def download_changed_images(expectations_dir, expected_name, updated_name, | |
| 115 expected_image_dir, actual_image_dir): | |
| 116 | |
| 117 """Download the expected and actual GMs that changed into the given paths. | |
| 118 Determining what changed will be done by comparing each expected_name JSON | |
| 119 results file to its corresponding updated_name JSON results file if it | |
| 120 exists. | |
| 121 | |
| 122 @param expectations_dir The directory to traverse for results files. This | |
| 123 should resmble expectations/gm in the Skia trunk. | |
| 124 @param expected_name The name of the expected result files. These are | |
| 125 in the format of expected-results.json. | |
| 126 @param updated_name The name of the updated expected result files. | |
| 127 Normally this matches --expectations-filename-output for the | |
| 128 rebaseline.py tool. | |
| 129 @param expected_image_dir The directory to place downloaded expected images | |
| 130 into. | |
| 131 @param actual_image_dir The directory to place downloaded actual images | |
| 132 into. | |
| 133 """ | |
| 134 | |
| 135 differ = jsondiff.GMDiffer() | |
| 136 | |
| 137 # Look through expectations for hashes that changed | |
| 138 for root, dirs, files in os.walk(expectations_dir): | |
| 139 for expectation_file in files: | |
| 140 # There are many files in the expectations directory. We only care | |
| 141 # about expected results. | |
| 142 if expectation_file != expected_name: | |
| 143 continue | |
| 144 | |
| 145 # Get the name of the results file, and be sure there is an updated | |
| 146 # result to compare against. If there is not, there is no point in | |
| 147 # diffing this device. | |
| 148 expected_file_path = os.path.join(root, expected_name) | |
| 149 updated_file_path = os.path.join(root, updated_name) | |
| 150 if not os.path.isfile(updated_file_path): | |
| 151 continue | |
| 152 | |
| 153 # Find all expectations that did not match. | |
| 154 expected_diff = differ.GenerateDiffDict(expected_file_path, | |
| 155 updated_file_path) | |
| 156 | |
| 157 # The name of the device corresponds to the name of the folder we | |
| 158 # are in. | |
| 159 device_name = os.path.basename(root) | |
| 160 | |
| 161 # Create name prefixes to store the devices old and new GM results | |
| 162 expected_image_prefix = os.path.join(expected_image_dir, | |
| 163 device_name) + '-' | |
| 164 | |
| 165 actual_image_prefix = os.path.join(actual_image_dir, | |
| 166 device_name) + '-' | |
| 167 | |
| 168 # Download each image that had a differing result | |
| 169 for image_name, hashes in expected_diff.iteritems(): | |
| 170 print('Downloading', image_name, 'for device', device_name) | |
| 171 download_gm_image(image_name, | |
| 172 expected_image_prefix + image_name, | |
| 173 hashes['old']) | |
| 174 download_gm_image(image_name, | |
| 175 actual_image_prefix + image_name, | |
| 176 hashes['new']) | |
| 177 | |
| 178 | |
| 179 def get_image_set_from_skpdiff(skpdiff_records): | 115 def get_image_set_from_skpdiff(skpdiff_records): |
| 180 """Get the set of all images references in the given records. | 116 """Get the set of all images references in the given records. |
| 181 | 117 |
| 182 @param skpdiff_records An array of records, which are dictionary objects. | 118 @param skpdiff_records An array of records, which are dictionary objects. |
| 183 """ | 119 """ |
| 184 expected_set = frozenset([r['baselinePath'] for r in skpdiff_records]) | 120 expected_set = frozenset([r['baselinePath'] for r in skpdiff_records]) |
| 185 actual_set = frozenset([r['testPath'] for r in skpdiff_records]) | 121 actual_set = frozenset([r['testPath'] for r in skpdiff_records]) |
| 186 return expected_set | actual_set | 122 return expected_set | actual_set |
| 187 | 123 |
| 188 | 124 |
| 125 def set_expected_hash_in_json(expected_results_json, image_name, hash_value): | |
| 126 """Set the expected hash for the object extracted from | |
| 127 expected-results.json. Note that this only work with bitmap-64bitMD5 hash | |
| 128 types. | |
| 129 | |
| 130 @param expected_results_json The Python dictionary with the results to | |
| 131 modify. | |
| 132 @param image_name The name of the image to set the hash of. | |
| 133 @param hash_value The hash to set for the image. | |
| 134 """ | |
| 135 expected_results = expected_results_json[gm_json.JSONKEY_EXPECTEDRESULTS] | |
| 136 | |
| 137 if image_name in expected_results: | |
| 138 expected_results[image_name][gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGE STS][0][1] = hash_value | |
| 139 else: | |
| 140 expected_results[image_name] = { | |
| 141 gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS: | |
| 142 [ | |
| 143 [ | |
| 144 gm_json.JSONKEY_HASHTYPE_BITMAP_64BITMD5, | |
| 145 hash_value | |
| 146 ] | |
| 147 ] | |
| 148 } | |
| 149 | |
| 150 | |
| 151 def get_head_version(path): | |
| 152 """Get the version of the file at the given path stored inside the HEAD of | |
| 153 the git repository. It is returned as a string. | |
| 154 | |
| 155 @param path The path of the file whose HEAD is returned. It is assumed the | |
| 156 path is inside a git repo rooted at SKIA_ROOT_DIR. | |
| 157 """ | |
| 158 | |
| 159 # git-show will not work with absolute paths. This ensures we give it a path | |
| 160 # relative to the skia root. | |
| 161 git_path = os.path.relpath(path, SKIA_ROOT_DIR) | |
| 162 git_show_proc = subprocess.Popen(['git', 'show', 'HEAD:' + git_path], | |
| 163 stdout=subprocess.PIPE) | |
| 164 | |
| 165 # When invoked outside a shell, git will output the last committed version | |
| 166 # of the file directly to stdout. | |
| 167 git_version_content, _ = git_show_proc.communicate() | |
| 168 return git_version_content | |
| 169 | |
| 170 | |
| 171 class GMInstance: | |
|
epoger
2013/08/06 15:26:43
Information about a particular GM test result:
d
Zach Reizner
2013/08/07 13:56:02
Done.
| |
| 172 def __init__(self, | |
| 173 device_name, image_name, | |
| 174 expected_hash, actual_hash): | |
| 175 self.device_name = device_name | |
| 176 self.image_name = image_name | |
| 177 self.expected_hash = expected_hash | |
| 178 self.actual_hash = actual_hash | |
| 179 | |
| 180 | |
| 181 class ExpectationsManager: | |
| 182 def __init__(self, expectations_dir, expected_name, updated_name, | |
| 183 skpdiff_path): | |
| 184 """ | |
| 185 @param expectations_dir The directory to traverse for results files. | |
| 186 This should resmble expectations/gm in the Skia trunk. | |
| 187 @param expected_name The name of the expected result files. These | |
| 188 are in the format of expected-results.json. | |
| 189 @param updated_name The name of the updated expected result files. | |
| 190 Normally this matches --expectations-filename-output for the | |
| 191 rebaseline.py tool. | |
| 192 @param skpdiff_path The path used to execute the skpdiff command. | |
| 193 """ | |
| 194 self._expectations_dir = expectations_dir | |
| 195 self._expected_name = expected_name | |
| 196 self._updated_name = updated_name | |
| 197 self._skpdiff_path = skpdiff_path | |
| 198 self._generate_gm_comparison() | |
| 199 | |
| 200 def _generate_gm_comparison(self): | |
| 201 """Generate all the data needed to compare GMs: | |
| 202 - determine which GMs changed | |
| 203 - download the changed images | |
| 204 - compare them with skpdiff | |
| 205 """ | |
| 206 | |
| 207 # Get the expectations and compare them with actual hashes | |
| 208 self._get_expectations() | |
| 209 | |
| 210 | |
| 211 # Create a temporary file tree that makes sense for skpdiff to operate | |
| 212 # on. | |
| 213 image_output_dir = tempfile.mkdtemp('skpdiff') | |
| 214 expected_image_dir = os.path.join(image_output_dir, 'expected') | |
| 215 actual_image_dir = os.path.join(image_output_dir, 'actual') | |
| 216 os.mkdir(expected_image_dir) | |
| 217 os.mkdir(actual_image_dir) | |
| 218 | |
| 219 # Download expected and actual images that differed into the temporary | |
| 220 # file tree. | |
| 221 self._download_expectation_images(expected_image_dir, actual_image_dir) | |
| 222 | |
| 223 # Invoke skpdiff with our downloaded images and place its results in the | |
| 224 # temporary directory. | |
| 225 self.skpdiff_output_path = os.path.join(image_output_dir, | |
| 226 'skpdiff_output.json') | |
| 227 skpdiff_cmd = SKPDIFF_INVOKE_FORMAT.format(self._skpdiff_path, | |
| 228 self.skpdiff_output_path, | |
| 229 expected_image_dir, | |
| 230 actual_image_dir) | |
| 231 os.system(skpdiff_cmd) | |
| 232 | |
| 233 | |
| 234 def _get_expectations(self): | |
| 235 """Build an array of expectations that have changed with the actual | |
|
epoger
2013/08/06 15:26:43
Maybe this would be clearer?
Fill self._expectati
Zach Reizner
2013/08/07 13:56:02
Done.
| |
| 236 results. | |
| 237 """ | |
| 238 differ = jsondiff.GMDiffer() | |
| 239 self._expectations = [] | |
| 240 for root, dirs, files in os.walk(self._expectations_dir): | |
| 241 for expectation_file in files: | |
| 242 # There are many files in the expectations directory. We only | |
| 243 # care about expected results. | |
| 244 if expectation_file != self._expected_name: | |
| 245 continue | |
| 246 | |
| 247 # Get the name of the results file, and be sure there is an | |
| 248 # updated result to compare against. If there is not, there is | |
| 249 # no point in diffing this device. | |
| 250 expected_file_path = os.path.join(root, self._expected_name) | |
| 251 updated_file_path = os.path.join(root, self._updated_name) | |
| 252 if not os.path.isfile(updated_file_path): | |
| 253 continue | |
| 254 | |
| 255 # Always get the expected results from git because we may have | |
| 256 # changed them in a previous instance of the server. | |
| 257 expected_contents = get_head_version(expected_file_path) | |
| 258 updated_contents = None | |
| 259 with open(updated_file_path, 'rb') as updated_file: | |
| 260 updated_contents = updated_file.read() | |
| 261 | |
| 262 # Find all expectations that did not match. | |
| 263 expected_diff = differ.GenerateDiffDictFromStrings( | |
| 264 expected_contents, | |
| 265 updated_contents) | |
| 266 | |
| 267 # The name of the device corresponds to the name of the folder | |
| 268 # we are in. | |
| 269 device_name = os.path.basename(root) | |
| 270 | |
| 271 # Download each image that had a differing result. We take care | |
|
epoger
2013/08/06 15:26:43
Not downloading anymore. Instead, maybe...
Store
Zach Reizner
2013/08/07 13:56:02
Done.
| |
| 272 # to store metadata about each image so that we know about an | |
| 273 # image from its path on disk alone. That is all we will know | |
| 274 # after skpdiff outputs its results. | |
| 275 for image_name, hashes in expected_diff.iteritems(): | |
| 276 self._expectations.append( | |
| 277 GMInstance(device_name, image_name, | |
| 278 hashes['old'], hashes['new'])) | |
| 279 | |
| 280 | |
| 281 def _download_expectation_images(self, expected_image_dir, actual_image_dir) : | |
| 282 """Download the expected and actual iamges for the _expectations array. | |
|
epoger
2013/08/06 15:26:43
iamges -> images
Zach Reizner
2013/08/07 13:56:02
Done.
| |
| 283 | |
| 284 @param expected_image_dir The directory to download expected images | |
| 285 into. | |
| 286 @param actual_image_dir The directory to download actual images into. | |
| 287 """ | |
| 288 image_map = {} | |
| 289 | |
| 290 # Look through expectations and download their images. | |
| 291 for expectation in self._expectations: | |
| 292 # Build appropriate paths to download the images into. | |
| 293 expected_image_path = os.path.join(expected_image_dir, | |
| 294 expectation.device_name + '-' + | |
| 295 expectation.image_name) | |
| 296 | |
| 297 actual_image_path = os.path.join(actual_image_dir, | |
| 298 expectation.device_name + '-' + | |
| 299 expectation.image_name) | |
| 300 | |
| 301 print('Downloading', expectation.image_name, | |
|
epoger
2013/08/06 15:26:43
A Python partisan would suggest:
print 'Downloadi
| |
| 302 'for device', expectation.device_name) | |
| 303 | |
| 304 # Download images | |
| 305 download_gm_image(expectation.image_name, | |
| 306 expected_image_path, | |
| 307 expectation.expected_hash) | |
| 308 | |
| 309 download_gm_image(expectation.image_name, | |
| 310 actual_image_path, | |
| 311 expectation.actual_hash) | |
| 312 | |
| 313 # Annotate the expectations with where the images were downloaded | |
| 314 # to. | |
| 315 expectation.expected_image_path = expected_image_path | |
| 316 expectation.actual_image_path = actual_image_path | |
| 317 | |
| 318 # Map the image paths back to the expectations. | |
| 319 image_map[expected_image_path] = (False, expectation) | |
| 320 image_map[actual_image_path] = (True, expectation) | |
| 321 | |
| 322 self.image_map = image_map | |
| 323 | |
| 324 def _set_expected_hash(self, device_name, image_name, hash_value): | |
| 325 """Set the expected hash for the image of the given device. This always | |
| 326 writes directly to the expected results file of the given device | |
| 327 | |
| 328 @param device_name The name of the device to write the hash to. | |
| 329 @param image_name The name of the image whose hash to set. | |
| 330 @param hash_value The value of the hash to set. | |
| 331 """ | |
| 332 | |
| 333 # Retrieve the expected results file as it is in the working tree | |
| 334 json_path = os.path.join(self._expectations_dir, device_name, | |
| 335 self._expected_name) | |
| 336 expectations = gm_json.LoadFromFile(json_path) | |
| 337 | |
| 338 # Set the specified hash. | |
| 339 set_expected_hash_in_json(expectations, image_name, hash_value) | |
| 340 | |
| 341 # Write it out to disk using gm_json to keep the formatting consistent. | |
| 342 gm_json.WriteToFile(expectations, json_path) | |
| 343 | |
| 344 def use_hash_of(self, image_path): | |
| 345 """Determine the hash of the image at the path using the records, and | |
| 346 set it as the expected hash for its device and image config. | |
| 347 | |
| 348 @param image_path The path of the image as it was stored in the output | |
| 349 of skpdiff_path | |
| 350 """ | |
| 351 | |
| 352 # Get the metadata about the image at the path. | |
| 353 is_actual, expectation = self.image_map[image_path] | |
| 354 | |
| 355 expectation_hash = expectation.actual_hash if is_actual else\ | |
| 356 expectation.expected_hash | |
| 357 | |
| 358 # Write out that image's hash directly to the expected results file. | |
| 359 self._set_expected_hash(expectation.device_name, expectation.image_name, | |
| 360 expectation_hash) | |
| 361 | |
| 362 | |
| 189 class SkPDiffHandler(BaseHTTPServer.BaseHTTPRequestHandler): | 363 class SkPDiffHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
| 190 def send_file(self, file_path): | 364 def send_file(self, file_path): |
| 191 # Grab the extension if there is one | 365 # Grab the extension if there is one |
| 192 extension = os.path.splitext(file_path)[1] | 366 extension = os.path.splitext(file_path)[1] |
| 193 if len(extension) >= 1: | 367 if len(extension) >= 1: |
| 194 extension = extension[1:] | 368 extension = extension[1:] |
| 195 | 369 |
| 196 # Determine the MIME type of the file from its extension | 370 # Determine the MIME type of the file from its extension |
| 197 mime_type = MIME_TYPE_MAP.get(extension, MIME_TYPE_MAP['']) | 371 mime_type = MIME_TYPE_MAP.get(extension, MIME_TYPE_MAP['']) |
| 198 | 372 |
| 199 # Open the file and send it over HTTP | 373 # Open the file and send it over HTTP |
| 200 if os.path.isfile(file_path): | 374 if os.path.isfile(file_path): |
| 201 with open(file_path, 'rb') as sending_file: | 375 with open(file_path, 'rb') as sending_file: |
| 202 self.send_response(200) | 376 self.send_response(200) |
| 203 self.send_header('Content-type', mime_type) | 377 self.send_header('Content-type', mime_type) |
| 204 self.end_headers() | 378 self.end_headers() |
| 205 self.wfile.write(sending_file.read()) | 379 self.wfile.write(sending_file.read()) |
| 206 else: | 380 else: |
| 207 self.send_error(404) | 381 self.send_error(404) |
| 208 | 382 |
| 209 def serve_if_in_dir(self, dir_path, file_path): | 383 def serve_if_in_dir(self, dir_path, file_path): |
| 210 # Determine if the file exists relative to the given dir_path AND exists | 384 # Determine if the file exists relative to the given dir_path AND exists |
| 211 # under the dir_path. This is to prevent accidentally serving files | 385 # under the dir_path. This is to prevent accidentally serving files |
| 212 # outside the directory intended using symlinks, or '../'. | 386 # outside the directory intended using symlinks, or '../'. |
| 213 real_path = os.path.normpath(os.path.join(dir_path, file_path)) | 387 real_path = os.path.normpath(os.path.join(dir_path, file_path)) |
| 214 print(repr(real_path)) | |
| 215 if os.path.commonprefix([real_path, dir_path]) == dir_path: | 388 if os.path.commonprefix([real_path, dir_path]) == dir_path: |
| 216 if os.path.isfile(real_path): | 389 if os.path.isfile(real_path): |
| 217 self.send_file(real_path) | 390 self.send_file(real_path) |
| 218 return True | 391 return True |
| 219 return False | 392 return False |
| 220 | 393 |
| 221 def do_GET(self): | 394 def do_GET(self): |
| 222 # Simple rewrite rule of the root path to 'viewer.html' | 395 # Simple rewrite rule of the root path to 'viewer.html' |
| 223 if self.path == '' or self.path == '/': | 396 if self.path == '' or self.path == '/': |
| 224 self.path = '/viewer.html' | 397 self.path = '/viewer.html' |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 241 | 414 |
| 242 # WARNING: Serving any file the user wants is incredibly insecure. Its | 415 # WARNING: Serving any file the user wants is incredibly insecure. Its |
| 243 # redeeming quality is that we only serve gm files on a white list. | 416 # redeeming quality is that we only serve gm files on a white list. |
| 244 if self.path in self.server.image_set: | 417 if self.path in self.server.image_set: |
| 245 self.send_file(self.path) | 418 self.send_file(self.path) |
| 246 return | 419 return |
| 247 | 420 |
| 248 # If no file to send was found, just give the standard 404 | 421 # If no file to send was found, just give the standard 404 |
| 249 self.send_error(404) | 422 self.send_error(404) |
| 250 | 423 |
| 424 def do_POST(self): | |
| 425 if self.path == '/set_hash': | |
| 426 content_length = int(self.headers['Content-length']) | |
| 427 request_data = json.loads(self.rfile.read(content_length)) | |
| 428 self.server.expectations_manager.use_hash_of(request_data['path']) | |
| 429 self.send_response(200) | |
| 430 self.send_header('Content-type', 'application/json') | |
| 431 self.end_headers() | |
| 432 self.wfile.write('{"success":true}') | |
| 433 return | |
| 251 | 434 |
| 252 def run_server(skpdiff_output_path, port=8080): | 435 # If the we have no handler for this path, give em' the 404 |
| 436 self.send_error(404) | |
| 437 | |
| 438 | |
| 439 def run_server(expectations_manager, port=8080): | |
| 253 # Preload the skpdiff results file. This is so we can perform some | 440 # Preload the skpdiff results file. This is so we can perform some |
| 254 # processing on it. | 441 # processing on it. |
| 255 skpdiff_output_json = '' | 442 skpdiff_output_json = '' |
| 256 with open(skpdiff_output_path, 'rb') as records_file: | 443 with open(expectations_manager.skpdiff_output_path, 'rb') as records_file: |
| 257 skpdiff_output_json = records_file.read() | 444 skpdiff_output_json = records_file.read() |
| 258 | 445 |
| 259 # It's important to parse the results file so that we can make a set of | 446 # It's important to parse the results file so that we can make a set of |
| 260 # images that the web page might request. | 447 # images that the web page might request. |
| 261 skpdiff_records = json.loads(skpdiff_output_json)['records'] | 448 skpdiff_records = json.loads(skpdiff_output_json)['records'] |
| 262 image_set = get_image_set_from_skpdiff(skpdiff_records) | 449 image_set = get_image_set_from_skpdiff(skpdiff_records) |
| 263 | 450 |
| 264 # Add JSONP padding to the JSON because the web page expects it. It expects | 451 # Add JSONP padding to the JSON because the web page expects it. It expects |
| 265 # it because it was designed to run with or without a web server. Without a | 452 # it because it was designed to run with or without a web server. Without a |
| 266 # web server, the only way to load JSON is with JSONP. | 453 # web server, the only way to load JSON is with JSONP. |
| 267 skpdiff_output_json = 'var SkPDiffRecords = ' + skpdiff_output_json | 454 skpdiff_output_json = ('var SkPDiffRecords = ' + |
| 455 json.dumps({'records': skpdiff_records}) + ';') | |
| 268 | 456 |
| 269 # Do not bind to interfaces other than localhost because the server will | 457 # Do not bind to interfaces other than localhost because the server will |
| 270 # attempt to serve files relative to the root directory as a last resort | 458 # attempt to serve files relative to the root directory as a last resort |
| 271 # before 404ing. This means all of your files can be accessed from this | 459 # before 404ing. This means all of your files can be accessed from this |
| 272 # server, so DO NOT let this server listen to anything but localhost. | 460 # server, so DO NOT let this server listen to anything but localhost. |
| 273 server_address = ('127.0.0.1', port) | 461 server_address = ('127.0.0.1', port) |
| 274 http_server = BaseHTTPServer.HTTPServer(server_address, SkPDiffHandler) | 462 http_server = BaseHTTPServer.HTTPServer(server_address, SkPDiffHandler) |
| 275 http_server.image_set = image_set | 463 http_server.image_set = image_set |
| 276 http_server.skpdiff_output_json = skpdiff_output_json | 464 http_server.skpdiff_output_json = skpdiff_output_json |
| 277 print('Navigate thine browser to: http://{}:{}'.format(*server_address)) | 465 http_server.expectations_manager = expectations_manager |
| 466 print('Navigate thine browser to: http://{}:{}/'.format(*server_address)) | |
| 278 http_server.serve_forever() | 467 http_server.serve_forever() |
| 279 | 468 |
| 280 | 469 |
| 281 def main(): | 470 def main(): |
| 282 parser = argparse.ArgumentParser() | 471 parser = argparse.ArgumentParser() |
| 283 parser.add_argument('--port', '-p', metavar='PORT', | 472 parser.add_argument('--port', '-p', metavar='PORT', |
| 284 type=int, | 473 type=int, |
| 285 default=8080, | 474 default=8080, |
| 286 help='port to bind the server to; ' + | 475 help='port to bind the server to; ' + |
| 287 'defaults to %(default)s', | 476 'defaults to %(default)s', |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 313 'defaults to out/Release/skpdiff or out/Default/skpdiff' | 502 'defaults to out/Release/skpdiff or out/Default/skpdiff' |
| 314 ) | 503 ) |
| 315 | 504 |
| 316 args = vars(parser.parse_args()) # Convert args into a python dict | 505 args = vars(parser.parse_args()) # Convert args into a python dict |
| 317 | 506 |
| 318 # Make sure we have access to an skpdiff binary | 507 # Make sure we have access to an skpdiff binary |
| 319 skpdiff_path = get_skpdiff_path(args['skpdiff_path']) | 508 skpdiff_path = get_skpdiff_path(args['skpdiff_path']) |
| 320 if skpdiff_path is None: | 509 if skpdiff_path is None: |
| 321 sys.exit(1) | 510 sys.exit(1) |
| 322 | 511 |
| 323 # Create a temporary file tree that makes sense for skpdiff.to operate on | |
| 324 image_output_dir = tempfile.mkdtemp('skpdiff') | |
| 325 expected_image_dir = os.path.join(image_output_dir, 'expected') | |
| 326 actual_image_dir = os.path.join(image_output_dir, 'actual') | |
| 327 os.mkdir(expected_image_dir) | |
| 328 os.mkdir(actual_image_dir) | |
| 329 | |
| 330 # Print out the paths of things for easier debugging | 512 # Print out the paths of things for easier debugging |
| 331 print('script dir :', SCRIPT_DIR) | 513 print('script dir :', SCRIPT_DIR) |
| 332 print('tools dir :', TOOLS_DIR) | 514 print('tools dir :', TOOLS_DIR) |
| 333 print('root dir :', SKIA_ROOT_DIR) | 515 print('root dir :', SKIA_ROOT_DIR) |
| 334 print('expectations dir :', args['expectations_dir']) | 516 print('expectations dir :', args['expectations_dir']) |
| 335 print('skpdiff path :', skpdiff_path) | 517 print('skpdiff path :', skpdiff_path) |
| 336 print('tmp dir :', image_output_dir) | |
| 337 print('expected image dir :', expected_image_dir) | |
| 338 print('actual image dir :', actual_image_dir) | |
| 339 | 518 |
| 340 # Download expected and actual images that differed into the temporary file | 519 expectations_manager = ExpectationsManager(args['expectations_dir'], |
| 341 # tree. | 520 args['expected'], |
| 342 download_changed_images(args['expectations_dir'], | 521 args['updated'], |
| 343 args['expected'], args['updated'], | 522 skpdiff_path) |
| 344 expected_image_dir, actual_image_dir) | |
| 345 | 523 |
| 346 # Invoke skpdiff with our downloaded images and place its results in the | 524 run_server(expectations_manager, port=args['port']) |
| 347 # temporary directory. | |
| 348 skpdiff_output_path = os.path.join(image_output_dir, 'skpdiff_output.json') | |
| 349 skpdiff_cmd = SKPDIFF_INVOKE_FORMAT.format(skpdiff_path, | |
| 350 skpdiff_output_path, | |
| 351 expected_image_dir, | |
| 352 actual_image_dir) | |
| 353 os.system(skpdiff_cmd) | |
| 354 | |
| 355 run_server(skpdiff_output_path, port=args['port']) | |
| 356 | 525 |
| 357 if __name__ == '__main__': | 526 if __name__ == '__main__': |
| 358 main() | 527 main() |
| OLD | NEW |