# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import functools
from pathlib
import Path
from gecko_taskgraph
import GECKO
@functools.cache
def _get_taskgraph_sparse_profile():
"""
Parse the taskgraph sparse profile
and return the paths
and globs it includes.
"""
# We need this nested function to handle %include directives recursively
def parse(profile_path):
paths = set()
globs = set()
full_path = Path(GECKO) / profile_path
if not full_path.exists():
raise FileNotFoundError(
f
"Sparse profile '{full_path.stem}' not found at {full_path}"
)
for raw_line
in full_path.read_text().splitlines():
line = raw_line.strip()
if not line
or line.startswith(
"#") or line.startswith("["):
continue
if line.startswith(
"%include "):
included_profile = line[len(
"%include ") :].strip()
included_paths, included_globs = parse(included_profile)
paths.update(included_paths)
globs.update(included_globs)
elif line.startswith(
"path:"):
path = line[len(
"path:") :].strip()
paths.add(Path(path))
elif line.startswith(
"glob:"):
glob = line[len(
"glob:") :].strip()
globs.add(glob)
return paths, globs
return parse(
"build/sparse-profiles/taskgraph")
@functools.cache
def is_path_covered_by_taskgraph_sparse_profile(path):
"""
Check
if a given path would be included
in the taskgraph sparse checkout.
"""
profile_paths, profile_globs = _get_taskgraph_sparse_profile()
path = Path(path)
for profile_path
in profile_paths:
if path == profile_path
or profile_path
in path.parents:
return True
# Path.match requires at least one directory for ** patterns to match
# root-level files, so we prepend a fake parent directory
path_with_parent = Path(
"_", path)
for pattern
in profile_globs:
if path_with_parent.match(pattern):
return True
return False