Skip to content

Commit dd84feb

Browse files
committed
pycross: Add patching support to py_wheel_library
This patch adds a few arguments to `py_wheel_library` to simulate how `http_archive` accepts patch-related arguments. I also amended the existing test to validate the behaviour at a very high level. References: bazel-contrib#1360
1 parent 9a8c447 commit dd84feb

File tree

5 files changed

+102
-4
lines changed

5 files changed

+102
-4
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
From b2ebe6fe67ff48edaf2ae937d24b1f0b67c16f81 Mon Sep 17 00:00:00 2001
2+
From: Philipp Schrader <[email protected]>
3+
Date: Thu, 28 Sep 2023 09:02:44 -0700
4+
Subject: [PATCH] Add new file for testing patch support
5+
6+
---
7+
site-packages/numpy/file_added_via_patch.txt | 1 +
8+
1 file changed, 1 insertion(+)
9+
create mode 100644 site-packages/numpy/file_added_via_patch.txt
10+
11+
diff --git a/site-packages/numpy/file_added_via_patch.txt b/site-packages/numpy/file_added_via_patch.txt
12+
new file mode 100644
13+
index 0000000..9d947a4
14+
--- /dev/null
15+
+++ b/site-packages/numpy/file_added_via_patch.txt
16+
@@ -0,0 +1 @@
17+
+Hello from a patch!

tests/pycross/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ load("//third_party/rules_pycross/pycross/private:wheel_library.bzl", "py_wheel_
1717

1818
py_wheel_library(
1919
name = "extracted_wheel_for_testing",
20+
patch_args = [
21+
"-p1",
22+
],
23+
patches = [
24+
"0001-Add-new-file-for-testing-patch-support.patch",
25+
],
2026
wheel = "@wheel_for_testing//file",
2127
)
2228

tests/pycross/py_wheel_library_test.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@
2323
class TestPyWheelLibrary(unittest.TestCase):
2424
def setUp(self):
2525
self.extraction_dir = Path(
26-
RUNFILES.Rlocation(
27-
"rules_python/tests/pycross/extracted_wheel_for_testing"
28-
)
26+
RUNFILES.Rlocation("rules_python/tests/pycross/extracted_wheel_for_testing")
2927
)
3028
self.assertTrue(self.extraction_dir.exists(), self.extraction_dir)
3129
self.assertTrue(self.extraction_dir.is_dir(), self.extraction_dir)
@@ -43,6 +41,11 @@ def test_file_presence(self):
4341
(self.extraction_dir / path).exists(), f"{path} does not exist"
4442
)
4543

44+
def test_patched_file_contents(self):
45+
"""Validate that the patch got applied correctly."""
46+
file = self.extraction_dir / "site-packages/numpy/file_added_via_patch.txt"
47+
self.assertEqual(file.read_text(), "Hello from a patch!\n")
48+
4649

4750
if __name__ == "__main__":
4851
unittest.main()

third_party/rules_pycross/pycross/private/tools/wheel_installer.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import argparse
2121
import os
2222
import shutil
23+
import subprocess
2324
import sys
2425
import tempfile
2526
from pathlib import Path
@@ -97,6 +98,24 @@ def main(args: Any) -> None:
9798

9899
setup_namespace_pkg_compatibility(lib_dir)
99100

101+
patch_args = [args.patch_tool] + args.patch_arg
102+
patch_dir = args.patch_dir or "."
103+
for patch in args.patch or []:
104+
with patch.open("r") as stdin:
105+
try:
106+
subprocess.run(
107+
patch_args,
108+
stdin=stdin,
109+
check=True,
110+
stdout=subprocess.PIPE,
111+
stderr=subprocess.STDOUT,
112+
cwd=args.directory / patch_dir,
113+
)
114+
except subprocess.CalledProcessError as error:
115+
print(f"Patch {patch} failed to apply:")
116+
print(error.stdout.decode("utf-8"))
117+
raise
118+
100119

101120
def parse_flags(argv) -> Any:
102121
parser = argparse.ArgumentParser(description="Extract a Python wheel.")
@@ -127,6 +146,33 @@ def parse_flags(argv) -> Any:
127146
help="The output path.",
128147
)
129148

149+
parser.add_argument(
150+
"--patch",
151+
type=Path,
152+
action="append",
153+
help="A patch file to apply.",
154+
)
155+
156+
parser.add_argument(
157+
"--patch-arg",
158+
type=Path,
159+
default=[],
160+
action="append",
161+
help="An argument for the patch_tool when applying the patches.",
162+
)
163+
164+
parser.add_argument(
165+
"--patch-tool",
166+
type=str,
167+
help="The tool to invoke when applying patches.",
168+
)
169+
170+
parser.add_argument(
171+
"--patch-dir",
172+
type=str,
173+
help="The directory from which to invoke patch_tool.",
174+
)
175+
130176
return parser.parse_args(argv[1:])
131177

132178

third_party/rules_pycross/pycross/private/wheel_library.bzl

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ def _py_wheel_library_impl(ctx):
3333
args = ctx.actions.args().use_param_file("--flagfile=%s")
3434
args.add("--wheel", wheel_file)
3535
args.add("--directory", out.path)
36+
args.add_all(ctx.files.patches, format_each = "--patch=%s")
37+
args.add_all(ctx.attr.patch_args, format_each = "--patch-arg=%s")
38+
args.add("--patch-tool", ctx.attr.patch_tool)
39+
args.add("--patch-dir", ctx.attr.patch_dir)
3640

37-
inputs = [wheel_file]
41+
inputs = [wheel_file] + ctx.files.patches
3842
if name_file:
3943
inputs.append(name_file)
4044
args.add("--wheel-name-file", name_file)
@@ -119,6 +123,28 @@ and py_test targets must specify either `legacy_create_init=False` or the global
119123
This option is required to support some packages which cannot handle the conversion to pkg-util style.
120124
""",
121125
),
126+
"patch_args": attr.string_list(
127+
default = ["-p0"],
128+
doc =
129+
"The arguments given to the patch tool. Defaults to -p0, " +
130+
"however -p1 will usually be needed for patches generated by " +
131+
"git. If multiple -p arguments are specified, the last one will take effect.",
132+
),
133+
"patch_dir": attr.string(
134+
default = "",
135+
doc = "The directory from which to invoke the patch_tool.",
136+
),
137+
"patch_tool": attr.string(
138+
default = "patch",
139+
doc = "The patch(1) utility to use.",
140+
),
141+
"patches": attr.label_list(
142+
allow_files = True,
143+
default = [],
144+
doc =
145+
"A list of files that are to be applied as patches after " +
146+
"extracting the archive. This will use the patch command line tool.",
147+
),
122148
"python_version": attr.string(
123149
doc = "The python version required for this wheel ('PY2' or 'PY3')",
124150
values = ["PY2", "PY3", ""],

0 commit comments

Comments
 (0)