pw_cli: Move exclude_paths

Moves exclude_paths() from pw_presubmit to pw_cli.

Change-Id: I356d21689e8cb494f08a34254b1214a20987d0b4
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/252293
Docs-Not-Needed: Armando Montanez <amontanez@google.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
Commit-Queue: Armando Montanez <amontanez@google.com>
Reviewed-by: Rob Mohr <mohrr@google.com>
diff --git a/pw_cli/py/pw_cli/file_filter.py b/pw_cli/py/pw_cli/file_filter.py
index 56ab835..040a571 100644
--- a/pw_cli/py/pw_cli/file_filter.py
+++ b/pw_cli/py/pw_cli/file_filter.py
@@ -13,6 +13,7 @@
 # the License.
 """Class for describing file filter patterns."""
 
+import os
 from pathlib import Path
 import re
 from typing import Pattern, Iterable, Sequence
@@ -79,3 +80,24 @@
 
     def filter(self, paths: Sequence[str | Path]) -> Sequence[Path]:
         return [Path(x) for x in paths if self.matches(x)]
+
+
+def exclude_paths(
+    exclusions: Iterable[Pattern[str]],
+    paths: Iterable[Path],
+    relative_to: Path | None = None,
+) -> Iterable[Path]:
+    """Excludes paths based on a series of regular expressions."""
+    if relative_to:
+
+        def relpath(path):
+            return Path(os.path.relpath(path, relative_to))
+
+    else:
+
+        def relpath(path):
+            return path
+
+    for path in paths:
+        if not any(e.search(relpath(path).as_posix()) for e in exclusions):
+            yield path
diff --git a/pw_presubmit/py/pw_presubmit/format_code.py b/pw_presubmit/py/pw_presubmit/format_code.py
index ed0fa83..b54c222 100755
--- a/pw_presubmit/py/pw_presubmit/format_code.py
+++ b/pw_presubmit/py/pw_presubmit/format_code.py
@@ -44,7 +44,7 @@
 import pw_cli.color
 from pw_cli.diff import colorize_diff
 import pw_cli.env
-from pw_cli.file_filter import FileFilter
+from pw_cli.file_filter import FileFilter, exclude_paths
 from pw_cli.plural import plural
 import pw_env_setup.config_file
 from pw_presubmit.presubmit import filter_paths
@@ -66,7 +66,6 @@
 from pw_presubmit.format.gn import GnFormatter
 from pw_presubmit.format.python import BlackFormatter
 from pw_presubmit.tools import (
-    exclude_paths,
     file_summary,
     log_run,
     PresubmitToolRunner,
diff --git a/pw_presubmit/py/pw_presubmit/keep_sorted.py b/pw_presubmit/py/pw_presubmit/keep_sorted.py
index 793f2ea..0a9fa2c 100644
--- a/pw_presubmit/py/pw_presubmit/keep_sorted.py
+++ b/pw_presubmit/py/pw_presubmit/keep_sorted.py
@@ -30,8 +30,9 @@
 
 import pw_cli
 from pw_cli.diff import colorize_diff
+from pw_cli.file_filter import exclude_paths
 from pw_cli.plural import plural
-from . import cli, git_repo, presubmit, presubmit_context, tools
+from . import cli, git_repo, presubmit, presubmit_context
 
 DEFAULT_PATH = Path('out', 'presubmit', 'keep_sorted')
 
@@ -455,7 +456,7 @@
 
         # Add files from Git and remove duplicates.
         files = sorted(
-            set(tools.exclude_paths(exclude, git_repo.list_files(base, paths)))
+            set(exclude_paths(exclude, git_repo.list_files(base, paths)))
             | set(files)
         )
     elif base:
diff --git a/pw_presubmit/py/pw_presubmit/presubmit.py b/pw_presubmit/py/pw_presubmit/presubmit.py
index 5b14825..76ca274 100644
--- a/pw_presubmit/py/pw_presubmit/presubmit.py
+++ b/pw_presubmit/py/pw_presubmit/presubmit.py
@@ -71,7 +71,7 @@
 import pw_cli.color
 import pw_cli.env
 from pw_cli.plural import plural
-from pw_cli.file_filter import FileFilter
+from pw_cli.file_filter import FileFilter, exclude_paths
 from pw_package import package_manager
 from pw_presubmit import git_repo, tools
 from pw_presubmit.presubmit_context import (
@@ -576,16 +576,14 @@
     modified_files: list[Path] = []
 
     all_files_repo = tuple(
-        tools.exclude_paths(
-            exclude, git_repo.list_files(None, pathspecs, repo), root
-        )
+        exclude_paths(exclude, git_repo.list_files(None, pathspecs, repo), root)
     )
     all_files += all_files_repo
 
     if base is None:
         modified_files += all_files_repo
     else:
-        modified_files += tools.exclude_paths(
+        modified_files += exclude_paths(
             exclude, git_repo.list_files(base, pathspecs, repo), root
         )
 
diff --git a/pw_presubmit/py/pw_presubmit/tools.py b/pw_presubmit/py/pw_presubmit/tools.py
index 14640d4..9376573 100644
--- a/pw_presubmit/py/pw_presubmit/tools.py
+++ b/pw_presubmit/py/pw_presubmit/tools.py
@@ -25,7 +25,6 @@
     Iterable,
     Iterator,
     Sequence,
-    Pattern,
 )
 
 from pw_cli.plural import plural
@@ -126,27 +125,6 @@
         yield Path(os.path.relpath(path, start))
 
 
-def exclude_paths(
-    exclusions: Iterable[Pattern[str]],
-    paths: Iterable[Path],
-    relative_to: Path | None = None,
-) -> Iterable[Path]:
-    """Excludes paths based on a series of regular expressions."""
-    if relative_to:
-
-        def relpath(path):
-            return Path(os.path.relpath(path, relative_to))
-
-    else:
-
-        def relpath(path):
-            return path
-
-    for path in paths:
-        if not any(e.search(relpath(path).as_posix()) for e in exclusions):
-            yield path
-
-
 def _truncate(value, length: int = 60) -> str:
     value = str(value)
     return (value[: length - 5] + '[...]') if len(value) > length else value