Repository: pypa/auditwheel

Issue:
Allow wildcards in `--exclude`
It would be nice if the `--exclude` argument supported wildcards, like so:

```
auditwheel repair --exclude 'libexternallib.so.*' my_wheel.whl
```

Hints from issue comments:
@petermbauer: I would like to prevent any libraries from being added, hope this can be achieved then with `--exclude "*"`.@KyleFromNVIDIA: > I would like to prevent any libraries from being added, hope this can be achieved then with `--exclude "*"`.

I just added a test to #508 to confirm that it supports this.

Solution patch:
diff --git a/src/auditwheel/lddtree.py b/src/auditwheel/lddtree.py
index 18064d87..cd529609 100644
--- a/src/auditwheel/lddtree.py
+++ b/src/auditwheel/lddtree.py
@@ -19,6 +19,7 @@
 import glob
 import logging
 import os
+from fnmatch import fnmatch
 from pathlib import Path
 from typing import Any
 
@@ -405,7 +406,7 @@ def lddtree(
                 elif t.entry.d_tag == "DT_RUNPATH":
                     runpaths = parse_ld_paths(t.runpath, path=path, root=root)
                 elif t.entry.d_tag == "DT_NEEDED":
-                    if t.needed in exclude:
+                    if any(fnmatch(t.needed, e) for e in exclude):
                         log.info(f"Excluding {t.needed}")
                     else:
                         libs.append(t.needed)
diff --git a/src/auditwheel/main_repair.py b/src/auditwheel/main_repair.py
index 4374f208..9f33bc1e 100644
--- a/src/auditwheel/main_repair.py
+++ b/src/auditwheel/main_repair.py
@@ -89,7 +89,10 @@ def configure_parser(sub_parsers):
         "--exclude",
         dest="EXCLUDE",
         help="Exclude SONAME from grafting into the resulting wheel "
-        "(can be specified multiple times)",
+        "Please make sure wheel metadata reflects your dependencies. "
+        "See https://github.com/pypa/auditwheel/pull/411#issuecomment-1500826281 "
+        "(can be specified multiple times) "
+        "(can contain wildcards, for example libfoo.so.*)",
         action="append",
         default=[],
     )
diff --git a/src/auditwheel/repair.py b/src/auditwheel/repair.py
index 220f5404..2a162cc8 100644
--- a/src/auditwheel/repair.py
+++ b/src/auditwheel/repair.py
@@ -8,6 +8,7 @@
 import shutil
 import stat
 from collections.abc import Iterable
+from fnmatch import fnmatch
 from os.path import abspath, basename, dirname, exists, isabs
 from os.path import join as pjoin
 from pathlib import Path
@@ -70,7 +71,7 @@ def repair_wheel(
             ext_libs: dict[str, str] = v[abis[0]]["libs"]
             replacements: list[tuple[str, str]] = []
             for soname, src_path in ext_libs.items():
-                assert soname not in exclude
+                assert not any(fnmatch(soname, e) for e in exclude)
 
                 if src_path is None:
                     raise ValueError(


Test patch:
diff --git a/tests/integration/test_bundled_wheels.py b/tests/integration/test_bundled_wheels.py
index e83535b7..a63305a3 100644
--- a/tests/integration/test_bundled_wheels.py
+++ b/tests/integration/test_bundled_wheels.py
@@ -25,6 +25,23 @@
     [
         ("cffi-1.5.0-cp27-none-linux_x86_64.whl", {"libffi.so.5"}, frozenset()),
         ("cffi-1.5.0-cp27-none-linux_x86_64.whl", set(), frozenset(["libffi.so.5"])),
+        (
+            "cffi-1.5.0-cp27-none-linux_x86_64.whl",
+            {"libffi.so.5"},
+            frozenset(["libffi.so.noexist", "libnoexist.so.*"]),
+        ),
+        (
+            "cffi-1.5.0-cp27-none-linux_x86_64.whl",
+            set(),
+            frozenset(["libffi.so.[4,5]"]),
+        ),
+        (
+            "cffi-1.5.0-cp27-none-linux_x86_64.whl",
+            {"libffi.so.5"},
+            frozenset(["libffi.so.[6,7]"]),
+        ),
+        ("cffi-1.5.0-cp27-none-linux_x86_64.whl", set(), frozenset(["libffi.so.*"])),
+        ("cffi-1.5.0-cp27-none-linux_x86_64.whl", set(), frozenset(["*"])),
         (
             "python_snappy-0.5.2-pp260-pypy_41-linux_x86_64.whl",
             {"libsnappy.so.1"},