| Index: third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/manifest/manifest.py
|
| diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/manifest/manifest.py b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/manifest/manifest.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1e7f349d2518717d5b4c5ba29b073b01eceaba75
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/manifest/manifest.py
|
| @@ -0,0 +1,228 @@
|
| +import json
|
| +import os
|
| +import re
|
| +from collections import defaultdict
|
| +from six import iteritems, itervalues, viewkeys
|
| +
|
| +from .item import ManualTest, WebdriverSpecTest, Stub, RefTestNode, RefTest, TestharnessTest, SupportFile, ConformanceCheckerTest, VisualTest
|
| +from .log import get_logger
|
| +from .utils import from_os_path, to_os_path, rel_path_to_url
|
| +
|
| +
|
| +CURRENT_VERSION = 4
|
| +
|
| +
|
| +class ManifestError(Exception):
|
| + pass
|
| +
|
| +
|
| +class ManifestVersionMismatch(ManifestError):
|
| + pass
|
| +
|
| +
|
| +def sourcefile_items(args):
|
| + tests_root, url_base, rel_path, status = args
|
| + source_file = SourceFile(tests_root,
|
| + rel_path,
|
| + url_base)
|
| + return rel_path, source_file.manifest_items()
|
| +
|
| +
|
| +class Manifest(object):
|
| + def __init__(self, url_base="/"):
|
| + assert url_base is not None
|
| + self._path_hash = {}
|
| + self._data = defaultdict(dict)
|
| + self._reftest_nodes_by_url = None
|
| + self.url_base = url_base
|
| +
|
| + def __iter__(self):
|
| + return self.itertypes()
|
| +
|
| + def itertypes(self, *types):
|
| + if not types:
|
| + types = sorted(self._data.keys())
|
| + for item_type in types:
|
| + for path, tests in sorted(iteritems(self._data[item_type])):
|
| + yield item_type, tests
|
| +
|
| + @property
|
| + def reftest_nodes_by_url(self):
|
| + if self._reftest_nodes_by_url is None:
|
| + by_url = {}
|
| + for path, nodes in iteritems(self._data.get("reftests", {})):
|
| + for node in nodes:
|
| + by_url[node.url] = node
|
| + self._reftest_nodes_by_url = by_url
|
| + return self._reftest_nodes_by_url
|
| +
|
| + def get_reference(self, url):
|
| + return self.reftest_nodes_by_url.get(url)
|
| +
|
| + def update(self, tree):
|
| + new_data = defaultdict(dict)
|
| + new_hashes = {}
|
| +
|
| + reftest_nodes = []
|
| + old_files = defaultdict(set, {k: set(viewkeys(v)) for k, v in iteritems(self._data)})
|
| +
|
| + changed = False
|
| + reftest_changes = False
|
| +
|
| + for source_file in tree:
|
| + rel_path = source_file.rel_path
|
| + file_hash = source_file.hash
|
| +
|
| + is_new = rel_path not in self._path_hash
|
| + hash_changed = False
|
| +
|
| + if not is_new:
|
| + old_hash, old_type = self._path_hash[rel_path]
|
| + old_files[old_type].remove(rel_path)
|
| + if old_hash != file_hash:
|
| + new_type, manifest_items = source_file.manifest_items()
|
| + hash_changed = True
|
| + else:
|
| + new_type, manifest_items = old_type, self._data[old_type][rel_path]
|
| + else:
|
| + new_type, manifest_items = source_file.manifest_items()
|
| +
|
| + if new_type in ("reftest", "reftest_node"):
|
| + reftest_nodes.extend(manifest_items)
|
| + if is_new or hash_changed:
|
| + reftest_changes = True
|
| + elif new_type:
|
| + new_data[new_type][rel_path] = set(manifest_items)
|
| +
|
| + new_hashes[rel_path] = (file_hash, new_type)
|
| +
|
| + if is_new or hash_changed:
|
| + changed = True
|
| +
|
| + if reftest_changes or old_files["reftest"] or old_files["reftest_node"]:
|
| + reftests, reftest_nodes, changed_hashes = self._compute_reftests(reftest_nodes)
|
| + new_data["reftest"] = reftests
|
| + new_data["reftest_node"] = reftest_nodes
|
| + new_hashes.update(changed_hashes)
|
| + else:
|
| + new_data["reftest"] = self._data["reftest"]
|
| + new_data["reftest_node"] = self._data["reftest_node"]
|
| +
|
| + if any(itervalues(old_files)):
|
| + changed = True
|
| +
|
| + self._data = new_data
|
| + self._path_hash = new_hashes
|
| +
|
| + return changed
|
| +
|
| + def _compute_reftests(self, reftest_nodes):
|
| + self._reftest_nodes_by_url = {}
|
| + has_inbound = set()
|
| + for item in reftest_nodes:
|
| + for ref_url, ref_type in item.references:
|
| + has_inbound.add(ref_url)
|
| +
|
| + reftests = defaultdict(set)
|
| + references = defaultdict(set)
|
| + changed_hashes = {}
|
| +
|
| + for item in reftest_nodes:
|
| + if item.url in has_inbound:
|
| + # This is a reference
|
| + if isinstance(item, RefTest):
|
| + item = item.to_RefTestNode()
|
| + changed_hashes[item.source_file.rel_path] = (item.source_file.hash,
|
| + item.item_type)
|
| + references[item.source_file.rel_path].add(item)
|
| + self._reftest_nodes_by_url[item.url] = item
|
| + else:
|
| + if isinstance(item, RefTestNode):
|
| + item = item.to_RefTest()
|
| + changed_hashes[item.source_file.rel_path] = (item.source_file.hash,
|
| + item.item_type)
|
| + reftests[item.source_file.rel_path].add(item)
|
| +
|
| + return reftests, references, changed_hashes
|
| +
|
| + def to_json(self):
|
| + out_items = {
|
| + test_type: {
|
| + from_os_path(path):
|
| + [t for t in sorted(test.to_json() for test in tests)]
|
| + for path, tests in iteritems(type_paths)
|
| + }
|
| + for test_type, type_paths in iteritems(self._data)
|
| + }
|
| + rv = {"url_base": self.url_base,
|
| + "paths": {from_os_path(k): v for k, v in iteritems(self._path_hash)},
|
| + "items": out_items,
|
| + "version": CURRENT_VERSION}
|
| + return rv
|
| +
|
| + @classmethod
|
| + def from_json(cls, tests_root, obj):
|
| + version = obj.get("version")
|
| + if version != CURRENT_VERSION:
|
| + raise ManifestVersionMismatch
|
| +
|
| + self = cls(url_base=obj.get("url_base", "/"))
|
| + if not hasattr(obj, "items") and hasattr(obj, "paths"):
|
| + raise ManifestError
|
| +
|
| + self._path_hash = {to_os_path(k): v for k, v in iteritems(obj["paths"])}
|
| +
|
| + item_classes = {"testharness": TestharnessTest,
|
| + "reftest": RefTest,
|
| + "reftest_node": RefTestNode,
|
| + "manual": ManualTest,
|
| + "stub": Stub,
|
| + "wdspec": WebdriverSpecTest,
|
| + "conformancechecker": ConformanceCheckerTest,
|
| + "visual": VisualTest,
|
| + "support": SupportFile}
|
| +
|
| + source_files = {}
|
| +
|
| + for test_type, type_paths in iteritems(obj["items"]):
|
| + if test_type not in item_classes:
|
| + raise ManifestError
|
| + test_cls = item_classes[test_type]
|
| + tests = defaultdict(set)
|
| + for path, manifest_tests in iteritems(type_paths):
|
| + path = to_os_path(path)
|
| + for test in manifest_tests:
|
| + manifest_item = test_cls.from_json(self,
|
| + tests_root,
|
| + path,
|
| + test,
|
| + source_files=source_files)
|
| + tests[path].add(manifest_item)
|
| + self._data[test_type] = tests
|
| +
|
| + return self
|
| +
|
| +
|
| +def load(tests_root, manifest):
|
| + logger = get_logger()
|
| +
|
| + # "manifest" is a path or file-like object.
|
| + if isinstance(manifest, basestring):
|
| + if os.path.exists(manifest):
|
| + logger.debug("Opening manifest at %s" % manifest)
|
| + else:
|
| + logger.debug("Creating new manifest at %s" % manifest)
|
| + try:
|
| + with open(manifest) as f:
|
| + rv = Manifest.from_json(tests_root, json.load(f))
|
| + except IOError:
|
| + return None
|
| + return rv
|
| +
|
| + return Manifest.from_json(tests_root, json.load(manifest))
|
| +
|
| +
|
| +def write(manifest, manifest_path):
|
| + with open(manifest_path, "wb") as f:
|
| + json.dump(manifest.to_json(), f, sort_keys=True, indent=1, separators=(',', ': '))
|
| + f.write("\n")
|
|
|