1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
"""Manifest structure used to store paths that should be included in a test run.
The manifest is represented by a tree of IncludeManifest objects, the root
representing the file and each subnode representing a subdirectory that should
be included or excluded.
"""
import glob
import os
import urlparse
from wptmanifest.node import DataNode
from wptmanifest.backends import conditional
from wptmanifest.backends.conditional import ManifestItem
class IncludeManifest(ManifestItem):
def __init__(self, node):
"""Node in a tree structure representing the paths
that should be included or excluded from the test run.
:param node: AST Node corresponding to this Node.
"""
ManifestItem.__init__(self, node)
self.child_map = {}
@classmethod
def create(cls):
"""Create an empty IncludeManifest tree"""
node = DataNode(None)
return cls(node)
def append(self, child):
ManifestItem.append(self, child)
self.child_map[child.name] = child
assert len(self.child_map) == len(self.children)
def include(self, test):
"""Return a boolean indicating whether a particular test should be
included in a test run, based on the IncludeManifest tree rooted on
this object.
:param test: The test object"""
path_components = self._get_components(test.url)
return self._include(test, path_components)
def _include(self, test, path_components):
if path_components:
next_path_part = path_components.pop()
if next_path_part in self.child_map:
return self.child_map[next_path_part]._include(test, path_components)
node = self
while node:
try:
skip_value = self.get("skip", {"test_type": test.item_type}).lower()
assert skip_value in ("true", "false")
return skip_value != "true"
except KeyError:
if node.parent is not None:
node = node.parent
else:
# Include by default
return True
def _get_components(self, url):
rv = []
url_parts = urlparse.urlsplit(url)
variant = ""
if url_parts.query:
variant += "?" + url_parts.query
if url_parts.fragment:
variant += "#" + url_parts.fragment
if variant:
rv.append(variant)
rv.extend([item for item in reversed(url_parts.path.split("/")) if item])
return rv
def _add_rule(self, test_manifests, url, direction):
maybe_path = os.path.join(os.path.abspath(os.curdir), url)
rest, last = os.path.split(maybe_path)
variant = ""
if "#" in last:
last, fragment = last.rsplit("#", 1)
variant += "#" + fragment
if "?" in last:
last, query = last.rsplit("?", 1)
variant += "?" + query
maybe_path = os.path.join(rest, last)
paths = glob.glob(maybe_path)
if paths:
urls = []
for path in paths:
for manifest, data in test_manifests.iteritems():
rel_path = os.path.relpath(path, data["tests_path"])
if ".." not in rel_path.split(os.sep):
urls.append(data["url_base"] + rel_path.replace(os.path.sep, "/") + variant)
break
else:
urls = [url]
assert direction in ("include", "exclude")
for url in urls:
components = self._get_components(url)
node = self
while components:
component = components.pop()
if component not in node.child_map:
new_node = IncludeManifest(DataNode(component))
node.append(new_node)
new_node.set("skip", node.get("skip", {}))
node = node.child_map[component]
skip = False if direction == "include" else True
node.set("skip", str(skip))
def add_include(self, test_manifests, url_prefix):
"""Add a rule indicating that tests under a url path
should be included in test runs
:param url_prefix: The url prefix to include
"""
return self._add_rule(test_manifests, url_prefix, "include")
def add_exclude(self, test_manifests, url_prefix):
"""Add a rule indicating that tests under a url path
should be excluded from test runs
:param url_prefix: The url prefix to exclude
"""
return self._add_rule(test_manifests, url_prefix, "exclude")
def get_manifest(manifest_path):
with open(manifest_path) as f:
return conditional.compile(f, data_cls_getter=lambda x, y: IncludeManifest)
|