Optimize methods in detect_root.bzl (#591)

* Faster method for detecting root

* Implement filter without sort

* Add comments
This commit is contained in:
David Marcin 2021-03-29 17:34:01 -07:00 committed by GitHub
parent 322732bef7
commit bae11c9a50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 9 additions and 50 deletions

View File

@ -16,53 +16,17 @@ def detect_root(source):
return "" return ""
root = None root = None
level = -1
# find topmost directory # Find topmost directory by searching for the file.dirname that is a
# prefix of all other files.
for file in sources: for file in sources:
file_level = _get_level(file.path) if root == None or root.startswith(file.dirname):
root = file.dirname
# If there is no level set or the current file's level
# is greather than what we have logged, update the root
if level == -1 or level > file_level:
root = file
level = file_level
if not root: if not root:
fail("No root source or directory was found") fail("No root source or directory was found")
if root.is_source: return root
return root.dirname
# Note this code path will never be hit due to a bug upstream Bazel
# https://github.com/bazelbuild/bazel/issues/12954
# If the root is not a source file, it must be a directory.
# Thus the path is returned
return root.path
def _get_level(path):
"""Determine the number of sub directories `path` is contained in
Args:
path (string): The target path
Returns:
int: The directory depth of `path`
"""
normalized = path
# This for loop ensures there are no double `//` substrings.
# A for loop is used because there's not currently a `while`
# or a better mechanism for guaranteeing all `//` have been
# cleaned up.
for i in range(len(path)):
new_normalized = normalized.replace("//", "/")
if len(new_normalized) == len(normalized):
break
normalized = new_normalized
return normalized.count("/")
# buildifier: disable=function-docstring-header # buildifier: disable=function-docstring-header
# buildifier: disable=function-docstring-args # buildifier: disable=function-docstring-args
@ -74,12 +38,7 @@ def filter_containing_dirs_from_inputs(input_files_list):
The parent directories will be created for us in the execroot anyway, The parent directories will be created for us in the execroot anyway,
so we filter them out.""" so we filter them out."""
# This puts directories in front of their children in list # Find all the directories that have at least one file or dir inside them.
sorted_list = sorted(input_files_list) populated_dirs = {f.dirname: None for f in input_files_list}
contains_map = {} # Filter out any files which are members of populated_dirs.
for input in input_files_list: return [f for f in input_files_list if f.path not in populated_dirs]
# If the immediate parent directory is already in the list, remove it
if contains_map.get(input.dirname):
contains_map.pop(input.dirname)
contains_map[input.path] = input
return contains_map.values()