зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 12 changesets (bug 1497898) for build bustages. CLOSED TREE
Backed out changeset 57877c614829 (bug 1497898) Backed out changeset 22a06c8c8dc6 (bug 1497898) Backed out changeset 7bba4d617db6 (bug 1497898) Backed out changeset 3a9a7760db5c (bug 1497898) Backed out changeset c482d18cc050 (bug 1497898) Backed out changeset 2caa5633dea1 (bug 1497898) Backed out changeset 48be184d5377 (bug 1497898) Backed out changeset 184bc31c33a6 (bug 1497898) Backed out changeset c3cb0408498c (bug 1497898) Backed out changeset a6a89509add7 (bug 1497898) Backed out changeset 9afac925aef8 (bug 1497898) Backed out changeset 5e3b8ad4c8f4 (bug 1497898)
This commit is contained in:
Родитель
9fa028580e
Коммит
966d95816c
|
@ -2,11 +2,8 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from mozboot.util import get_state_dir
|
|
||||||
|
|
||||||
|
|
||||||
def create_parser_wpt():
|
def create_parser_wpt():
|
||||||
from wptrunner import wptcommandline
|
from wptrunner import wptcommandline
|
||||||
|
@ -47,5 +44,4 @@ class WebPlatformTestsRunner(object):
|
||||||
return manifestupdate.run(logger=logger,
|
return manifestupdate.run(logger=logger,
|
||||||
src_root=self.setup.topsrcdir,
|
src_root=self.setup.topsrcdir,
|
||||||
obj_root=self.setup.topobjdir,
|
obj_root=self.setup.topobjdir,
|
||||||
cache_root=os.path.join(get_state_dir()[0], "cache", "wpt"),
|
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
import argparse
|
import argparse
|
||||||
import hashlib
|
|
||||||
import imp
|
import imp
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -106,8 +105,7 @@ def run(src_root, obj_root, logger=None, **kwargs):
|
||||||
logger.debug("Skipping manifest download")
|
logger.debug("Skipping manifest download")
|
||||||
|
|
||||||
if kwargs["update"] or kwargs["rebuild"]:
|
if kwargs["update"] or kwargs["rebuild"]:
|
||||||
manifests = update(logger, src_wpt_dir, test_paths, rebuild=kwargs["rebuild"],
|
manifests = update(logger, src_wpt_dir, test_paths, rebuild=kwargs["rebuild"])
|
||||||
cache_root=kwargs["cache_root"])
|
|
||||||
else:
|
else:
|
||||||
logger.debug("Skipping manifest update")
|
logger.debug("Skipping manifest update")
|
||||||
manifests = load_manifests(test_paths)
|
manifests = load_manifests(test_paths)
|
||||||
|
@ -166,17 +164,24 @@ def generate_config(logger, repo_root, wpt_dir, dest_path, force_rewrite=False):
|
||||||
return dest_config_path
|
return dest_config_path
|
||||||
|
|
||||||
|
|
||||||
def update(logger, wpt_dir, test_paths, rebuild=False, config_dir=None, cache_root=None):
|
def update(logger, wpt_dir, test_paths, rebuild=False, config_dir=None):
|
||||||
rv = {}
|
rv = {}
|
||||||
wptdir_hash = hashlib.sha256(os.path.abspath(wpt_dir)).hexdigest()
|
|
||||||
for url_base, paths in test_paths.iteritems():
|
for url_base, paths in test_paths.iteritems():
|
||||||
|
m = None
|
||||||
manifest_path = paths["manifest_path"]
|
manifest_path = paths["manifest_path"]
|
||||||
this_cache_root = os.path.join(cache_root, wptdir_hash, os.path.dirname(paths["manifest_rel_path"]))
|
if not rebuild and os.path.exists(manifest_path):
|
||||||
m = manifest.manifest.load_and_update(paths["tests_path"],
|
logger.info("Updating manifest %s" % manifest_path)
|
||||||
manifest_path,
|
try:
|
||||||
url_base,
|
m = manifest.manifest.load(paths["tests_path"], manifest_path)
|
||||||
working_copy=True,
|
except manifest.manifest.ManifestVersionMismatch:
|
||||||
cache_root=this_cache_root)
|
logger.info("Manifest format changed, rebuilding")
|
||||||
|
if m is None:
|
||||||
|
logger.info("Recreating manifest %s" % manifest_path)
|
||||||
|
m = manifest.manifest.Manifest(url_base)
|
||||||
|
manifest.update.update(paths["tests_path"], m, working_copy=True)
|
||||||
|
manifest.manifest.write(m, manifest_path)
|
||||||
|
|
||||||
path_data = {"url_base": url_base}
|
path_data = {"url_base": url_base}
|
||||||
path_data.update(paths)
|
path_data.update(paths)
|
||||||
rv[m] = path_data
|
rv[m] = path_data
|
||||||
|
|
|
@ -5,15 +5,19 @@ _venv/
|
||||||
.cache/
|
.cache/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
.tox/
|
.tox/
|
||||||
.coverage*
|
|
||||||
|
|
||||||
# Node
|
# Node
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
# WPT repo stuff
|
# WPT repo stuff
|
||||||
/MANIFEST.json
|
/MANIFEST.json
|
||||||
.wptcache/
|
|
||||||
/config.json
|
testharness_runner.html
|
||||||
|
!/testharness_runner.html
|
||||||
|
!/tools/wptrunner/wptrunner/testharness_runner.html
|
||||||
|
|
||||||
|
_certs
|
||||||
|
config.json
|
||||||
|
|
||||||
# Various OS/editor specific files
|
# Various OS/editor specific files
|
||||||
*#
|
*#
|
||||||
|
|
|
@ -19,7 +19,6 @@ test_infrastructure() {
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
PRODUCTS=( "firefox" "chrome" )
|
PRODUCTS=( "firefox" "chrome" )
|
||||||
./wpt manifest --rebuild -p ~/meta/MANIFEST.json
|
|
||||||
for PRODUCT in "${PRODUCTS[@]}"; do
|
for PRODUCT in "${PRODUCTS[@]}"; do
|
||||||
if [ "$PRODUCT" != "firefox" ]; then
|
if [ "$PRODUCT" != "firefox" ]; then
|
||||||
# Firefox is expected to work using pref settings for DNS
|
# Firefox is expected to work using pref settings for DNS
|
||||||
|
|
|
@ -1,29 +1,21 @@
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import itertools
|
|
||||||
from six import itervalues, iteritems
|
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
|
|
||||||
end_space = re.compile(r"([^\\]\s)*$")
|
end_space = re.compile(r"([^\\]\s)*$")
|
||||||
|
|
||||||
|
|
||||||
def fnmatch_translate(pat):
|
def fnmatch_translate(pat, path_name=False):
|
||||||
parts = []
|
parts = []
|
||||||
seq = None
|
seq = False
|
||||||
i = 0
|
i = 0
|
||||||
any_char = "[^/]"
|
if pat[0] == "/" or path_name:
|
||||||
if pat[0] == "/":
|
|
||||||
parts.append("^")
|
parts.append("^")
|
||||||
pat = pat[1:]
|
any_char = "[^/]"
|
||||||
|
if pat[0] == "/":
|
||||||
|
pat = pat[1:]
|
||||||
else:
|
else:
|
||||||
# By default match the entire path up to a /
|
any_char = "."
|
||||||
# but if / doesn't appear in the pattern we will mark is as
|
|
||||||
# a name pattern and just produce a pattern that matches against
|
|
||||||
# the filename
|
|
||||||
parts.append("^(?:.*/)?")
|
parts.append("^(?:.*/)?")
|
||||||
|
|
||||||
name_pattern = True
|
|
||||||
if pat[-1] == "/":
|
if pat[-1] == "/":
|
||||||
# If the last character is / match this directory or any subdirectory
|
# If the last character is / match this directory or any subdirectory
|
||||||
pat = pat[:-1]
|
pat = pat[:-1]
|
||||||
|
@ -39,10 +31,11 @@ def fnmatch_translate(pat):
|
||||||
parts.append(re.escape(c))
|
parts.append(re.escape(c))
|
||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
elif seq is not None:
|
elif seq:
|
||||||
# TODO: this doesn't really handle invalid sequences in the right way
|
|
||||||
if c == "]":
|
if c == "]":
|
||||||
seq = None
|
seq = False
|
||||||
|
# First two cases are to deal with the case where / is the only character
|
||||||
|
# in the sequence but path_name is True so it shouldn't match anything
|
||||||
if parts[-1] == "[":
|
if parts[-1] == "[":
|
||||||
parts = parts[:-1]
|
parts = parts[:-1]
|
||||||
elif parts[-1] == "^" and parts[-2] == "[":
|
elif parts[-1] == "^" and parts[-2] == "[":
|
||||||
|
@ -51,46 +44,35 @@ def fnmatch_translate(pat):
|
||||||
parts.append(c)
|
parts.append(c)
|
||||||
elif c == "-":
|
elif c == "-":
|
||||||
parts.append(c)
|
parts.append(c)
|
||||||
else:
|
elif not (path_name and c == "/"):
|
||||||
parts += re.escape(c)
|
parts += re.escape(c)
|
||||||
elif c == "[":
|
elif c == "[":
|
||||||
parts.append("[")
|
parts.append("[")
|
||||||
if i < len(pat) - 1 and pat[i+1] in ("!", "^"):
|
if i < len(pat) - 1 and pat[i+1] in ("!", "^"):
|
||||||
parts.append("^")
|
parts.append("^")
|
||||||
i += 1
|
i += 1
|
||||||
seq = i
|
seq = True
|
||||||
elif c == "*":
|
elif c == "*":
|
||||||
if i < len(pat) - 1 and pat[i+1] == "*":
|
if i < len(pat) - 1 and pat[i+1] == "*":
|
||||||
if i > 0 and pat[i-1] != "/":
|
parts.append(any_char + "*")
|
||||||
raise ValueError
|
|
||||||
parts.append(".*")
|
|
||||||
i += 1
|
i += 1
|
||||||
if i < len(pat) - 1 and pat[i+1] != "/":
|
if i < len(pat) - 1 and pat[i+1] == "*":
|
||||||
raise ValueError
|
raise ValueError
|
||||||
else:
|
else:
|
||||||
parts.append(any_char + "*")
|
parts.append(any_char + "*")
|
||||||
elif c == "?":
|
elif c == "?":
|
||||||
parts.append(any_char)
|
parts.append(any_char)
|
||||||
elif c == "/" and not seq:
|
|
||||||
name_pattern = False
|
|
||||||
parts.append(c)
|
|
||||||
else:
|
else:
|
||||||
parts.append(re.escape(c))
|
parts.append(re.escape(c))
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
if name_pattern:
|
if seq:
|
||||||
parts[0] = "^"
|
|
||||||
|
|
||||||
if seq is not None:
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
parts.append(suffix)
|
parts.append(suffix)
|
||||||
try:
|
try:
|
||||||
return name_pattern, re.compile("".join(parts))
|
return re.compile("".join(parts))
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ValueError
|
raise
|
||||||
|
|
||||||
# Regexp matching rules that have to be converted to patterns
|
|
||||||
pattern_re = re.compile(r".*[\*\[\?]")
|
|
||||||
|
|
||||||
|
|
||||||
def parse_line(line):
|
def parse_line(line):
|
||||||
|
@ -107,19 +89,11 @@ def parse_line(line):
|
||||||
if dir_only:
|
if dir_only:
|
||||||
line = line[:-1]
|
line = line[:-1]
|
||||||
|
|
||||||
# Could make a special case for **/foo, but we don't have any patterns like that
|
return invert, dir_only, fnmatch_translate(line, dir_only)
|
||||||
if not invert and not pattern_re.match(line):
|
|
||||||
literal = True
|
|
||||||
pattern = tuple(line.rsplit("/", 1))
|
|
||||||
else:
|
|
||||||
pattern = fnmatch_translate(line)
|
|
||||||
literal = False
|
|
||||||
|
|
||||||
return invert, dir_only, literal, pattern
|
|
||||||
|
|
||||||
|
|
||||||
class PathFilter(object):
|
class PathFilter(object):
|
||||||
def __init__(self, root, extras=None, cache=None):
|
def __init__(self, root, extras=None):
|
||||||
if root:
|
if root:
|
||||||
ignore_path = os.path.join(root, ".gitignore")
|
ignore_path = os.path.join(root, ".gitignore")
|
||||||
else:
|
else:
|
||||||
|
@ -129,123 +103,51 @@ class PathFilter(object):
|
||||||
return
|
return
|
||||||
self.trivial = False
|
self.trivial = False
|
||||||
|
|
||||||
self.literals_file = defaultdict(dict)
|
self.rules_file = []
|
||||||
self.literals_dir = defaultdict(dict)
|
self.rules_dir = []
|
||||||
self.patterns_file = []
|
|
||||||
self.patterns_dir = []
|
|
||||||
self.cache = cache or {}
|
|
||||||
|
|
||||||
if extras is None:
|
if extras is None:
|
||||||
extras = []
|
extras = []
|
||||||
|
|
||||||
if ignore_path and os.path.exists(ignore_path):
|
if ignore_path and os.path.exists(ignore_path):
|
||||||
args = ignore_path, extras
|
self._read_ignore(ignore_path)
|
||||||
else:
|
|
||||||
args = None, extras
|
|
||||||
self._read_ignore(*args)
|
|
||||||
|
|
||||||
def _read_ignore(self, ignore_path, extras):
|
for item in extras:
|
||||||
if ignore_path is not None:
|
self._read_line(item)
|
||||||
with open(ignore_path) as f:
|
|
||||||
for line in f:
|
def _read_ignore(self, ignore_path):
|
||||||
self._read_line(line)
|
with open(ignore_path) as f:
|
||||||
for line in extras:
|
for line in f:
|
||||||
self._read_line(line)
|
self._read_line(line)
|
||||||
|
|
||||||
def _read_line(self, line):
|
def _read_line(self, line):
|
||||||
parsed = parse_line(line)
|
parsed = parse_line(line)
|
||||||
if not parsed:
|
if not parsed:
|
||||||
return
|
return
|
||||||
invert, dir_only, literal, rule = parsed
|
invert, dir_only, regexp = parsed
|
||||||
|
if dir_only:
|
||||||
if invert:
|
self.rules_dir.append((regexp, invert))
|
||||||
# For exclude rules, we attach the rules to all preceeding patterns, so
|
|
||||||
# that we can match patterns out of order and check if they were later
|
|
||||||
# overriden by an exclude rule
|
|
||||||
assert not literal
|
|
||||||
if not dir_only:
|
|
||||||
rules_iter = itertools.chain(
|
|
||||||
itertools.chain(*(iteritems(item) for item in itervalues(self.literals_dir))),
|
|
||||||
itertools.chain(*(iteritems(item) for item in itervalues(self.literals_file))),
|
|
||||||
self.patterns_dir,
|
|
||||||
self.patterns_file)
|
|
||||||
else:
|
|
||||||
rules_iter = itertools.chain(
|
|
||||||
itertools.chain(*(iteritems(item) for item in itervalues(self.literals_dir))),
|
|
||||||
self.patterns_dir)
|
|
||||||
|
|
||||||
for rules in rules_iter:
|
|
||||||
rules[1].append(rule)
|
|
||||||
else:
|
else:
|
||||||
if literal:
|
self.rules_file.append((regexp, invert))
|
||||||
if len(rule) == 1:
|
|
||||||
dir_name, pattern = None, rule[0]
|
|
||||||
else:
|
|
||||||
dir_name, pattern = rule
|
|
||||||
self.literals_dir[dir_name][pattern] = []
|
|
||||||
if not dir_only:
|
|
||||||
self.literals_file[dir_name][pattern] = []
|
|
||||||
else:
|
|
||||||
self.patterns_dir.append((rule, []))
|
|
||||||
if not dir_only:
|
|
||||||
self.patterns_file.append((rule, []))
|
|
||||||
|
|
||||||
def filter(self, iterator):
|
def __call__(self, path):
|
||||||
empty = {}
|
if os.path.sep != "/":
|
||||||
for dirpath, dirnames, filenames in iterator:
|
path = path.replace(os.path.sep, "/")
|
||||||
orig_dirpath = dirpath
|
|
||||||
if os.path.sep != "/":
|
|
||||||
dirpath = dirpath.replace(os.path.sep, "/")
|
|
||||||
|
|
||||||
keep_dirs = []
|
|
||||||
keep_files = []
|
|
||||||
|
|
||||||
for iter_items, literals, patterns, target, suffix in [
|
|
||||||
(dirnames, self.literals_dir, self.patterns_dir, keep_dirs, "/"),
|
|
||||||
(filenames, self.literals_file, self.patterns_file, keep_files, "")]:
|
|
||||||
for item in iter_items:
|
|
||||||
name = item[0]
|
|
||||||
if dirpath:
|
|
||||||
path = "%s/%s" % (dirpath, name) + suffix
|
|
||||||
else:
|
|
||||||
path = name + suffix
|
|
||||||
if path in self.cache:
|
|
||||||
if not self.cache[path]:
|
|
||||||
target.append(item)
|
|
||||||
continue
|
|
||||||
for rule_dir in [None, dirpath]:
|
|
||||||
if name in literals.get(rule_dir, empty):
|
|
||||||
exclude = literals[rule_dir][name]
|
|
||||||
if not any(rule.match(path) for rule in exclude):
|
|
||||||
# Skip this item
|
|
||||||
self.cache[path] = True
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
for (component_only, pattern), exclude in patterns:
|
|
||||||
if component_only:
|
|
||||||
match = pattern.match(name)
|
|
||||||
else:
|
|
||||||
match = pattern.match(path)
|
|
||||||
if match:
|
|
||||||
if not any(rule.match(name if name_only else path)
|
|
||||||
for name_only, rule in exclude):
|
|
||||||
# Skip this item
|
|
||||||
self.cache[path] = True
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
self.cache[path] = False
|
|
||||||
target.append(item)
|
|
||||||
|
|
||||||
dirnames[:] = keep_dirs
|
|
||||||
assert ".git" not in dirnames
|
|
||||||
yield orig_dirpath, dirnames, keep_files
|
|
||||||
|
|
||||||
def __call__(self, iterator):
|
|
||||||
if self.trivial:
|
if self.trivial:
|
||||||
return iterator
|
return True
|
||||||
|
|
||||||
return self.filter(iterator)
|
path_is_dir = path[-1] == "/"
|
||||||
|
if path_is_dir:
|
||||||
|
path = path[:-1]
|
||||||
|
rules = self.rules_dir
|
||||||
|
else:
|
||||||
|
rules = self.rules_file
|
||||||
|
|
||||||
|
include = True
|
||||||
def has_ignore(dirpath):
|
for regexp, invert in rules:
|
||||||
return os.path.exists(os.path.join(dirpath, ".gitignore"))
|
if not include and invert and regexp.match(path):
|
||||||
|
include = True
|
||||||
|
elif include and not invert and regexp.match(path):
|
||||||
|
include = False
|
||||||
|
return include
|
||||||
|
|
|
@ -3,98 +3,80 @@ import pytest
|
||||||
from ..gitignore import fnmatch_translate, PathFilter
|
from ..gitignore import fnmatch_translate, PathFilter
|
||||||
|
|
||||||
match_data = [
|
match_data = [
|
||||||
("foo", True, ["a/foo", "foo"]),
|
("foo", False, ["a/foo", "foo"]),
|
||||||
("*.a", True, ["foo.a", "a/foo.a", "a/b/foo.a", "a.a/foo.a"]),
|
("*.a", False, ["foo.a", "a/foo.a", "a/b/foo.a", "a.a/foo.a"]),
|
||||||
("*.py[co]", True, ["a.pyc", "a.pyo", "a/b/c.pyc"]),
|
("*.py[co]", False, ["a.pyc", "a.pyo", "a/b/c.pyc"]),
|
||||||
("\\#*", True, ["#a", "a/#b"]),
|
("\\#*", False, ["#a", "a/#b"]),
|
||||||
("*#", True, ["a#", "a/b#", "#a#"]),
|
("*#", False, ["a#", "a/b#", "#a#"]),
|
||||||
("/*.c", True, ["a.c", ".c"]),
|
("/*.c", False, ["a.c", ".c"]),
|
||||||
("**/b", False, ["a/b", "a/c/b"]),
|
("**/b", False, ["a/b", "a/c/b"]),
|
||||||
("*b", True, ["ab"]),
|
("*b", True, ["ab"]),
|
||||||
("*b", True, ["a/b"]),
|
("**/b", True, ["a/b"]),
|
||||||
("**/b", False, ["a/b"]),
|
("a/", True, ["a", "a/b", "a/b/c"])
|
||||||
("a/", True, ["a"]),
|
|
||||||
("a[/]b", True, []),
|
|
||||||
("**/b", False, ["a/c/b"]),
|
|
||||||
("a?c", True, ["abc"]),
|
|
||||||
("a[^b]c", True, ["acc"]),
|
|
||||||
("a[b-c]c", True, ["abc", "acc"]),
|
|
||||||
("a[^]c", True, ["ac"]), # This is probably wrong
|
|
||||||
("a[^]c", True, ["ac"]), # This is probably wrong
|
|
||||||
]
|
]
|
||||||
|
|
||||||
mismatch_data = [
|
mismatch_data = [
|
||||||
("foo", True, ["foob", "afoo"]),
|
("foo", False, ["foob", "afoo"]),
|
||||||
("*.a", True, ["a", "foo:a", "a.a/foo"]),
|
("*.a", False, ["a", "foo:a", "a.a/foo"]),
|
||||||
("*.py[co]", True, ["a.pyd", "pyo", "a.py"]),
|
("*.py[co]", False, ["a.pyd", "pyo"]),
|
||||||
("a", True, ["ab"]),
|
("/*.c", False, ["a/b.c"]),
|
||||||
("a?c", True, ["ac", "abbc"]),
|
("*b", True, ["a/b"]),
|
||||||
("a[^b]c", True, ["abc"]),
|
("**b", True, ["a/b"]),
|
||||||
("a[b-c]c", True, ["adc"]),
|
("a[/]b", True, ["a/b"]),
|
||||||
|
("**/b", True, ["a/c/b"]),
|
||||||
|
("a", True, ["ab"])
|
||||||
]
|
]
|
||||||
|
|
||||||
invalid_data = [
|
invalid_data = [
|
||||||
"[a",
|
"[a",
|
||||||
"***/foo",
|
"***/foo",
|
||||||
"a\\",
|
"a\\",
|
||||||
"**b",
|
|
||||||
"b**/",
|
|
||||||
"[[]"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
filter_data = [
|
filter_data = [
|
||||||
(["foo", "bar/", "/a", "*.py"],
|
("foo", True),
|
||||||
[("", ["foo", "bar", "baz"], ["a"]),
|
("a", False),
|
||||||
("baz", ["a"], ["foo", "bar"])],
|
("a/b", False),
|
||||||
[(["baz"], []),
|
("a/c", True),
|
||||||
(["a"], ["bar"])]),
|
("a/c/", False),
|
||||||
(["#foo", "", "a*", "!a.py"],
|
("c/b", True)
|
||||||
[("", ["foo"], ["a", "a.foo", "a.py"])],
|
|
||||||
[(["foo"], ["a.py"])]),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def expand_data(compact_data):
|
def expand_data(compact_data):
|
||||||
for pattern, name_only, inputs in compact_data:
|
for pattern, path_name, inputs in compact_data:
|
||||||
for input in inputs:
|
for input in inputs:
|
||||||
yield pattern, name_only, input
|
yield pattern, input, path_name
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("pattern, name_only, input", expand_data(match_data))
|
@pytest.mark.parametrize("pattern, input, path_name", expand_data(match_data))
|
||||||
def tests_match(pattern, name_only, input):
|
def tests_match(pattern, input, path_name):
|
||||||
name_only_result, regexp = fnmatch_translate(pattern)
|
regexp = fnmatch_translate(pattern, path_name)
|
||||||
assert name_only_result == name_only
|
|
||||||
if name_only:
|
|
||||||
input = input.rsplit("/", 1)[-1]
|
|
||||||
assert regexp.match(input) is not None
|
assert regexp.match(input) is not None
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("pattern, name_only, input", expand_data(mismatch_data))
|
@pytest.mark.parametrize("pattern, input, path_name", expand_data(mismatch_data))
|
||||||
def tests_no_match(pattern, name_only, input):
|
def tests_no_match(pattern, input, path_name):
|
||||||
name_only_result, regexp = fnmatch_translate(pattern)
|
regexp = fnmatch_translate(pattern, path_name)
|
||||||
assert name_only_result == name_only
|
|
||||||
if name_only:
|
|
||||||
input = input.rsplit("/", 1)[-1]
|
|
||||||
assert regexp.match(input) is None
|
assert regexp.match(input) is None
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("pattern", invalid_data)
|
@pytest.mark.parametrize("pattern", invalid_data)
|
||||||
def tests_invalid(pattern):
|
def tests_invalid(pattern):
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
fnmatch_translate(pattern)
|
fnmatch_translate(pattern, False)
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
fnmatch_translate(pattern, True)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("rules, input, expected", filter_data)
|
@pytest.mark.parametrize("path, expected", filter_data)
|
||||||
def test_path_filter(rules, input, expected):
|
def test_path_filter(path, expected):
|
||||||
f = PathFilter(None, rules)
|
extras = [
|
||||||
# Add some fake stat data
|
"#foo",
|
||||||
for i, item in enumerate(input):
|
"a ",
|
||||||
repl = [input[i][0]]
|
"**/b",
|
||||||
for j in [1, 2]:
|
"a/c/",
|
||||||
repl.append([(name, None) for name in input[i][j]])
|
"!c/b",
|
||||||
input[i] = tuple(repl)
|
]
|
||||||
|
f = PathFilter(None, extras)
|
||||||
for i, output in enumerate(f(input)):
|
assert f(path) == expected
|
||||||
assert output[0] == input[i][0]
|
|
||||||
for j in [1, 2]:
|
|
||||||
assert [item[0] for item in output[j]] == expected[i][j-1]
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ from . import fnmatch
|
||||||
from .. import localpaths
|
from .. import localpaths
|
||||||
from ..gitignore.gitignore import PathFilter
|
from ..gitignore.gitignore import PathFilter
|
||||||
from ..wpt import testfiles
|
from ..wpt import testfiles
|
||||||
from ..manifest.vcs import walk
|
|
||||||
|
|
||||||
from manifest.sourcefile import SourceFile, js_meta_re, python_meta_re, space_chars, get_any_variants, get_default_any_variants
|
from manifest.sourcefile import SourceFile, js_meta_re, python_meta_re, space_chars, get_any_variants, get_default_any_variants
|
||||||
from six import binary_type, iteritems, itervalues
|
from six import binary_type, iteritems, itervalues
|
||||||
|
@ -68,11 +67,14 @@ def all_filesystem_paths(repo_root, subdir=None):
|
||||||
expanded_path = subdir
|
expanded_path = subdir
|
||||||
else:
|
else:
|
||||||
expanded_path = repo_root
|
expanded_path = repo_root
|
||||||
for dirpath, dirnames, filenames in path_filter(walk(expanded_path)):
|
for dirpath, dirnames, filenames in os.walk(expanded_path):
|
||||||
for filename, _ in filenames:
|
for filename in filenames:
|
||||||
path = os.path.join(dirpath, filename)
|
path = os.path.relpath(os.path.join(dirpath, filename), repo_root)
|
||||||
yield path
|
if path_filter(path):
|
||||||
|
yield path
|
||||||
|
dirnames[:] = [item for item in dirnames if
|
||||||
|
path_filter(os.path.relpath(os.path.join(dirpath, item) + "/",
|
||||||
|
repo_root)+"/")]
|
||||||
|
|
||||||
def _all_files_equal(paths):
|
def _all_files_equal(paths):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -401,13 +401,13 @@ def test_check_css_globally_unique_ignored_dir(caplog):
|
||||||
|
|
||||||
def test_all_filesystem_paths():
|
def test_all_filesystem_paths():
|
||||||
with mock.patch(
|
with mock.patch(
|
||||||
'tools.lint.lint.walk',
|
'os.walk',
|
||||||
return_value=[('',
|
return_value=[('.',
|
||||||
[('dir_a', None), ('dir_b', None)],
|
['dir_a', 'dir_b'],
|
||||||
[('file_a', None), ('file_b', None)]),
|
['file_a', 'file_b']),
|
||||||
('dir_a',
|
(os.path.join('.', 'dir_a'),
|
||||||
[],
|
[],
|
||||||
[('file_c', None), ('file_d', None)])]
|
['file_c', 'file_d'])]
|
||||||
):
|
):
|
||||||
got = list(lint_mod.all_filesystem_paths('.'))
|
got = list(lint_mod.all_filesystem_paths('.'))
|
||||||
assert got == ['file_a',
|
assert got == ['file_a',
|
||||||
|
|
|
@ -2,4 +2,5 @@
|
||||||
{"path": "update.py", "script": "run", "parser": "create_parser", "help": "Update the MANIFEST.json file",
|
{"path": "update.py", "script": "run", "parser": "create_parser", "help": "Update the MANIFEST.json file",
|
||||||
"virtualenv": false},
|
"virtualenv": false},
|
||||||
"manifest-download":
|
"manifest-download":
|
||||||
{"path": "download.py", "script": "run", "parser": "create_parser", "help": "Download recent pregenerated MANIFEST.json file", "virtualenv": false}}
|
{"path": "download.py", "script": "run", "parser": "create_parser", "help": "Download recent pregenerated MANIFEST.json file",
|
||||||
|
"virtualenv": false}}
|
||||||
|
|
|
@ -2,21 +2,19 @@ from six.moves.urllib.parse import urljoin, urlparse
|
||||||
from abc import ABCMeta, abstractproperty
|
from abc import ABCMeta, abstractproperty
|
||||||
|
|
||||||
|
|
||||||
class SourceFileCache(object):
|
def get_source_file(source_files, tests_root, manifest, path):
|
||||||
def __init__(self):
|
def make_new():
|
||||||
self.source_files = {}
|
|
||||||
|
|
||||||
def make_new(self, tests_root, path, url_base):
|
|
||||||
from .sourcefile import SourceFile
|
from .sourcefile import SourceFile
|
||||||
|
|
||||||
return SourceFile(tests_root, path, url_base)
|
return SourceFile(tests_root, path, manifest.url_base)
|
||||||
|
|
||||||
def get(self, tests_root, manifest, path):
|
if source_files is None:
|
||||||
|
return make_new()
|
||||||
|
|
||||||
if path not in self.source_files:
|
if path not in source_files:
|
||||||
self.source_files[path] = self.make_new(tests_root, path, manifest.url_base)
|
source_files[path] = make_new()
|
||||||
|
|
||||||
return self.source_files[path]
|
return source_files[path]
|
||||||
|
|
||||||
|
|
||||||
item_types = {}
|
item_types = {}
|
||||||
|
@ -39,9 +37,8 @@ class ManifestItem(object):
|
||||||
|
|
||||||
item_type = None
|
item_type = None
|
||||||
|
|
||||||
source_file_cache = SourceFileCache()
|
|
||||||
|
|
||||||
def __init__(self, source_file, manifest=None):
|
def __init__(self, source_file, manifest=None):
|
||||||
|
self.manifest = manifest
|
||||||
self.source_file = source_file
|
self.source_file = source_file
|
||||||
|
|
||||||
@abstractproperty
|
@abstractproperty
|
||||||
|
@ -87,8 +84,8 @@ class ManifestItem(object):
|
||||||
return [{}]
|
return [{}]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, manifest, tests_root, path, obj):
|
def from_json(cls, manifest, tests_root, path, obj, source_files=None):
|
||||||
source_file = cls.source_file_cache.get(tests_root, manifest, path)
|
source_file = get_source_file(source_files, tests_root, manifest, path)
|
||||||
return cls(source_file,
|
return cls(source_file,
|
||||||
manifest=manifest)
|
manifest=manifest)
|
||||||
|
|
||||||
|
@ -116,8 +113,8 @@ class URLManifestItem(ManifestItem):
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, manifest, tests_root, path, obj):
|
def from_json(cls, manifest, tests_root, path, obj, source_files=None):
|
||||||
source_file = cls.source_file_cache.get(tests_root, manifest, path)
|
source_file = get_source_file(source_files, tests_root, manifest, path)
|
||||||
url, extras = obj
|
url, extras = obj
|
||||||
return cls(source_file,
|
return cls(source_file,
|
||||||
url,
|
url,
|
||||||
|
@ -148,8 +145,8 @@ class TestharnessTest(URLManifestItem):
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, manifest, tests_root, path, obj):
|
def from_json(cls, manifest, tests_root, path, obj, source_files=None):
|
||||||
source_file = cls.source_file_cache.get(tests_root, manifest, path)
|
source_file = get_source_file(source_files, tests_root, manifest, path)
|
||||||
|
|
||||||
url, extras = obj
|
url, extras = obj
|
||||||
return cls(source_file,
|
return cls(source_file,
|
||||||
|
@ -190,8 +187,8 @@ class RefTestNode(URLManifestItem):
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, manifest, tests_root, path, obj):
|
def from_json(cls, manifest, tests_root, path, obj, source_files=None):
|
||||||
source_file = cls.source_file_cache.get(tests_root, manifest, path)
|
source_file = get_source_file(source_files, tests_root, manifest, path)
|
||||||
url, references, extras = obj
|
url, references, extras = obj
|
||||||
return cls(source_file,
|
return cls(source_file,
|
||||||
url,
|
url,
|
||||||
|
@ -251,8 +248,8 @@ class WebDriverSpecTest(URLManifestItem):
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, manifest, tests_root, path, obj):
|
def from_json(cls, manifest, tests_root, path, obj, source_files=None):
|
||||||
source_file = cls.source_file_cache.get(tests_root, manifest, path)
|
source_file = get_source_file(source_files, tests_root, manifest, path)
|
||||||
|
|
||||||
url, extras = obj
|
url, extras = obj
|
||||||
return cls(source_file,
|
return cls(source_file,
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
import itertools
|
import itertools
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from six import iteritems, iterkeys, itervalues, string_types
|
from six import iteritems, itervalues, viewkeys, string_types
|
||||||
|
|
||||||
from . import vcs
|
from .item import ManualTest, WebDriverSpecTest, Stub, RefTestNode, RefTest, TestharnessTest, SupportFile, ConformanceCheckerTest, VisualTest
|
||||||
from .item import (ManualTest, WebDriverSpecTest, Stub, RefTestNode, RefTest,
|
|
||||||
TestharnessTest, SupportFile, ConformanceCheckerTest, VisualTest)
|
|
||||||
from .log import get_logger
|
from .log import get_logger
|
||||||
from .utils import from_os_path, to_os_path
|
from .utils import from_os_path, to_os_path
|
||||||
|
|
||||||
try:
|
|
||||||
import ujson as json
|
|
||||||
except ImportError:
|
|
||||||
import json
|
|
||||||
|
|
||||||
CURRENT_VERSION = 5
|
CURRENT_VERSION = 5
|
||||||
|
|
||||||
|
@ -32,173 +27,11 @@ def iterfilter(filters, iter):
|
||||||
yield item
|
yield item
|
||||||
|
|
||||||
|
|
||||||
item_classes = {"testharness": TestharnessTest,
|
|
||||||
"reftest": RefTest,
|
|
||||||
"reftest_node": RefTestNode,
|
|
||||||
"manual": ManualTest,
|
|
||||||
"stub": Stub,
|
|
||||||
"wdspec": WebDriverSpecTest,
|
|
||||||
"conformancechecker": ConformanceCheckerTest,
|
|
||||||
"visual": VisualTest,
|
|
||||||
"support": SupportFile}
|
|
||||||
|
|
||||||
|
|
||||||
class TypeData(object):
|
|
||||||
def __init__(self, manifest, type_cls, meta_filters):
|
|
||||||
"""Dict-like object containing the TestItems for each test type.
|
|
||||||
|
|
||||||
Loading an actual Item class for each test is unnecessarily
|
|
||||||
slow, so this class allows lazy-loading of the test
|
|
||||||
items. When the manifest is loaded we store the raw json
|
|
||||||
corresponding to the test type, and only create an Item
|
|
||||||
subclass when the test is accessed. In order to remain
|
|
||||||
API-compatible with consumers that depend on getting an Item
|
|
||||||
from iteration, we do egerly load all items when iterating
|
|
||||||
over the class."""
|
|
||||||
self.manifest = manifest
|
|
||||||
self.type_cls = type_cls
|
|
||||||
self.json_data = {}
|
|
||||||
self.tests_root = None
|
|
||||||
self.data = {}
|
|
||||||
self.meta_filters = meta_filters or []
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
if key not in self.data:
|
|
||||||
self.load(key)
|
|
||||||
return self.data[key]
|
|
||||||
|
|
||||||
def __bool__(self):
|
|
||||||
return bool(self.data)
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
rv = len(self.data)
|
|
||||||
if self.json_data is not None:
|
|
||||||
rv += len(self.json_data)
|
|
||||||
return rv
|
|
||||||
|
|
||||||
def __delitem__(self, key):
|
|
||||||
del self.data[key]
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
self.data[key] = value
|
|
||||||
|
|
||||||
def __contains__(self, key):
|
|
||||||
self.load_all()
|
|
||||||
return key in self.data
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
self.load_all()
|
|
||||||
return self.data.__iter__()
|
|
||||||
|
|
||||||
def pop(self, key, default=None):
|
|
||||||
try:
|
|
||||||
value = self[key]
|
|
||||||
except ValueError:
|
|
||||||
value = default
|
|
||||||
else:
|
|
||||||
del self.data[key]
|
|
||||||
return value
|
|
||||||
|
|
||||||
def get(self, key, default=None):
|
|
||||||
try:
|
|
||||||
return self[key]
|
|
||||||
except ValueError:
|
|
||||||
return default
|
|
||||||
|
|
||||||
def itervalues(self):
|
|
||||||
self.load_all()
|
|
||||||
return itervalues(self.data)
|
|
||||||
|
|
||||||
def iteritems(self):
|
|
||||||
self.load_all()
|
|
||||||
return iteritems(self.data)
|
|
||||||
|
|
||||||
def values(self):
|
|
||||||
return self.itervalues()
|
|
||||||
|
|
||||||
def items(self):
|
|
||||||
return self.iteritems()
|
|
||||||
|
|
||||||
def load(self, key):
|
|
||||||
"""Load a specific Item given a path"""
|
|
||||||
if self.json_data is not None:
|
|
||||||
data = set()
|
|
||||||
path = from_os_path(key)
|
|
||||||
for test in iterfilter(self.meta_filters, self.json_data.get(path, [])):
|
|
||||||
manifest_item = self.type_cls.from_json(self.manifest,
|
|
||||||
self.tests_root,
|
|
||||||
path,
|
|
||||||
test)
|
|
||||||
data.add(manifest_item)
|
|
||||||
try:
|
|
||||||
del self.json_data[path]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
self.data[key] = data
|
|
||||||
else:
|
|
||||||
raise ValueError
|
|
||||||
|
|
||||||
def load_all(self):
|
|
||||||
"""Load all test items in this class"""
|
|
||||||
if self.json_data is not None:
|
|
||||||
for path, value in iteritems(self.json_data):
|
|
||||||
key = to_os_path(path)
|
|
||||||
if key in self.data:
|
|
||||||
continue
|
|
||||||
data = set()
|
|
||||||
for test in iterfilter(self.meta_filters, self.json_data.get(path, [])):
|
|
||||||
manifest_item = self.type_cls.from_json(self.manifest,
|
|
||||||
self.tests_root,
|
|
||||||
path,
|
|
||||||
test)
|
|
||||||
data.add(manifest_item)
|
|
||||||
self.data[key] = data
|
|
||||||
self.json_data = None
|
|
||||||
|
|
||||||
def set_json(self, tests_root, data):
|
|
||||||
if not isinstance(data, dict):
|
|
||||||
raise ValueError("Got a %s expected a dict" % (type(data)))
|
|
||||||
self.tests_root = tests_root
|
|
||||||
self.json_data = data
|
|
||||||
|
|
||||||
def paths(self):
|
|
||||||
"""Get a list of all paths containing items of this type,
|
|
||||||
without actually constructing all the items"""
|
|
||||||
rv = set(iterkeys(self.data))
|
|
||||||
if self.json_data:
|
|
||||||
rv |= set(to_os_path(item) for item in iterkeys(self.json_data))
|
|
||||||
return rv
|
|
||||||
|
|
||||||
|
|
||||||
class ManifestData(dict):
|
|
||||||
def __init__(self, manifest, meta_filters=None):
|
|
||||||
"""Dictionary subclass containing a TypeData instance for each test type,
|
|
||||||
keyed by type name"""
|
|
||||||
self.initialized = False
|
|
||||||
for key, value in iteritems(item_classes):
|
|
||||||
self[key] = TypeData(manifest, value, meta_filters=meta_filters)
|
|
||||||
self.initialized = True
|
|
||||||
self.json_obj = None
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
if self.initialized:
|
|
||||||
raise AttributeError
|
|
||||||
dict.__setitem__(self, key, value)
|
|
||||||
|
|
||||||
def paths(self):
|
|
||||||
"""Get a list of all paths containing test items
|
|
||||||
without actually constructing all the items"""
|
|
||||||
rv = set()
|
|
||||||
for item_data in itervalues(self):
|
|
||||||
rv |= set(item_data.paths())
|
|
||||||
return rv
|
|
||||||
|
|
||||||
|
|
||||||
class Manifest(object):
|
class Manifest(object):
|
||||||
def __init__(self, url_base="/", meta_filters=None):
|
def __init__(self, url_base="/"):
|
||||||
assert url_base is not None
|
assert url_base is not None
|
||||||
self._path_hash = {}
|
self._path_hash = {}
|
||||||
self._data = ManifestData(self, meta_filters)
|
self._data = defaultdict(dict)
|
||||||
self._reftest_nodes_by_url = None
|
self._reftest_nodes_by_url = None
|
||||||
self.url_base = url_base
|
self.url_base = url_base
|
||||||
|
|
||||||
|
@ -209,8 +42,7 @@ class Manifest(object):
|
||||||
if not types:
|
if not types:
|
||||||
types = sorted(self._data.keys())
|
types = sorted(self._data.keys())
|
||||||
for item_type in types:
|
for item_type in types:
|
||||||
for path in sorted(self._data[item_type]):
|
for path, tests in sorted(iteritems(self._data[item_type])):
|
||||||
tests = self._data[item_type][path]
|
|
||||||
yield item_type, path, tests
|
yield item_type, path, tests
|
||||||
|
|
||||||
def iterpath(self, path):
|
def iterpath(self, path):
|
||||||
|
@ -242,86 +74,61 @@ class Manifest(object):
|
||||||
return self.reftest_nodes_by_url.get(url)
|
return self.reftest_nodes_by_url.get(url)
|
||||||
|
|
||||||
def update(self, tree):
|
def update(self, tree):
|
||||||
"""Update the manifest given an iterable of items that make up the updated manifest.
|
new_data = defaultdict(dict)
|
||||||
|
new_hashes = {}
|
||||||
|
|
||||||
The iterable must either generate tuples of the form (SourceFile, True) for paths
|
|
||||||
that are to be updated, or (path, False) for items that are not to be updated. This
|
|
||||||
unusual API is designed as an optimistaion meaning that SourceFile items need not be
|
|
||||||
constructed in the case we are not updating a path, but the absence of an item from
|
|
||||||
the iterator may be used to remove defunct entries from the manifest."""
|
|
||||||
reftest_nodes = []
|
reftest_nodes = []
|
||||||
seen_files = set()
|
old_files = defaultdict(set, {k: set(viewkeys(v)) for k, v in iteritems(self._data)})
|
||||||
|
|
||||||
changed = False
|
changed = False
|
||||||
reftest_changes = False
|
reftest_changes = False
|
||||||
|
|
||||||
prev_files = self._data.paths()
|
for source_file in tree:
|
||||||
|
rel_path = source_file.rel_path
|
||||||
|
file_hash = source_file.hash
|
||||||
|
|
||||||
reftest_types = ("reftest", "reftest_node")
|
is_new = rel_path not in self._path_hash
|
||||||
|
hash_changed = False
|
||||||
|
|
||||||
for source_file, update in tree:
|
if not is_new:
|
||||||
if not update:
|
old_hash, old_type = self._path_hash[rel_path]
|
||||||
rel_path = source_file
|
old_files[old_type].remove(rel_path)
|
||||||
seen_files.add(rel_path)
|
if old_hash != file_hash:
|
||||||
else:
|
|
||||||
rel_path = source_file.rel_path
|
|
||||||
seen_files.add(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]
|
|
||||||
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]
|
|
||||||
if old_type in reftest_types and new_type != old_type:
|
|
||||||
reftest_changes = True
|
|
||||||
else:
|
|
||||||
new_type, manifest_items = source_file.manifest_items()
|
new_type, manifest_items = source_file.manifest_items()
|
||||||
|
hash_changed = True
|
||||||
if new_type in ("reftest", "reftest_node"):
|
|
||||||
reftest_nodes.extend(manifest_items)
|
|
||||||
if is_new or hash_changed:
|
|
||||||
reftest_changes = True
|
|
||||||
elif new_type:
|
|
||||||
self._data[new_type][rel_path] = set(manifest_items)
|
|
||||||
|
|
||||||
self._path_hash[rel_path] = (file_hash, new_type)
|
|
||||||
|
|
||||||
if is_new or hash_changed:
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
deleted = prev_files - seen_files
|
|
||||||
if deleted:
|
|
||||||
changed = True
|
|
||||||
for rel_path in deleted:
|
|
||||||
if rel_path in self._path_hash:
|
|
||||||
_, old_type = self._path_hash[rel_path]
|
|
||||||
if old_type in reftest_types:
|
|
||||||
reftest_changes = True
|
|
||||||
try:
|
|
||||||
del self._path_hash[rel_path]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
del self._data[old_type][rel_path]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
else:
|
else:
|
||||||
for test_data in itervalues(self._data):
|
new_type, manifest_items = old_type, self._data[old_type][rel_path]
|
||||||
if rel_path in test_data:
|
if old_type in ("reftest", "reftest_node") and new_type != old_type:
|
||||||
del test_data[rel_path]
|
reftest_changes = True
|
||||||
|
else:
|
||||||
|
new_type, manifest_items = source_file.manifest_items()
|
||||||
|
|
||||||
if reftest_changes:
|
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)
|
reftests, reftest_nodes, changed_hashes = self._compute_reftests(reftest_nodes)
|
||||||
self._data["reftest"].data = reftests
|
new_data["reftest"] = reftests
|
||||||
self._data["reftest_node"].data = reftest_nodes
|
new_data["reftest_node"] = reftest_nodes
|
||||||
self._path_hash.update(changed_hashes)
|
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
|
return changed
|
||||||
|
|
||||||
|
@ -361,7 +168,7 @@ class Manifest(object):
|
||||||
[t for t in sorted(test.to_json() for test in tests)]
|
[t for t in sorted(test.to_json() for test in tests)]
|
||||||
for path, tests in iteritems(type_paths)
|
for path, tests in iteritems(type_paths)
|
||||||
}
|
}
|
||||||
for test_type, type_paths in iteritems(self._data) if type_paths
|
for test_type, type_paths in iteritems(self._data)
|
||||||
}
|
}
|
||||||
rv = {"url_base": self.url_base,
|
rv = {"url_base": self.url_base,
|
||||||
"paths": {from_os_path(k): v for k, v in iteritems(self._path_hash)},
|
"paths": {from_os_path(k): v for k, v in iteritems(self._path_hash)},
|
||||||
|
@ -375,12 +182,26 @@ class Manifest(object):
|
||||||
if version != CURRENT_VERSION:
|
if version != CURRENT_VERSION:
|
||||||
raise ManifestVersionMismatch
|
raise ManifestVersionMismatch
|
||||||
|
|
||||||
self = cls(url_base=obj.get("url_base", "/"), meta_filters=meta_filters)
|
self = cls(url_base=obj.get("url_base", "/"))
|
||||||
if not hasattr(obj, "items") and hasattr(obj, "paths"):
|
if not hasattr(obj, "items") and hasattr(obj, "paths"):
|
||||||
raise ManifestError
|
raise ManifestError
|
||||||
|
|
||||||
self._path_hash = {to_os_path(k): v for k, v in iteritems(obj["paths"])}
|
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}
|
||||||
|
|
||||||
|
meta_filters = meta_filters or []
|
||||||
|
|
||||||
|
source_files = {}
|
||||||
|
|
||||||
for test_type, type_paths in iteritems(obj["items"]):
|
for test_type, type_paths in iteritems(obj["items"]):
|
||||||
if test_type not in item_classes:
|
if test_type not in item_classes:
|
||||||
raise ManifestError
|
raise ManifestError
|
||||||
|
@ -388,7 +209,18 @@ class Manifest(object):
|
||||||
if types and test_type not in types:
|
if types and test_type not in types:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self._data[test_type].set_json(tests_root, type_paths)
|
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 iterfilter(meta_filters, 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
|
return self
|
||||||
|
|
||||||
|
@ -396,11 +228,6 @@ class Manifest(object):
|
||||||
def load(tests_root, manifest, types=None, meta_filters=None):
|
def load(tests_root, manifest, types=None, meta_filters=None):
|
||||||
logger = get_logger()
|
logger = get_logger()
|
||||||
|
|
||||||
logger.warning("Prefer load_and_update instead")
|
|
||||||
return _load(logger, tests_root, manifest, types, meta_filters)
|
|
||||||
|
|
||||||
|
|
||||||
def _load(logger, tests_root, manifest, types=None, meta_filters=None):
|
|
||||||
# "manifest" is a path or file-like object.
|
# "manifest" is a path or file-like object.
|
||||||
if isinstance(manifest, string_types):
|
if isinstance(manifest, string_types):
|
||||||
if os.path.exists(manifest):
|
if os.path.exists(manifest):
|
||||||
|
@ -409,10 +236,7 @@ def _load(logger, tests_root, manifest, types=None, meta_filters=None):
|
||||||
logger.debug("Creating new manifest at %s" % manifest)
|
logger.debug("Creating new manifest at %s" % manifest)
|
||||||
try:
|
try:
|
||||||
with open(manifest) as f:
|
with open(manifest) as f:
|
||||||
rv = Manifest.from_json(tests_root,
|
rv = Manifest.from_json(tests_root, json.load(f), types=types, meta_filters=meta_filters)
|
||||||
json.load(f),
|
|
||||||
types=types,
|
|
||||||
meta_filters=meta_filters)
|
|
||||||
except IOError:
|
except IOError:
|
||||||
return None
|
return None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -420,52 +244,7 @@ def _load(logger, tests_root, manifest, types=None, meta_filters=None):
|
||||||
return None
|
return None
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
return Manifest.from_json(tests_root,
|
return Manifest.from_json(tests_root, json.load(manifest), types=types, meta_filters=meta_filters)
|
||||||
json.load(manifest),
|
|
||||||
types=types,
|
|
||||||
meta_filters=meta_filters)
|
|
||||||
|
|
||||||
|
|
||||||
def load_and_update(tests_root,
|
|
||||||
manifest_path,
|
|
||||||
url_base,
|
|
||||||
update=True,
|
|
||||||
rebuild=False,
|
|
||||||
metadata_path=None,
|
|
||||||
cache_root=None,
|
|
||||||
working_copy=False,
|
|
||||||
types=None,
|
|
||||||
meta_filters=None,
|
|
||||||
write_manifest=True):
|
|
||||||
logger = get_logger()
|
|
||||||
|
|
||||||
manifest = None
|
|
||||||
if not rebuild:
|
|
||||||
try:
|
|
||||||
manifest = _load(logger,
|
|
||||||
tests_root,
|
|
||||||
manifest_path,
|
|
||||||
types=types,
|
|
||||||
meta_filters=meta_filters)
|
|
||||||
except ManifestVersionMismatch:
|
|
||||||
logger.info("Manifest version changed, rebuilding")
|
|
||||||
|
|
||||||
if manifest is not None and manifest.url_base != url_base:
|
|
||||||
logger.info("Manifest url base did not match, rebuilding")
|
|
||||||
|
|
||||||
if manifest is None:
|
|
||||||
manifest = Manifest(url_base, meta_filters=meta_filters)
|
|
||||||
update = True
|
|
||||||
|
|
||||||
if update:
|
|
||||||
tree = vcs.get_tree(tests_root, manifest, manifest_path, cache_root,
|
|
||||||
working_copy, rebuild)
|
|
||||||
changed = manifest.update(tree)
|
|
||||||
if write_manifest and changed:
|
|
||||||
write(manifest, manifest_path)
|
|
||||||
tree.dump_caches()
|
|
||||||
|
|
||||||
return manifest
|
|
||||||
|
|
||||||
|
|
||||||
def write(manifest, manifest_path):
|
def write(manifest, manifest_path):
|
||||||
|
@ -473,5 +252,5 @@ def write(manifest, manifest_path):
|
||||||
if not os.path.exists(dir_name):
|
if not os.path.exists(dir_name):
|
||||||
os.makedirs(dir_name)
|
os.makedirs(dir_name)
|
||||||
with open(manifest_path, "wb") as f:
|
with open(manifest_path, "wb") as f:
|
||||||
json.dump(manifest.to_json(), f, sort_keys=True, indent=1)
|
json.dump(manifest.to_json(), f, sort_keys=True, indent=1, separators=(',', ': '))
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
|
|
|
@ -72,7 +72,7 @@ def sourcefile_strategy(draw):
|
||||||
def test_manifest_to_json(s):
|
def test_manifest_to_json(s):
|
||||||
m = manifest.Manifest()
|
m = manifest.Manifest()
|
||||||
|
|
||||||
assert m.update((item, True) for item in s) is True
|
assert m.update(s) is True
|
||||||
|
|
||||||
json_str = m.to_json()
|
json_str = m.to_json()
|
||||||
loaded = manifest.Manifest.from_json("/", json_str)
|
loaded = manifest.Manifest.from_json("/", json_str)
|
||||||
|
@ -90,11 +90,11 @@ def test_manifest_to_json(s):
|
||||||
def test_manifest_idempotent(s):
|
def test_manifest_idempotent(s):
|
||||||
m = manifest.Manifest()
|
m = manifest.Manifest()
|
||||||
|
|
||||||
assert m.update((item, True) for item in s) is True
|
assert m.update(s) is True
|
||||||
|
|
||||||
m1 = list(m)
|
m1 = list(m)
|
||||||
|
|
||||||
assert m.update((item, True) for item in s) is False
|
assert m.update(s) is False
|
||||||
|
|
||||||
assert list(m) == m1
|
assert list(m) == m1
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ def test_manifest_to_json_forwardslash():
|
||||||
|
|
||||||
s = SourceFileWithTest("a/b", "0"*40, item.TestharnessTest)
|
s = SourceFileWithTest("a/b", "0"*40, item.TestharnessTest)
|
||||||
|
|
||||||
assert m.update([(s, True)]) is True
|
assert m.update([s]) is True
|
||||||
|
|
||||||
assert m.to_json() == {
|
assert m.to_json() == {
|
||||||
'paths': {
|
'paths': {
|
||||||
|
@ -113,6 +113,8 @@ def test_manifest_to_json_forwardslash():
|
||||||
'version': 5,
|
'version': 5,
|
||||||
'url_base': '/',
|
'url_base': '/',
|
||||||
'items': {
|
'items': {
|
||||||
|
'reftest': {},
|
||||||
|
'reftest_node': {},
|
||||||
'testharness': {
|
'testharness': {
|
||||||
'a/b': [['/a/b', {}]]
|
'a/b': [['/a/b', {}]]
|
||||||
}
|
}
|
||||||
|
@ -126,7 +128,7 @@ def test_manifest_to_json_backslash():
|
||||||
s = SourceFileWithTest("a\\b", "0"*40, item.TestharnessTest)
|
s = SourceFileWithTest("a\\b", "0"*40, item.TestharnessTest)
|
||||||
|
|
||||||
if os.path.sep == "\\":
|
if os.path.sep == "\\":
|
||||||
assert m.update([(s, True)]) is True
|
assert m.update([s]) is True
|
||||||
|
|
||||||
assert m.to_json() == {
|
assert m.to_json() == {
|
||||||
'paths': {
|
'paths': {
|
||||||
|
@ -135,6 +137,8 @@ def test_manifest_to_json_backslash():
|
||||||
'version': 5,
|
'version': 5,
|
||||||
'url_base': '/',
|
'url_base': '/',
|
||||||
'items': {
|
'items': {
|
||||||
|
'reftest': {},
|
||||||
|
'reftest_node': {},
|
||||||
'testharness': {
|
'testharness': {
|
||||||
'a/b': [['/a/b', {}]]
|
'a/b': [['/a/b', {}]]
|
||||||
}
|
}
|
||||||
|
@ -144,7 +148,7 @@ def test_manifest_to_json_backslash():
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
# one of these must raise ValueError
|
# one of these must raise ValueError
|
||||||
# the first must return True if it doesn't raise
|
# the first must return True if it doesn't raise
|
||||||
assert m.update([(s, True)]) is True
|
assert m.update([s]) is True
|
||||||
m.to_json()
|
m.to_json()
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,6 +160,8 @@ def test_manifest_from_json_backslash():
|
||||||
'version': 5,
|
'version': 5,
|
||||||
'url_base': '/',
|
'url_base': '/',
|
||||||
'items': {
|
'items': {
|
||||||
|
'reftest': {},
|
||||||
|
'reftest_node': {},
|
||||||
'testharness': {
|
'testharness': {
|
||||||
'a\\b': [['/a/b', {}]]
|
'a\\b': [['/a/b', {}]]
|
||||||
}
|
}
|
||||||
|
@ -172,7 +178,7 @@ def test_reftest_computation_chain():
|
||||||
s1 = SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test2", "==")])
|
s1 = SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test2", "==")])
|
||||||
s2 = SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test3", "==")])
|
s2 = SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test3", "==")])
|
||||||
|
|
||||||
m.update([(s1, True), (s2, True)])
|
m.update([s1, s2])
|
||||||
|
|
||||||
test1 = s1.manifest_items()[1][0]
|
test1 = s1.manifest_items()[1][0]
|
||||||
test2 = s2.manifest_items()[1][0]
|
test2 = s2.manifest_items()[1][0]
|
||||||
|
@ -188,7 +194,7 @@ def test_reftest_computation_chain_update_add():
|
||||||
s2 = SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test3", "==")])
|
s2 = SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test3", "==")])
|
||||||
test2 = s2.manifest_items()[1][0]
|
test2 = s2.manifest_items()[1][0]
|
||||||
|
|
||||||
assert m.update([(s2, True)]) is True
|
assert m.update([s2]) is True
|
||||||
|
|
||||||
assert list(m) == [("reftest", test2.path, {test2})]
|
assert list(m) == [("reftest", test2.path, {test2})]
|
||||||
|
|
||||||
|
@ -196,7 +202,7 @@ def test_reftest_computation_chain_update_add():
|
||||||
test1 = s1.manifest_items()[1][0]
|
test1 = s1.manifest_items()[1][0]
|
||||||
|
|
||||||
# s2's hash is unchanged, but it has gone from a test to a node
|
# s2's hash is unchanged, but it has gone from a test to a node
|
||||||
assert m.update([(s1, True), (s2, True)]) is True
|
assert m.update([s1, s2]) is True
|
||||||
|
|
||||||
test2_node = test2.to_RefTestNode()
|
test2_node = test2.to_RefTestNode()
|
||||||
|
|
||||||
|
@ -210,7 +216,7 @@ def test_reftest_computation_chain_update_remove():
|
||||||
s1 = SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test2", "==")])
|
s1 = SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test2", "==")])
|
||||||
s2 = SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test3", "==")])
|
s2 = SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test3", "==")])
|
||||||
|
|
||||||
assert m.update([(s1, True), (s2, True)]) is True
|
assert m.update([s1, s2]) is True
|
||||||
|
|
||||||
test1 = s1.manifest_items()[1][0]
|
test1 = s1.manifest_items()[1][0]
|
||||||
test2 = s2.manifest_items()[1][0]
|
test2 = s2.manifest_items()[1][0]
|
||||||
|
@ -220,7 +226,7 @@ def test_reftest_computation_chain_update_remove():
|
||||||
("reftest_node", test2.path, {test2_node})]
|
("reftest_node", test2.path, {test2_node})]
|
||||||
|
|
||||||
# s2's hash is unchanged, but it has gone from a node to a test
|
# s2's hash is unchanged, but it has gone from a node to a test
|
||||||
assert m.update([(s2, True)]) is True
|
assert m.update([s2]) is True
|
||||||
|
|
||||||
assert list(m) == [("reftest", test2.path, {test2})]
|
assert list(m) == [("reftest", test2.path, {test2})]
|
||||||
|
|
||||||
|
@ -230,7 +236,7 @@ def test_reftest_computation_chain_update_test_type():
|
||||||
|
|
||||||
s1 = SourceFileWithTest("test", "0"*40, item.RefTest, [("/test-ref", "==")])
|
s1 = SourceFileWithTest("test", "0"*40, item.RefTest, [("/test-ref", "==")])
|
||||||
|
|
||||||
assert m.update([(s1, True)]) is True
|
assert m.update([s1]) is True
|
||||||
|
|
||||||
test1 = s1.manifest_items()[1][0]
|
test1 = s1.manifest_items()[1][0]
|
||||||
|
|
||||||
|
@ -240,7 +246,7 @@ def test_reftest_computation_chain_update_test_type():
|
||||||
# based on the file contents). The updated manifest should not includes the
|
# based on the file contents). The updated manifest should not includes the
|
||||||
# old reftest.
|
# old reftest.
|
||||||
s2 = SourceFileWithTest("test", "1"*40, item.TestharnessTest)
|
s2 = SourceFileWithTest("test", "1"*40, item.TestharnessTest)
|
||||||
assert m.update([(s2, True)]) is True
|
assert m.update([s2]) is True
|
||||||
|
|
||||||
test2 = s2.manifest_items()[1][0]
|
test2 = s2.manifest_items()[1][0]
|
||||||
|
|
||||||
|
@ -253,7 +259,7 @@ def test_reftest_computation_chain_update_node_change():
|
||||||
s1 = SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test2", "==")])
|
s1 = SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test2", "==")])
|
||||||
s2 = SourceFileWithTest("test2", "0"*40, item.RefTestNode, [("/test3", "==")])
|
s2 = SourceFileWithTest("test2", "0"*40, item.RefTestNode, [("/test3", "==")])
|
||||||
|
|
||||||
assert m.update([(s1, True), (s2, True)]) is True
|
assert m.update([s1, s2]) is True
|
||||||
|
|
||||||
test1 = s1.manifest_items()[1][0]
|
test1 = s1.manifest_items()[1][0]
|
||||||
test2 = s2.manifest_items()[1][0]
|
test2 = s2.manifest_items()[1][0]
|
||||||
|
@ -264,7 +270,7 @@ def test_reftest_computation_chain_update_node_change():
|
||||||
#test2 changes to support type
|
#test2 changes to support type
|
||||||
s2 = SourceFileWithTest("test2", "1"*40, item.SupportFile)
|
s2 = SourceFileWithTest("test2", "1"*40, item.SupportFile)
|
||||||
|
|
||||||
assert m.update([(s1, True), (s2, True)]) is True
|
assert m.update([s1,s2]) is True
|
||||||
test3 = s2.manifest_items()[1][0]
|
test3 = s2.manifest_items()[1][0]
|
||||||
|
|
||||||
assert list(m) == [("reftest", test1.path, {test1}),
|
assert list(m) == [("reftest", test1.path, {test1}),
|
||||||
|
@ -274,14 +280,12 @@ def test_reftest_computation_chain_update_node_change():
|
||||||
def test_iterpath():
|
def test_iterpath():
|
||||||
m = manifest.Manifest()
|
m = manifest.Manifest()
|
||||||
|
|
||||||
# This has multiple test types from the same file, which isn't really supported,
|
|
||||||
# so pretend they have different hashes
|
|
||||||
sources = [SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test1-ref", "==")]),
|
sources = [SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test1-ref", "==")]),
|
||||||
SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test2-ref", "==")]),
|
SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test2-ref", "==")]),
|
||||||
SourceFileWithTests("test2", "1"*40, item.TestharnessTest, [("/test2-1.html",),
|
SourceFileWithTests("test2", "0"*40, item.TestharnessTest, [("/test2-1.html",),
|
||||||
("/test2-2.html",)]),
|
("/test2-2.html",)]),
|
||||||
SourceFileWithTest("test3", "0"*40, item.TestharnessTest)]
|
SourceFileWithTest("test3", "0"*40, item.TestharnessTest)]
|
||||||
m.update([(s, True) for s in sources])
|
m.update(sources)
|
||||||
|
|
||||||
assert set(item.url for item in m.iterpath("test2")) == set(["/test2",
|
assert set(item.url for item in m.iterpath("test2")) == set(["/test2",
|
||||||
"/test2-1.html",
|
"/test2-1.html",
|
||||||
|
@ -292,14 +296,12 @@ def test_iterpath():
|
||||||
def test_filter():
|
def test_filter():
|
||||||
m = manifest.Manifest()
|
m = manifest.Manifest()
|
||||||
|
|
||||||
# This has multiple test types from the same file, which isn't really supported,
|
|
||||||
# so pretend they have different hashes
|
|
||||||
sources = [SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test1-ref", "==")]),
|
sources = [SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test1-ref", "==")]),
|
||||||
SourceFileWithTest("test2", "1"*40, item.RefTest, [("/test2-ref", "==")]),
|
SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test2-ref", "==")]),
|
||||||
SourceFileWithTests("test2", "0"*40, item.TestharnessTest, [("/test2-1.html",),
|
SourceFileWithTests("test2", "0"*40, item.TestharnessTest, [("/test2-1.html",),
|
||||||
("/test2-2.html",)]),
|
("/test2-2.html",)]),
|
||||||
SourceFileWithTest("test3", "0"*40, item.TestharnessTest)]
|
SourceFileWithTest("test3", "0"*40, item.TestharnessTest)]
|
||||||
m.update([(s, True) for s in sources])
|
m.update(sources)
|
||||||
|
|
||||||
json = m.to_json()
|
json = m.to_json()
|
||||||
|
|
||||||
|
@ -326,7 +328,7 @@ def test_reftest_node_by_url():
|
||||||
s1 = SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test2", "==")])
|
s1 = SourceFileWithTest("test1", "0"*40, item.RefTest, [("/test2", "==")])
|
||||||
s2 = SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test3", "==")])
|
s2 = SourceFileWithTest("test2", "0"*40, item.RefTest, [("/test3", "==")])
|
||||||
|
|
||||||
m.update([(s1, True), (s2, True)])
|
m.update([s1, s2])
|
||||||
|
|
||||||
test1 = s1.manifest_items()[1][0]
|
test1 = s1.manifest_items()[1][0]
|
||||||
test2 = s2.manifest_items()[1][0]
|
test2 = s2.manifest_items()[1][0]
|
||||||
|
@ -337,44 +339,3 @@ def test_reftest_node_by_url():
|
||||||
m._reftest_nodes_by_url = None
|
m._reftest_nodes_by_url = None
|
||||||
assert m.reftest_nodes_by_url == {"/test1": test1,
|
assert m.reftest_nodes_by_url == {"/test1": test1,
|
||||||
"/test2": test2_node}
|
"/test2": test2_node}
|
||||||
|
|
||||||
|
|
||||||
def test_no_update():
|
|
||||||
m = manifest.Manifest()
|
|
||||||
|
|
||||||
s1 = SourceFileWithTest("test1", "0"*40, item.TestharnessTest)
|
|
||||||
s2 = SourceFileWithTest("test2", "0"*40, item.TestharnessTest)
|
|
||||||
|
|
||||||
m.update([(s1, True), (s2, True)])
|
|
||||||
|
|
||||||
test1 = s1.manifest_items()[1][0]
|
|
||||||
test2 = s2.manifest_items()[1][0]
|
|
||||||
|
|
||||||
assert list(m) == [("testharness", test1.path, {test1}),
|
|
||||||
("testharness", test2.path, {test2})]
|
|
||||||
|
|
||||||
s1_1 = SourceFileWithTest("test1", "1"*40, item.TestharnessTest)
|
|
||||||
|
|
||||||
m.update([(s1, True), (s2.rel_path, False)])
|
|
||||||
|
|
||||||
test1_1 = s1_1.manifest_items()[1][0]
|
|
||||||
|
|
||||||
assert list(m) == [("testharness", test1_1.path, {test1_1}),
|
|
||||||
("testharness", test2.path, {test2})]
|
|
||||||
|
|
||||||
|
|
||||||
def test_no_update_delete():
|
|
||||||
m = manifest.Manifest()
|
|
||||||
|
|
||||||
s1 = SourceFileWithTest("test1", "0"*40, item.TestharnessTest)
|
|
||||||
s2 = SourceFileWithTest("test2", "0"*40, item.TestharnessTest)
|
|
||||||
|
|
||||||
m.update([(s1, True), (s2, True)])
|
|
||||||
|
|
||||||
s1_1 = SourceFileWithTest("test1", "1"*40, item.TestharnessTest)
|
|
||||||
|
|
||||||
m.update([(s1, True)])
|
|
||||||
|
|
||||||
test1_1 = s1_1.manifest_items()[1][0]
|
|
||||||
|
|
||||||
assert list(m) == [("testharness", test1_1.path, {test1_1})]
|
|
||||||
|
|
|
@ -13,18 +13,14 @@ wpt_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir))
|
||||||
|
|
||||||
logger = get_logger()
|
logger = get_logger()
|
||||||
|
|
||||||
|
def update(tests_root, manifest, working_copy=False):
|
||||||
def update(tests_root,
|
|
||||||
manifest,
|
|
||||||
manifest_path=None,
|
|
||||||
working_copy=False,
|
|
||||||
cache_root=None,
|
|
||||||
rebuild=False):
|
|
||||||
logger.warning("Deprecated; use manifest.load_and_update instead")
|
|
||||||
logger.info("Updating manifest")
|
logger.info("Updating manifest")
|
||||||
|
tree = None
|
||||||
|
if not working_copy:
|
||||||
|
tree = vcs.Git.for_path(tests_root, manifest.url_base)
|
||||||
|
if tree is None:
|
||||||
|
tree = vcs.FileSystem(tests_root, manifest.url_base)
|
||||||
|
|
||||||
tree = vcs.get_tree(tests_root, manifest, manifest_path, cache_root,
|
|
||||||
working_copy, rebuild)
|
|
||||||
return manifest.update(tree)
|
return manifest.update(tree)
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,16 +29,26 @@ def update_from_cli(**kwargs):
|
||||||
path = kwargs["path"]
|
path = kwargs["path"]
|
||||||
assert tests_root is not None
|
assert tests_root is not None
|
||||||
|
|
||||||
|
m = None
|
||||||
|
|
||||||
if kwargs["download"]:
|
if kwargs["download"]:
|
||||||
download_from_github(path, tests_root)
|
download_from_github(path, tests_root)
|
||||||
|
|
||||||
manifest.load_and_update(tests_root,
|
if not kwargs.get("rebuild", False):
|
||||||
path,
|
try:
|
||||||
kwargs["url_base"],
|
m = manifest.load(tests_root, path)
|
||||||
update=True,
|
except manifest.ManifestVersionMismatch:
|
||||||
rebuild=kwargs["rebuild"],
|
logger.info("Manifest version changed, rebuilding")
|
||||||
cache_root=kwargs["cache_root"],
|
m = None
|
||||||
working_copy=kwargs["work"])
|
|
||||||
|
if m is None:
|
||||||
|
m = manifest.Manifest(kwargs["url_base"])
|
||||||
|
|
||||||
|
changed = update(tests_root,
|
||||||
|
m,
|
||||||
|
working_copy=kwargs["work"])
|
||||||
|
if changed:
|
||||||
|
manifest.write(m, path)
|
||||||
|
|
||||||
|
|
||||||
def abs_path(path):
|
def abs_path(path):
|
||||||
|
@ -67,9 +73,6 @@ def create_parser():
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--no-download", dest="download", action="store_false", default=True,
|
"--no-download", dest="download", action="store_false", default=True,
|
||||||
help="Never attempt to download the manifest.")
|
help="Never attempt to download the manifest.")
|
||||||
parser.add_argument(
|
|
||||||
"--cache-root", action="store", default=os.path.join(wpt_root, ".wptcache"),
|
|
||||||
help="Path in which to store any caches (default <tests_root>/.wptcache/")
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,9 +87,10 @@ def find_top_repo():
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
|
||||||
def run(*args, **kwargs):
|
def run(**kwargs):
|
||||||
if kwargs["path"] is None:
|
if kwargs["path"] is None:
|
||||||
kwargs["path"] = os.path.join(kwargs["tests_root"], "MANIFEST.json")
|
kwargs["path"] = os.path.join(kwargs["tests_root"], "MANIFEST.json")
|
||||||
|
|
||||||
update_from_cli(**kwargs)
|
update_from_cli(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,46 +1,15 @@
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
import platform
|
|
||||||
import stat
|
|
||||||
import subprocess
|
import subprocess
|
||||||
from collections import deque
|
import platform
|
||||||
|
|
||||||
from .sourcefile import SourceFile
|
from .sourcefile import SourceFile
|
||||||
|
|
||||||
|
|
||||||
def get_tree(tests_root, manifest, manifest_path, cache_root,
|
|
||||||
working_copy=False, rebuild=False):
|
|
||||||
tree = None
|
|
||||||
if cache_root is None:
|
|
||||||
cache_root = os.path.join(tests_root, ".wptcache")
|
|
||||||
if not os.path.exists(cache_root):
|
|
||||||
try:
|
|
||||||
os.makedirs(cache_root)
|
|
||||||
except IOError:
|
|
||||||
cache_root = None
|
|
||||||
|
|
||||||
if not working_copy:
|
|
||||||
tree = Git.for_path(tests_root,
|
|
||||||
manifest.url_base,
|
|
||||||
manifest_path=manifest_path,
|
|
||||||
cache_path=cache_root,
|
|
||||||
rebuild=rebuild)
|
|
||||||
if tree is None:
|
|
||||||
tree = FileSystem(tests_root,
|
|
||||||
manifest.url_base,
|
|
||||||
manifest_path=manifest_path,
|
|
||||||
cache_path=cache_root,
|
|
||||||
rebuild=rebuild)
|
|
||||||
return tree
|
|
||||||
|
|
||||||
|
|
||||||
class Git(object):
|
class Git(object):
|
||||||
def __init__(self, repo_root, url_base, cache_path, manifest_path=None,
|
def __init__(self, repo_root, url_base):
|
||||||
rebuild=False):
|
self.root = os.path.abspath(repo_root)
|
||||||
self.root = repo_root
|
|
||||||
self.git = Git.get_func(repo_root)
|
self.git = Git.get_func(repo_root)
|
||||||
self.url_base = url_base
|
self.url_base = url_base
|
||||||
# rebuild is a noop for now since we don't cache anything
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_func(repo_path):
|
def get_func(repo_path):
|
||||||
|
@ -57,11 +26,10 @@ class Git(object):
|
||||||
return git
|
return git
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def for_path(cls, path, url_base, cache_path, manifest_path=None, rebuild=False):
|
def for_path(cls, path, url_base):
|
||||||
git = Git.get_func(path)
|
git = Git.get_func(path)
|
||||||
try:
|
try:
|
||||||
return cls(git("rev-parse", "--show-toplevel").rstrip(), url_base, cache_path,
|
return cls(git("rev-parse", "--show-toplevel").rstrip(), url_base)
|
||||||
manifest_path=manifest_path, rebuild=rebuild)
|
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -106,194 +74,27 @@ class Git(object):
|
||||||
rel_path,
|
rel_path,
|
||||||
self.url_base,
|
self.url_base,
|
||||||
hash,
|
hash,
|
||||||
contents=contents), True
|
contents=contents)
|
||||||
|
|
||||||
def dump_caches(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class FileSystem(object):
|
class FileSystem(object):
|
||||||
def __init__(self, root, url_base, cache_path, manifest_path=None, rebuild=False):
|
def __init__(self, root, url_base):
|
||||||
from gitignore import gitignore
|
self.root = root
|
||||||
self.root = os.path.abspath(root)
|
|
||||||
self.url_base = url_base
|
self.url_base = url_base
|
||||||
self.ignore_cache = None
|
from gitignore import gitignore
|
||||||
self.mtime_cache = None
|
self.path_filter = gitignore.PathFilter(self.root, extras=[".git/"])
|
||||||
if cache_path is not None:
|
|
||||||
if manifest_path is not None:
|
|
||||||
self.mtime_cache = MtimeCache(cache_path, root, manifest_path, rebuild)
|
|
||||||
if gitignore.has_ignore(root):
|
|
||||||
self.ignore_cache = GitIgnoreCache(cache_path, root, rebuild)
|
|
||||||
self.path_filter = gitignore.PathFilter(self.root,
|
|
||||||
extras=[".git/"],
|
|
||||||
cache=self.ignore_cache)
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
mtime_cache = self.mtime_cache
|
paths = self.get_paths()
|
||||||
for dirpath, dirnames, filenames in self.path_filter(walk(self.root)):
|
for path in paths:
|
||||||
for filename, path_stat in filenames:
|
yield SourceFile(self.root, path, self.url_base)
|
||||||
path = os.path.join(dirpath, filename)
|
|
||||||
if mtime_cache is None or mtime_cache.updated(path, path_stat):
|
|
||||||
yield SourceFile(self.root, path, self.url_base), True
|
|
||||||
else:
|
|
||||||
yield path, False
|
|
||||||
|
|
||||||
def dump_caches(self):
|
def get_paths(self):
|
||||||
for cache in [self.mtime_cache, self.ignore_cache]:
|
for dirpath, dirnames, filenames in os.walk(self.root):
|
||||||
if cache is not None:
|
for filename in filenames:
|
||||||
cache.dump()
|
path = os.path.relpath(os.path.join(dirpath, filename), self.root)
|
||||||
|
if self.path_filter(path):
|
||||||
|
yield path
|
||||||
|
|
||||||
|
dirnames[:] = [item for item in dirnames if self.path_filter(
|
||||||
class CacheFile(object):
|
os.path.relpath(os.path.join(dirpath, item), self.root) + "/")]
|
||||||
file_name = None
|
|
||||||
|
|
||||||
def __init__(self, cache_root, tests_root, rebuild=False):
|
|
||||||
self.tests_root = tests_root
|
|
||||||
if not os.path.exists(cache_root):
|
|
||||||
os.makedirs(cache_root)
|
|
||||||
self.path = os.path.join(cache_root, self.file_name)
|
|
||||||
self.modified = False
|
|
||||||
self.data = self.load(rebuild)
|
|
||||||
|
|
||||||
def dump(self):
|
|
||||||
if not self.modified:
|
|
||||||
return
|
|
||||||
with open(self.path, 'w') as f:
|
|
||||||
json.dump(self.data, f, indent=1)
|
|
||||||
|
|
||||||
def load(self, rebuild=False):
|
|
||||||
data = {}
|
|
||||||
try:
|
|
||||||
if not rebuild:
|
|
||||||
with open(self.path, 'r') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
data = self.check_valid(data)
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
return data
|
|
||||||
|
|
||||||
def check_valid(self, data):
|
|
||||||
"""Check if the cached data is valid and return an updated copy of the
|
|
||||||
cache containing only data that can be used."""
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
class MtimeCache(CacheFile):
|
|
||||||
file_name = "mtime.json"
|
|
||||||
|
|
||||||
def __init__(self, cache_root, tests_root, manifest_path, rebuild=False):
|
|
||||||
self.manifest_path = manifest_path
|
|
||||||
super(MtimeCache, self).__init__(cache_root, tests_root, rebuild=False)
|
|
||||||
|
|
||||||
def updated(self, rel_path, stat):
|
|
||||||
"""Return a boolean indicating whether the file changed since the cache was last updated.
|
|
||||||
|
|
||||||
This implicitly updates the cache with the new mtime data."""
|
|
||||||
mtime = stat.st_mtime
|
|
||||||
if mtime != self.data.get(rel_path):
|
|
||||||
self.modified = True
|
|
||||||
self.data[rel_path] = mtime
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_valid(self, data):
|
|
||||||
if data.get("/tests_root") != self.tests_root:
|
|
||||||
self.modified = True
|
|
||||||
else:
|
|
||||||
if self.manifest_path is not None and os.path.exists(self.manifest_path):
|
|
||||||
mtime = os.path.getmtime(self.manifest_path)
|
|
||||||
if data.get("/manifest_path") != [self.manifest_path, mtime]:
|
|
||||||
self.modified = True
|
|
||||||
else:
|
|
||||||
self.modified = True
|
|
||||||
if self.modified:
|
|
||||||
data = {}
|
|
||||||
data["/tests_root"] = self.tests_root
|
|
||||||
return data
|
|
||||||
|
|
||||||
def dump(self):
|
|
||||||
if self.manifest_path is None:
|
|
||||||
raise ValueError
|
|
||||||
if not os.path.exists(self.manifest_path):
|
|
||||||
return
|
|
||||||
mtime = os.path.getmtime(self.manifest_path)
|
|
||||||
self.data["/manifest_path"] = [self.manifest_path, mtime]
|
|
||||||
self.data["/tests_root"] = self.tests_root
|
|
||||||
super(MtimeCache, self).dump()
|
|
||||||
|
|
||||||
|
|
||||||
class GitIgnoreCache(CacheFile):
|
|
||||||
file_name = "gitignore.json"
|
|
||||||
|
|
||||||
def check_valid(self, data):
|
|
||||||
ignore_path = os.path.join(self.tests_root, ".gitignore")
|
|
||||||
mtime = os.path.getmtime(ignore_path)
|
|
||||||
if data.get("/gitignore_file") != [ignore_path, mtime]:
|
|
||||||
self.modified = True
|
|
||||||
data = {}
|
|
||||||
data["/gitignore_file"] = [ignore_path, mtime]
|
|
||||||
return data
|
|
||||||
|
|
||||||
def __contains__(self, key):
|
|
||||||
return key in self.data
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
return self.data[key]
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
if self.data.get(key) != value:
|
|
||||||
self.modified = True
|
|
||||||
self.data[key] = value
|
|
||||||
|
|
||||||
|
|
||||||
def walk(root):
|
|
||||||
"""Re-implementation of os.walk. Returns an iterator over
|
|
||||||
(dirpath, dirnames, filenames), with some semantic differences
|
|
||||||
to os.walk.
|
|
||||||
|
|
||||||
This has a similar interface to os.walk, with the important difference
|
|
||||||
that instead of lists of filenames and directory names, it yields
|
|
||||||
lists of tuples of the form [(name, stat)] where stat is the result of
|
|
||||||
os.stat for the file. That allows reusing the same stat data in the
|
|
||||||
caller. It also always returns the dirpath relative to the root, with
|
|
||||||
the root iself being returned as the empty string.
|
|
||||||
|
|
||||||
Unlike os.walk the implementation is not recursive."""
|
|
||||||
|
|
||||||
listdir = os.listdir
|
|
||||||
get_stat = os.stat
|
|
||||||
listdir = os.listdir
|
|
||||||
join = os.path.join
|
|
||||||
is_dir = stat.S_ISDIR
|
|
||||||
is_link = stat.S_ISLNK
|
|
||||||
relpath = os.path.relpath
|
|
||||||
|
|
||||||
root = os.path.abspath(root)
|
|
||||||
stack = deque([(root, "")])
|
|
||||||
|
|
||||||
while stack:
|
|
||||||
dir_path, rel_path = stack.popleft()
|
|
||||||
try:
|
|
||||||
# Note that listdir and error are globals in this module due
|
|
||||||
# to earlier import-*.
|
|
||||||
names = listdir(dir_path)
|
|
||||||
except OSError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
dirs, non_dirs = [], []
|
|
||||||
for name in names:
|
|
||||||
path = join(dir_path, name)
|
|
||||||
try:
|
|
||||||
path_stat = get_stat(path)
|
|
||||||
except OSError:
|
|
||||||
continue
|
|
||||||
if is_dir(path_stat.st_mode):
|
|
||||||
dirs.append((name, path_stat))
|
|
||||||
else:
|
|
||||||
non_dirs.append((name, path_stat))
|
|
||||||
|
|
||||||
yield rel_path, dirs, non_dirs
|
|
||||||
for name, path_stat in dirs:
|
|
||||||
new_path = join(dir_path, name)
|
|
||||||
if not is_link(path_stat.st_mode):
|
|
||||||
stack.append((new_path, relpath(new_path, root)))
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import sys
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
from ..manifest import manifest
|
from ..manifest import manifest, update
|
||||||
|
|
||||||
here = os.path.dirname(__file__)
|
here = os.path.dirname(__file__)
|
||||||
wpt_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir))
|
wpt_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir))
|
||||||
|
@ -190,8 +190,10 @@ def _init_manifest_cache():
|
||||||
return c[manifest_path]
|
return c[manifest_path]
|
||||||
# cache at most one path:manifest
|
# cache at most one path:manifest
|
||||||
c.clear()
|
c.clear()
|
||||||
wpt_manifest = manifest.load_and_update(wpt_root, manifest_path, "/",
|
wpt_manifest = manifest.load(wpt_root, manifest_path)
|
||||||
update=True)
|
if wpt_manifest is None:
|
||||||
|
wpt_manifest = manifest.Manifest()
|
||||||
|
update.update(wpt_root, wpt_manifest)
|
||||||
c[manifest_path] = wpt_manifest
|
c[manifest_path] = wpt_manifest
|
||||||
return c[manifest_path]
|
return c[manifest_path]
|
||||||
return load
|
return load
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import urlparse
|
import urlparse
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
@ -366,7 +367,6 @@ class TestFilter(object):
|
||||||
if include_tests:
|
if include_tests:
|
||||||
yield test_type, test_path, include_tests
|
yield test_type, test_path, include_tests
|
||||||
|
|
||||||
|
|
||||||
class TagFilter(object):
|
class TagFilter(object):
|
||||||
def __init__(self, tags):
|
def __init__(self, tags):
|
||||||
self.tags = set(tags)
|
self.tags = set(tags)
|
||||||
|
@ -378,8 +378,7 @@ class TagFilter(object):
|
||||||
|
|
||||||
|
|
||||||
class ManifestLoader(object):
|
class ManifestLoader(object):
|
||||||
def __init__(self, test_paths, force_manifest_update=False, manifest_download=False,
|
def __init__(self, test_paths, force_manifest_update=False, manifest_download=False, types=None, meta_filters=None):
|
||||||
types=None, meta_filters=None):
|
|
||||||
do_delayed_imports()
|
do_delayed_imports()
|
||||||
self.test_paths = test_paths
|
self.test_paths = test_paths
|
||||||
self.force_manifest_update = force_manifest_update
|
self.force_manifest_update = force_manifest_update
|
||||||
|
@ -400,12 +399,57 @@ class ManifestLoader(object):
|
||||||
rv[manifest_file] = path_data
|
rv[manifest_file] = path_data
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
def load_manifest(self, tests_path, manifest_path, metadata_path, url_base="/", **kwargs):
|
def create_manifest(self, manifest_path, tests_path, url_base="/"):
|
||||||
cache_root = os.path.join(metadata_path, ".cache")
|
self.update_manifest(manifest_path, tests_path, url_base, recreate=True,
|
||||||
if self.manifest_download:
|
download=self.manifest_download)
|
||||||
|
|
||||||
|
def update_manifest(self, manifest_path, tests_path, url_base="/",
|
||||||
|
recreate=False, download=False):
|
||||||
|
self.logger.info("Updating test manifest %s" % manifest_path)
|
||||||
|
manifest_log.setup()
|
||||||
|
|
||||||
|
json_data = None
|
||||||
|
if download:
|
||||||
|
# TODO: make this not github-specific
|
||||||
download_from_github(manifest_path, tests_path)
|
download_from_github(manifest_path, tests_path)
|
||||||
return manifest.load_and_update(tests_path, manifest_path, url_base,
|
|
||||||
cache_root=cache_root, update=self.force_manifest_update)
|
if not recreate:
|
||||||
|
try:
|
||||||
|
with open(manifest_path) as f:
|
||||||
|
json_data = json.load(f)
|
||||||
|
except IOError:
|
||||||
|
self.logger.info("Unable to find test manifest")
|
||||||
|
except ValueError:
|
||||||
|
self.logger.info("Unable to parse test manifest")
|
||||||
|
|
||||||
|
if not json_data:
|
||||||
|
self.logger.info("Creating test manifest")
|
||||||
|
manifest_file = manifest.Manifest(url_base)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
manifest_file = manifest.Manifest.from_json(tests_path, json_data)
|
||||||
|
except manifest.ManifestVersionMismatch:
|
||||||
|
manifest_file = manifest.Manifest(url_base)
|
||||||
|
|
||||||
|
manifest_update.update(tests_path, manifest_file, True)
|
||||||
|
|
||||||
|
manifest.write(manifest_file, manifest_path)
|
||||||
|
|
||||||
|
def load_manifest(self, tests_path, manifest_path, url_base="/", **kwargs):
|
||||||
|
if (not os.path.exists(manifest_path) or
|
||||||
|
self.force_manifest_update):
|
||||||
|
self.update_manifest(manifest_path, tests_path, url_base, download=self.manifest_download)
|
||||||
|
try:
|
||||||
|
manifest_file = manifest.load(tests_path, manifest_path, types=self.types, meta_filters=self.meta_filters)
|
||||||
|
except manifest.ManifestVersionMismatch:
|
||||||
|
manifest_file = manifest.Manifest(url_base)
|
||||||
|
if manifest_file.url_base != url_base:
|
||||||
|
self.logger.info("Updating url_base in manifest from %s to %s" % (manifest_file.url_base,
|
||||||
|
url_base))
|
||||||
|
manifest_file.url_base = url_base
|
||||||
|
manifest.write(manifest_file, manifest_path)
|
||||||
|
|
||||||
|
return manifest_file
|
||||||
|
|
||||||
|
|
||||||
def iterfilter(filters, iter):
|
def iterfilter(filters, iter):
|
||||||
|
@ -465,12 +509,12 @@ class TestLoader(object):
|
||||||
self._test_ids += [item.id for item in test_dict[test_type]]
|
self._test_ids += [item.id for item in test_dict[test_type]]
|
||||||
return self._test_ids
|
return self._test_ids
|
||||||
|
|
||||||
def get_test(self, manifest_file, manifest_test, inherit_metadata, test_metadata):
|
def get_test(self, manifest_test, inherit_metadata, test_metadata):
|
||||||
if test_metadata is not None:
|
if test_metadata is not None:
|
||||||
inherit_metadata.append(test_metadata)
|
inherit_metadata.append(test_metadata)
|
||||||
test_metadata = test_metadata.get_test(manifest_test.id)
|
test_metadata = test_metadata.get_test(manifest_test.id)
|
||||||
|
|
||||||
return wpttest.from_manifest(manifest_file, manifest_test, inherit_metadata, test_metadata)
|
return wpttest.from_manifest(manifest_test, inherit_metadata, test_metadata)
|
||||||
|
|
||||||
def load_dir_metadata(self, test_manifest, metadata_path, test_path):
|
def load_dir_metadata(self, test_manifest, metadata_path, test_path):
|
||||||
rv = []
|
rv = []
|
||||||
|
@ -493,29 +537,27 @@ class TestLoader(object):
|
||||||
|
|
||||||
def iter_tests(self):
|
def iter_tests(self):
|
||||||
manifest_items = []
|
manifest_items = []
|
||||||
manifests_by_url_base = {}
|
|
||||||
|
|
||||||
for manifest in sorted(self.manifests.keys(), key=lambda x:x.url_base):
|
for manifest in sorted(self.manifests.keys(), key=lambda x:x.url_base):
|
||||||
manifest_iter = iterfilter(self.manifest_filters,
|
manifest_iter = iterfilter(self.manifest_filters,
|
||||||
manifest.itertypes(*self.test_types))
|
manifest.itertypes(*self.test_types))
|
||||||
manifest_items.extend(manifest_iter)
|
manifest_items.extend(manifest_iter)
|
||||||
manifests_by_url_base[manifest.url_base] = manifest
|
|
||||||
|
|
||||||
if self.chunker is not None:
|
if self.chunker is not None:
|
||||||
manifest_items = self.chunker(manifest_items)
|
manifest_items = self.chunker(manifest_items)
|
||||||
|
|
||||||
for test_type, test_path, tests in manifest_items:
|
for test_type, test_path, tests in manifest_items:
|
||||||
manifest_file = manifests_by_url_base[iter(tests).next().url_base]
|
manifest_file = iter(tests).next().manifest
|
||||||
metadata_path = self.manifests[manifest_file]["metadata_path"]
|
metadata_path = self.manifests[manifest_file]["metadata_path"]
|
||||||
inherit_metadata, test_metadata = self.load_metadata(manifest_file, metadata_path, test_path)
|
inherit_metadata, test_metadata = self.load_metadata(manifest_file, metadata_path, test_path)
|
||||||
|
|
||||||
for test in iterfilter(self.meta_filters,
|
for test in iterfilter(self.meta_filters,
|
||||||
self.iter_wpttest(manifest_file, inherit_metadata, test_metadata, tests)):
|
self.iter_wpttest(inherit_metadata, test_metadata, tests)):
|
||||||
yield test_path, test_type, test
|
yield test_path, test_type, test
|
||||||
|
|
||||||
def iter_wpttest(self, manifest_file, inherit_metadata, test_metadata, tests):
|
def iter_wpttest(self, inherit_metadata, test_metadata, tests):
|
||||||
for manifest_test in tests:
|
for manifest_test in tests:
|
||||||
yield self.get_test(manifest_file, manifest_test, inherit_metadata, test_metadata)
|
yield self.get_test(manifest_test, inherit_metadata, test_metadata)
|
||||||
|
|
||||||
def _load_tests(self):
|
def _load_tests(self):
|
||||||
"""Read in the tests from the manifest file and add them to a queue"""
|
"""Read in the tests from the manifest file and add them to a queue"""
|
||||||
|
|
|
@ -98,7 +98,7 @@ def create_test_manifest(tests, url_base="/"):
|
||||||
source_files = []
|
source_files = []
|
||||||
for i, (test, _, test_type, _) in enumerate(tests):
|
for i, (test, _, test_type, _) in enumerate(tests):
|
||||||
if test_type:
|
if test_type:
|
||||||
source_files.append((SourceFileWithTest(test, str(i) * 40, item_classes[test_type]), True))
|
source_files.append(SourceFileWithTest(test, str(i) * 40, item_classes[test_type]))
|
||||||
m = manifest.Manifest()
|
m = manifest.Manifest()
|
||||||
m.update(source_files)
|
m.update(source_files)
|
||||||
return m
|
return m
|
||||||
|
|
|
@ -60,7 +60,7 @@ def test_metadata_inherit():
|
||||||
url_base="")
|
url_base="")
|
||||||
|
|
||||||
test = tests[0][2].pop()
|
test = tests[0][2].pop()
|
||||||
test_obj = wpttest.from_manifest(tests, test, inherit_metadata, test_metadata.get_test(test.id))
|
test_obj = wpttest.from_manifest(test, inherit_metadata, test_metadata.get_test(test.id))
|
||||||
assert test_obj.max_assertion_count == 3
|
assert test_obj.max_assertion_count == 3
|
||||||
assert test_obj.min_assertion_count == 1
|
assert test_obj.min_assertion_count == 1
|
||||||
assert test_obj.prefs == {"b": "c", "c": "d"}
|
assert test_obj.prefs == {"b": "c", "c": "d"}
|
||||||
|
@ -78,7 +78,7 @@ def test_conditional():
|
||||||
url_base="")
|
url_base="")
|
||||||
|
|
||||||
test = tests[1][2].pop()
|
test = tests[1][2].pop()
|
||||||
test_obj = wpttest.from_manifest(tests, test, [], test_metadata.get_test(test.id))
|
test_obj = wpttest.from_manifest(test, [], test_metadata.get_test(test.id))
|
||||||
assert test_obj.prefs == {"a": "b", "c": "d"}
|
assert test_obj.prefs == {"a": "b", "c": "d"}
|
||||||
assert test_obj.expected() == "FAIL"
|
assert test_obj.expected() == "FAIL"
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ class Test(object):
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_manifest(cls, manifest_file, manifest_item, inherit_metadata, test_metadata):
|
def from_manifest(cls, manifest_item, inherit_metadata, test_metadata):
|
||||||
timeout = cls.long_timeout if manifest_item.timeout == "long" else cls.default_timeout
|
timeout = cls.long_timeout if manifest_item.timeout == "long" else cls.default_timeout
|
||||||
protocol = "https" if hasattr(manifest_item, "https") and manifest_item.https else "http"
|
protocol = "https" if hasattr(manifest_item, "https") and manifest_item.https else "http"
|
||||||
return cls(manifest_item.source_file.tests_root,
|
return cls(manifest_item.source_file.tests_root,
|
||||||
|
@ -302,7 +302,7 @@ class TestharnessTest(Test):
|
||||||
self.scripts = scripts or []
|
self.scripts = scripts or []
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_manifest(cls, manifest_file, manifest_item, inherit_metadata, test_metadata):
|
def from_manifest(cls, manifest_item, inherit_metadata, test_metadata):
|
||||||
timeout = cls.long_timeout if manifest_item.timeout == "long" else cls.default_timeout
|
timeout = cls.long_timeout if manifest_item.timeout == "long" else cls.default_timeout
|
||||||
protocol = "https" if hasattr(manifest_item, "https") and manifest_item.https else "http"
|
protocol = "https" if hasattr(manifest_item, "https") and manifest_item.https else "http"
|
||||||
testdriver = manifest_item.testdriver if hasattr(manifest_item, "testdriver") else False
|
testdriver = manifest_item.testdriver if hasattr(manifest_item, "testdriver") else False
|
||||||
|
@ -352,7 +352,6 @@ class ReftestTest(Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_manifest(cls,
|
def from_manifest(cls,
|
||||||
manifest_file,
|
|
||||||
manifest_test,
|
manifest_test,
|
||||||
inherit_metadata,
|
inherit_metadata,
|
||||||
test_metadata,
|
test_metadata,
|
||||||
|
@ -395,10 +394,9 @@ class ReftestTest(Test):
|
||||||
|
|
||||||
references_seen.add(comparison_key)
|
references_seen.add(comparison_key)
|
||||||
|
|
||||||
manifest_node = manifest_file.get_reference(ref_url)
|
manifest_node = manifest_test.manifest.get_reference(ref_url)
|
||||||
if manifest_node:
|
if manifest_node:
|
||||||
reference = ReftestTest.from_manifest(manifest_file,
|
reference = ReftestTest.from_manifest(manifest_node,
|
||||||
manifest_node,
|
|
||||||
[],
|
[],
|
||||||
None,
|
None,
|
||||||
nodes,
|
nodes,
|
||||||
|
@ -450,6 +448,6 @@ manifest_test_cls = {"reftest": ReftestTest,
|
||||||
"wdspec": WdspecTest}
|
"wdspec": WdspecTest}
|
||||||
|
|
||||||
|
|
||||||
def from_manifest(manifest_file, manifest_test, inherit_metadata, test_metadata):
|
def from_manifest(manifest_test, inherit_metadata, test_metadata):
|
||||||
test_cls = manifest_test_cls[manifest_test.item_type]
|
test_cls = manifest_test_cls[manifest_test.item_type]
|
||||||
return test_cls.from_manifest(manifest_file, manifest_test, inherit_metadata, test_metadata)
|
return test_cls.from_manifest(manifest_test, inherit_metadata, test_metadata)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче