Repository: pantsbuild/pants

Issue:
filespecs don't respect --pants-ignore for ignored BUILD files
Repro at https://github.com/illicitonion/pants-glob-repro


Discussion:
Thanks for the repro.

Resolving patch:
diff --git a/src/python/pants/base/specs.py b/src/python/pants/base/specs.py
--- a/src/python/pants/base/specs.py
+++ b/src/python/pants/base/specs.py
@@ -450,27 +450,33 @@ def ignores(self) -> Tuple[FilesystemIgnoreSpec, ...]:
         return tuple(spec for spec in self.dependencies if isinstance(spec, FilesystemIgnoreSpec))
 
     @staticmethod
-    def _generate_path_globs(specs: Iterable[FilesystemSpec]) -> PathGlobs:
+    def _generate_path_globs(
+        specs: Iterable[FilesystemSpec], glob_match_error_behavior: GlobMatchErrorBehavior
+    ) -> PathGlobs:
         return PathGlobs(
             globs=(s.to_spec_string() for s in specs),
-            # We error on unmatched globs for consistency with unmatched address specs. This also
-            # ensures that scripts don't silently do the wrong thing.
-            glob_match_error_behavior=GlobMatchErrorBehavior.error,
+            glob_match_error_behavior=glob_match_error_behavior,
             # We validate that _every_ glob is valid.
             conjunction=GlobExpansionConjunction.all_match,
-            description_of_origin="file arguments",
+            description_of_origin=(
+                None
+                if glob_match_error_behavior == GlobMatchErrorBehavior.ignore
+                else "file arguments"
+            ),
         )
 
     def path_globs_for_spec(
-        self, spec: Union[FilesystemLiteralSpec, FilesystemGlobSpec]
+        self,
+        spec: Union[FilesystemLiteralSpec, FilesystemGlobSpec],
+        glob_match_error_behavior: GlobMatchErrorBehavior,
     ) -> PathGlobs:
         """Generate PathGlobs for the specific spec, automatically including the instance's
         FilesystemIgnoreSpecs."""
-        return self._generate_path_globs(specs=(spec, *self.ignores))
+        return self._generate_path_globs((spec, *self.ignores), glob_match_error_behavior)
 
-    def to_path_globs(self) -> PathGlobs:
+    def to_path_globs(self, glob_match_error_behavior: GlobMatchErrorBehavior) -> PathGlobs:
         """Generate a single PathGlobs for the instance."""
-        return self._generate_path_globs(specs=(*self.includes, *self.ignores))
+        return self._generate_path_globs((*self.includes, *self.ignores), glob_match_error_behavior)
 
 
 class AmbiguousSpecs(Exception):
diff --git a/src/python/pants/engine/legacy/graph.py b/src/python/pants/engine/legacy/graph.py
--- a/src/python/pants/engine/legacy/graph.py
+++ b/src/python/pants/engine/legacy/graph.py
@@ -878,10 +878,15 @@ async def sources_snapshots_from_address_specs(address_specs: AddressSpecs) -> S
 
 @rule
 async def sources_snapshots_from_filesystem_specs(
-    filesystem_specs: FilesystemSpecs,
+    filesystem_specs: FilesystemSpecs, global_options: GlobalOptions,
 ) -> SourcesSnapshots:
     """Resolve the snapshot associated with the provided filesystem specs."""
-    snapshot = await Get[Snapshot](PathGlobs, filesystem_specs.to_path_globs())
+    snapshot = await Get[Snapshot](
+        PathGlobs,
+        filesystem_specs.to_path_globs(
+            global_options.options.owners_not_found_behavior.to_glob_match_error_behavior()
+        ),
+    )
     return SourcesSnapshots([SourcesSnapshot(snapshot)])
 
 
@@ -896,7 +901,10 @@ async def addresses_with_origins_from_filesystem_specs(
     FilesystemMergedSpec.
     """
     pathglobs_per_include = (
-        filesystem_specs.path_globs_for_spec(spec) for spec in filesystem_specs.includes
+        filesystem_specs.path_globs_for_spec(
+            spec, global_options.options.owners_not_found_behavior.to_glob_match_error_behavior(),
+        )
+        for spec in filesystem_specs.includes
     )
     snapshot_per_include = await MultiGet(
         Get[Snapshot](PathGlobs, pg) for pg in pathglobs_per_include
diff --git a/src/python/pants/option/global_options.py b/src/python/pants/option/global_options.py
--- a/src/python/pants/option/global_options.py
+++ b/src/python/pants/option/global_options.py
@@ -64,6 +64,9 @@ class OwnersNotFoundBehavior(Enum):
     warn = "warn"
     error = "error"
 
+    def to_glob_match_error_behavior(self) -> GlobMatchErrorBehavior:
+        return GlobMatchErrorBehavior(self.value)
+
 
 class BuildFileImportsBehavior(Enum):
     warn = "warn"


Test patch:
diff --git a/tests/python/pants_test/engine/legacy/test_filesystem_specs_integration.py b/tests/python/pants_test/engine/legacy/test_filesystem_specs_integration.py
--- a/tests/python/pants_test/engine/legacy/test_filesystem_specs_integration.py
+++ b/tests/python/pants_test/engine/legacy/test_filesystem_specs_integration.py
@@ -36,6 +36,13 @@ def test_nonexistent_file(self) -> None:
         pants_run = self.run_pants(["list", "src/fake.py"])
         self.assert_failure(pants_run)
         assert 'Unmatched glob from file arguments: "src/fake.py"' in pants_run.stderr_data
+        pants_run = self.run_pants(["--owners-not-found-behavior=ignore", "list", "src/fake.py"])
+        self.assert_success(pants_run)
+        assert 'Unmatched glob from file arguments: "src/fake.py"' not in pants_run.stderr_data
+        assert (
+            "No owning targets could be found for the file `src/fake.py`"
+            not in pants_run.stderr_data
+        )
 
     def test_no_owner(self) -> None:
         """Literal file args should fail when there is no owner, but globs should be fine."""