dependency: relevancy check should account for directories.

Relevancy checks were being done based on the matching of file paths.
Use prefix-based matching to account for directories in the package's
dependent source paths.

BUG=chromium:1111319
TEST=./run_pytest

Change-Id: I78f16366df0cd24b5d1600433f16ffd3d3d3a006
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/2383480
Commit-Queue: Navil Perez <navil@google.com>
Tested-by: Navil Perez <navil@google.com>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Sean Abraham <seanabraham@chromium.org>
diff --git a/service/dependency.py b/service/dependency.py
index a2cdf54..84a7d70 100644
--- a/service/dependency.py
+++ b/service/dependency.py
@@ -8,6 +8,7 @@
 from __future__ import print_function
 
 import os
+from pathlib import Path
 import re
 from typing import List, Optional
 
@@ -358,6 +359,30 @@
   return results, sdk_results
 
 
+def determine_package_relevance(dep_src_paths: List[str],
+                                src_paths: Optional[List[str]] = None) -> bool:
+  """Determine if the package is relevant to the given source paths.
+
+  A package is relevant if any of its dependent source paths is in the given
+  list of source paths. If no source paths are given, the default is True.
+
+  Args:
+    dep_src_paths: List of source paths the package depends on.
+    src_paths: List of source paths of interest.
+  """
+  if not src_paths:
+    return True
+  for src_path in (Path(x) for x in src_paths):
+    for dep_src_path in (Path(x) for x in dep_src_paths):
+      try:
+        # Will throw an error if src_path isn't under dep_src_path.
+        src_path.relative_to(dep_src_path)
+        return True
+      except ValueError:
+        pass
+  return False
+
+
 def GetDependencies(sysroot_path: str,
                     build_target: build_target_lib.BuildTarget,
                     src_paths: Optional[List[str]] = None,
@@ -381,7 +406,7 @@
 
   relevant_packages = set()
   for cpv, dep_src_paths in json_deps['source_path_mapping'].items():
-    if not src_paths or (set(dep_src_paths) & set(src_paths)):
+    if determine_package_relevance(dep_src_paths, src_paths):
       relevant_packages.add(cpv)
 
   relevant_package_deps = set()
diff --git a/service/dependency_unittest.py b/service/dependency_unittest.py
index 89fb325..76edd51 100644
--- a/service/dependency_unittest.py
+++ b/service/dependency_unittest.py
@@ -110,6 +110,27 @@
           dependency.NormalizeSourcePaths([foo_dir, ab_cd_file, bar_baz_dir]),
           expected_paths)
 
+  def testDeterminePackageRelevanceNotRelevant(self):
+    """Test determine_package_relevance with no matching paths."""
+    src_paths = ['foo/bar/baz', 'foo/bar/b', 'foo/bar', 'bar/foo']
+    dep_src_paths = ['foo/bar/ba']
+    self.assertFalse(
+        dependency.determine_package_relevance(dep_src_paths, src_paths))
+
+  def testDeterminePackageRelevanceExactMatch(self):
+    """Test determine_package_relevance given an exact match."""
+    src_paths = ['foo/bar/baz']
+    dep_src_paths = ['foo/bar/baz']
+    self.assertTrue(
+        dependency.determine_package_relevance(dep_src_paths, src_paths))
+
+  def testDeterminePackageRelevanceDirectoryMatch(self):
+    """Test determine_package_relevance given a directory match."""
+    src_paths = ['foo/bar/baz']
+    dep_src_paths = ['foo/bar']
+    self.assertTrue(
+        dependency.determine_package_relevance(dep_src_paths, src_paths))
+
   def testGetDependenciesWithDefaultArgs(self):
     """Test GetDependencies using the default args."""
     self.PatchObject(