fix: spill module mapping args to a file (#2644)

Calls to the modules mapping rule contains very long command line args
due to the use of the full `wheels` parameter. This change adds support
for spilling the args into a file as needed.

In addition, it improves the performance of the `modules_mapping` rule:

* Remove the calls `to_list` that are unnecessary on the depset.
* Remove the iteration over the depset when passing to `args`, and other
calls to `.path`, and instead let args do this lazily.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 849b458..8eaac3d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -63,6 +63,8 @@
   is now the default. Note that running as root may still cause spurious
   Bazel cache invalidation
   ([#1169](https://github.com/bazelbuild/rules_python/issues/1169)).
+* (gazelle) Don't collapse depsets to a list or into args when generating the modules mapping file.
+  Support spilling modules mapping args into a params file.
 
 {#v0-0-0-added}
 ### Added
diff --git a/gazelle/modules_mapping/def.bzl b/gazelle/modules_mapping/def.bzl
index eb17f5c..48a5477 100644
--- a/gazelle/modules_mapping/def.bzl
+++ b/gazelle/modules_mapping/def.bzl
@@ -25,18 +25,25 @@
 
 def _modules_mapping_impl(ctx):
     modules_mapping = ctx.actions.declare_file(ctx.attr.modules_mapping_name)
-    args = ctx.actions.args()
     all_wheels = depset(
         [whl for whl in ctx.files.wheels],
         transitive = [dep[DefaultInfo].files for dep in ctx.attr.wheels] + [dep[DefaultInfo].data_runfiles.files for dep in ctx.attr.wheels],
     )
-    args.add("--output_file", modules_mapping.path)
+
+    args = ctx.actions.args()
+
+    # Spill parameters to a file prefixed with '@'. Note, the '@' prefix is the same
+    # prefix as used in the `generator.py` in `fromfile_prefix_chars` attribute.
+    args.use_param_file(param_file_arg = "@%s")
+    args.set_param_file_format(format = "multiline")
     if ctx.attr.include_stub_packages:
         args.add("--include_stub_packages")
+    args.add("--output_file", modules_mapping)
     args.add_all("--exclude_patterns", ctx.attr.exclude_patterns)
-    args.add_all("--wheels", [whl.path for whl in all_wheels.to_list()])
+    args.add_all("--wheels", all_wheels)
+
     ctx.actions.run(
-        inputs = all_wheels.to_list(),
+        inputs = all_wheels,
         outputs = [modules_mapping],
         executable = ctx.executable._generator,
         arguments = [args],
diff --git a/gazelle/modules_mapping/generator.py b/gazelle/modules_mapping/generator.py
index 99f565e..d5ddca2 100644
--- a/gazelle/modules_mapping/generator.py
+++ b/gazelle/modules_mapping/generator.py
@@ -152,6 +152,9 @@
     parser = argparse.ArgumentParser(
         prog="generator",
         description="Generates the modules mapping used by the Gazelle manifest.",
+        # Automatically read parameters from a file. Note, the '@' is the same prefix
+        # as set in the 'args.use_param_file' in the bazel rule.
+        fromfile_prefix_chars="@",
     )
     parser.add_argument("--output_file", type=str)
     parser.add_argument("--include_stub_packages", action="store_true")