import abc import os import stat from collections import deque from os import stat_result from typing import (Any, Dict, Iterable, Iterator, List, MutableMapping, Optional, Set, Text, Tuple,
TYPE_CHECKING)
from . import jsonlib from .utils import git
# Cannot do `from ..gitignore import gitignore` because # relative import beyond toplevel throws *ImportError*! from gitignore import gitignore # type: ignore
if TYPE_CHECKING: from .manifest import Manifest # avoid cyclic import
if tree isNone:
tree = FileSystem(tests_root,
manifest.url_base,
manifest_path=manifest_path,
cache_path=cache_root,
paths_to_update=paths_to_update,
rebuild=rebuild,
) return tree
def _local_changes(self) -> Set[Text]: """get a set of files which have changed between HEAD and working copy""" assert self.git isnotNone # note that git runs the command with tests_root as the cwd, which may # not be the root of the git repo (e.g., within a browser repo) # # `git diff-index --relative` without a path still compares all tracked # files before non-WPT files are filtered out, which can be slow in # vendor repos. Explicitly pass the CWD (i.e., `tests_root`) as a path # argument to avoid unnecessary diffing.
cmd = ["diff-index", "--relative", "--no-renames", "--name-only", "-z", "HEAD", os.curdir]
data = self.git(*cmd) return set(data.split("\0"))
def hash_cache(self) -> Dict[Text, Optional[Text]]: """
A dict of rel_path -> current git object id if the working tree matches HEAD elseNone """
hash_cache: Dict[Text, Optional[Text]] = {}
if self.git isNone: return hash_cache
# note that git runs the command with tests_root as the cwd, which may # not be the root of the git repo (e.g., within a browser repo)
cmd = ["ls-tree", "-r", "-z", "HEAD"]
local_changes = self._local_changes() for result in self.git(*cmd).split("\0")[:-1]: # type: Text
data, rel_path = result.rsplit("\t", 1)
hash_cache[rel_path] = Noneif rel_path in local_changes else data.split(" ", 3)[2]
def dump(self) -> None: ifnot self.modified: return with open(self.path, 'w') as f:
jsonlib.dump_local(self.data, f)
def load(self, rebuild: bool = False) -> Dict[Text, Any]:
data: Dict[Text, Any] = {} try: ifnot rebuild: with open(self.path) as f: try:
data = jsonlib.load(f) except ValueError: pass
data = self.check_valid(data) except OSError: pass return data
def check_valid(self, data: Dict[Text, Any]) -> Dict[Text, Any]: """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 updated(self, rel_path: Text, stat: stat_result) -> bool: """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 returnTrue returnFalse
def check_valid(self, data: Dict[Any, Any]) -> Dict[Any, Any]: if data.get("/tests_root") != self.tests_root:
self.modified = True else: if self.manifest_path isnotNoneand 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 __iter__(self) -> Iterator[bytes]: return (key.encode("utf-8") for key in self.data)
def __len__(self) -> int: return len(self.data)
def walk(root: bytes) -> Iterable[Tuple[bytes, List[Tuple[bytes, stat_result]], List[Tuple[bytes, stat_result]]]]: """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 isnot recursive."""
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) ifnot is_link(path_stat.st_mode):
stack.append((new_path, relpath(new_path, root)))
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.