Skip to content

Commit 322bbc9

Browse files
committed
feat: add repo_utils with fork of @bazel_tools patch function that takes a working_directory argument
1 parent 1421a1d commit 322bbc9

8 files changed

+307
-9
lines changed

docs/BUILD.bazel

+5
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,9 @@ stardoc_with_diff_test(
7373
bzl_library_target = "//lib:transitions",
7474
)
7575

76+
stardoc_with_diff_test(
77+
name = "repo_utils",
78+
bzl_library_target = "//lib:repo_utils",
79+
)
80+
7681
update_docs()

docs/repo_utils.md

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<!-- Generated with Stardoc: http://skydoc.bazel.build -->
2+
3+
Public API
4+
5+
<a id="#is_darwin_os"></a>
6+
7+
## is_darwin_os
8+
9+
<pre>
10+
is_darwin_os(<a href="#is_darwin_os-rctx">rctx</a>)
11+
</pre>
12+
13+
Returns true if the host operating system is Darwin
14+
15+
**PARAMETERS**
16+
17+
18+
| Name | Description | Default Value |
19+
| :------------- | :------------- | :------------- |
20+
| <a id="is_darwin_os-rctx"></a>rctx | <p align="center"> - </p> | none |
21+
22+
23+
<a id="#is_linux_os"></a>
24+
25+
## is_linux_os
26+
27+
<pre>
28+
is_linux_os(<a href="#is_linux_os-rctx">rctx</a>)
29+
</pre>
30+
31+
Returns true if the host operating system is Linux
32+
33+
**PARAMETERS**
34+
35+
36+
| Name | Description | Default Value |
37+
| :------------- | :------------- | :------------- |
38+
| <a id="is_linux_os-rctx"></a>rctx | <p align="center"> - </p> | none |
39+
40+
41+
<a id="#is_windows_os"></a>
42+
43+
## is_windows_os
44+
45+
<pre>
46+
is_windows_os(<a href="#is_windows_os-rctx">rctx</a>)
47+
</pre>
48+
49+
Returns true if the host operating system is Windows
50+
51+
**PARAMETERS**
52+
53+
54+
| Name | Description | Default Value |
55+
| :------------- | :------------- | :------------- |
56+
| <a id="is_windows_os-rctx"></a>rctx | <p align="center"> - </p> | none |
57+
58+
59+
<a id="#patch"></a>
60+
61+
## patch
62+
63+
<pre>
64+
patch(<a href="#patch-ctx">ctx</a>, <a href="#patch-patches">patches</a>, <a href="#patch-patch_cmds">patch_cmds</a>, <a href="#patch-patch_cmds_win">patch_cmds_win</a>, <a href="#patch-patch_tool">patch_tool</a>, <a href="#patch-patch_args">patch_args</a>, <a href="#patch-auth">auth</a>, <a href="#patch-patch_directory">patch_directory</a>)
65+
</pre>
66+
67+
Implementation of patching an already extracted repository.
68+
69+
This rule is intended to be used in the implementation function of
70+
a repository rule. If the parameters `patches`, `patch_tool`,
71+
`patch_args`, `patch_cmds` and `patch_cmds_win` are not specified
72+
then they are taken from `ctx.attr`.
73+
74+
75+
**PARAMETERS**
76+
77+
78+
| Name | Description | Default Value |
79+
| :------------- | :------------- | :------------- |
80+
| <a id="patch-ctx"></a>ctx | The repository context of the repository rule calling this utility function. | none |
81+
| <a id="patch-patches"></a>patches | The patch files to apply. List of strings, Labels, or paths. | <code>None</code> |
82+
| <a id="patch-patch_cmds"></a>patch_cmds | Bash commands to run for patching, passed one at a time to bash -c. List of strings | <code>None</code> |
83+
| <a id="patch-patch_cmds_win"></a>patch_cmds_win | Powershell commands to run for patching, passed one at a time to powershell /c. List of strings. If the boolean value of this parameter is false, patch_cmds will be used and this parameter will be ignored. | <code>None</code> |
84+
| <a id="patch-patch_tool"></a>patch_tool | Path of the patch tool to execute for applying patches. String. | <code>None</code> |
85+
| <a id="patch-patch_args"></a>patch_args | Arguments to pass to the patch tool. List of strings. | <code>None</code> |
86+
| <a id="patch-auth"></a>auth | An optional dict specifying authentication information for some of the URLs. | <code>None</code> |
87+
| <a id="patch-patch_directory"></a>patch_directory | Directory to apply the patches in | <code>None</code> |
88+
89+

lib/BUILD.bazel

+10
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,13 @@ bzl_library(
127127
srcs = ["windows_utils.bzl"],
128128
visibility = ["//visibility:public"],
129129
)
130+
131+
bzl_library(
132+
name = "repo_utils",
133+
srcs = ["repo_utils.bzl"],
134+
visibility = ["//visibility:public"],
135+
deps = [
136+
"//lib/private:patch",
137+
"//lib/private:repo_utils",
138+
],
139+
)

lib/private/BUILD.bazel

+13
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,16 @@ bzl_library(
120120
"@bazel_skylib//lib:dicts",
121121
],
122122
)
123+
124+
bzl_library(
125+
name = "repo_utils",
126+
srcs = ["repo_utils.bzl"],
127+
visibility = ["//lib:__subpackages__"],
128+
)
129+
130+
bzl_library(
131+
name = "patch",
132+
srcs = ["patch.bzl"],
133+
visibility = ["//lib:__subpackages__"],
134+
deps = [":repo_utils"],
135+
)

lib/private/patch copy.bzl

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Copyright 2018 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Fork of @bazel_tools//tools/build_defs/repo:utils.bzl patch function with
16+
working_directory argument added.
17+
"""
18+
19+
load(":repo_utils.bzl", "repo_utils")
20+
21+
# Temporary directory for downloading remote patch files.
22+
_REMOTE_PATCH_DIR = ".tmp_remote_patches"
23+
24+
def _use_native_patch(patch_args):
25+
"""If patch_args only contains -p<NUM> options, we can use the native patch implementation."""
26+
for arg in patch_args:
27+
if not arg.startswith("-p"):
28+
return False
29+
return True
30+
31+
def _download_patch(ctx, patch_url, integrity, auth):
32+
name = patch_url.split("/")[-1]
33+
patch_path = ctx.path(_REMOTE_PATCH_DIR).get_child(name)
34+
ctx.download(
35+
patch_url,
36+
patch_path,
37+
canonical_id = ctx.attr.canonical_id,
38+
auth = auth,
39+
integrity = integrity,
40+
)
41+
return patch_path
42+
43+
def patch(ctx, patches = None, patch_cmds = None, patch_cmds_win = None, patch_tool = None, patch_args = None, auth = None, working_directory = None):
44+
"""Implementation of patching an already extracted repository.
45+
46+
This rule is intended to be used in the implementation function of
47+
a repository rule. If the parameters `patches`, `patch_tool`,
48+
`patch_args`, `patch_cmds` and `patch_cmds_win` are not specified
49+
then they are taken from `ctx.attr`.
50+
51+
Args:
52+
ctx: The repository context of the repository rule calling this utility
53+
function.
54+
patches: The patch files to apply. List of strings, Labels, or paths.
55+
patch_cmds: Bash commands to run for patching, passed one at a
56+
time to bash -c. List of strings
57+
patch_cmds_win: Powershell commands to run for patching, passed
58+
one at a time to powershell /c. List of strings. If the
59+
boolean value of this parameter is false, patch_cmds will be
60+
used and this parameter will be ignored.
61+
patch_tool: Path of the patch tool to execute for applying
62+
patches. String.
63+
patch_args: Arguments to pass to the patch tool. List of strings.
64+
auth: An optional dict specifying authentication information for some of the URLs.
65+
working_directory: Working directory to apply the patches in
66+
67+
"""
68+
bash_exe = ctx.os.environ["BAZEL_SH"] if "BAZEL_SH" in ctx.os.environ else "bash"
69+
powershell_exe = ctx.os.environ["BAZEL_POWERSHELL"] if "BAZEL_POWERSHELL" in ctx.os.environ else "powershell.exe"
70+
71+
if patches == None:
72+
patches = []
73+
if hasattr(ctx.attr, "patches") and ctx.attr.patches:
74+
patches += ctx.attr.patches
75+
76+
remote_patches = {}
77+
remote_patch_strip = 0
78+
if hasattr(ctx.attr, "remote_patches") and ctx.attr.remote_patches:
79+
if hasattr(ctx.attr, "remote_patch_strip"):
80+
remote_patch_strip = ctx.attr.remote_patch_strip
81+
remote_patches = ctx.attr.remote_patches
82+
83+
if patch_cmds == None and hasattr(ctx.attr, "patch_cmds"):
84+
patch_cmds = ctx.attr.patch_cmds
85+
if patch_cmds == None:
86+
patch_cmds = []
87+
88+
if patch_cmds_win == None and hasattr(ctx.attr, "patch_cmds_win"):
89+
patch_cmds_win = ctx.attr.patch_cmds_win
90+
if patch_cmds_win == None:
91+
patch_cmds_win = []
92+
93+
if patch_tool == None and hasattr(ctx.attr, "patch_tool"):
94+
patch_tool = ctx.attr.patch_tool
95+
if not patch_tool:
96+
patch_tool = "patch"
97+
native_patch = True
98+
else:
99+
native_patch = False
100+
101+
if patch_args == None and hasattr(ctx.attr, "patch_args"):
102+
patch_args = ctx.attr.patch_args
103+
if patch_args == None:
104+
patch_args = []
105+
106+
if len(remote_patches) > 0 or len(patches) > 0 or len(patch_cmds) > 0:
107+
ctx.report_progress("Patching repository")
108+
109+
# Apply remote patches
110+
for patch_url in remote_patches:
111+
integrity = remote_patches[patch_url]
112+
patchfile = _download_patch(ctx, patch_url, integrity, auth)
113+
ctx.patch(patchfile, remote_patch_strip)
114+
ctx.delete(patchfile)
115+
ctx.delete(ctx.path(_REMOTE_PATCH_DIR))
116+
117+
# Apply local patches
118+
if native_patch and _use_native_patch(patch_args) and not working_directory:
119+
if patch_args:
120+
strip = int(patch_args[-1][2:])
121+
else:
122+
strip = 0
123+
for patchfile in patches:
124+
ctx.patch(patchfile, strip)
125+
else:
126+
for patchfile in patches:
127+
command = "{patchtool} {patch_args} < {patchfile}".format(
128+
patchtool = patch_tool,
129+
patchfile = ctx.path(patchfile),
130+
patch_args = " ".join([
131+
"'%s'" % arg
132+
for arg in patch_args
133+
]),
134+
)
135+
st = ctx.execute([bash_exe, "-c", command], working_directory = working_directory)
136+
if st.return_code:
137+
fail("Error applying patch %s:\n%s%s" %
138+
(str(patchfile), st.stderr, st.stdout))
139+
140+
if repo_utils.is_windows_os(ctx) and patch_cmds_win:
141+
for cmd in patch_cmds_win:
142+
st = ctx.execute([powershell_exe, "/c", cmd], working_directory = working_directory)
143+
if st.return_code:
144+
fail("Error applying patch command %s:\n%s%s" %
145+
(cmd, st.stdout, st.stderr))
146+
else:
147+
for cmd in patch_cmds:
148+
st = ctx.execute([bash_exe, "-c", cmd], working_directory = working_directory)
149+
if st.return_code:
150+
fail("Error applying patch command %s:\n%s%s" %
151+
(cmd, st.stdout, st.stderr))

lib/private/patch.bzl

+11-9
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,11 @@ Upstream code is at
1919
https://github.com/bazelbuild/bazel/blob/f4214746fcd15f0ef8c4e747ef8e3edca9f112a5/tools/build_defs/repo/utils.bzl#L87
2020
"""
2121

22+
load(":repo_utils.bzl", "repo_utils")
23+
2224
# Temporary directory for downloading remote patch files.
2325
_REMOTE_PATCH_DIR = ".tmp_remote_patches"
2426

25-
def _is_windows(ctx):
26-
return ctx.os.name.lower().find("windows") != -1
27-
2827
def _use_native_patch(patch_args):
2928
"""If patch_args only contains -p<NUM> options, we can use the native patch implementation."""
3029
for arg in patch_args:
@@ -44,13 +43,14 @@ def _download_patch(ctx, patch_url, integrity, auth):
4443
)
4544
return patch_path
4645

47-
def patch(ctx, patches = None, patch_cmds = None, patch_cmds_win = None, patch_tool = None, patch_args = None, auth = None):
46+
def patch(ctx, patches = None, patch_cmds = None, patch_cmds_win = None, patch_tool = None, patch_args = None, auth = None, patch_directory = None):
4847
"""Implementation of patching an already extracted repository.
4948
5049
This rule is intended to be used in the implementation function of
5150
a repository rule. If the parameters `patches`, `patch_tool`,
5251
`patch_args`, `patch_cmds` and `patch_cmds_win` are not specified
5352
then they are taken from `ctx.attr`.
53+
5454
Args:
5555
ctx: The repository context of the repository rule calling this utility
5656
function.
@@ -65,6 +65,8 @@ def patch(ctx, patches = None, patch_cmds = None, patch_cmds_win = None, patch_t
6565
patches. String.
6666
patch_args: Arguments to pass to the patch tool. List of strings.
6767
auth: An optional dict specifying authentication information for some of the URLs.
68+
patch_directory: Directory to apply the patches in
69+
6870
"""
6971
bash_exe = ctx.os.environ["BAZEL_SH"] if "BAZEL_SH" in ctx.os.environ else "bash"
7072
powershell_exe = ctx.os.environ["BAZEL_POWERSHELL"] if "BAZEL_POWERSHELL" in ctx.os.environ else "powershell.exe"
@@ -116,7 +118,7 @@ def patch(ctx, patches = None, patch_cmds = None, patch_cmds_win = None, patch_t
116118
ctx.delete(ctx.path(_REMOTE_PATCH_DIR))
117119

118120
# Apply local patches
119-
if native_patch and _use_native_patch(patch_args):
121+
if native_patch and _use_native_patch(patch_args) and not patch_directory:
120122
if patch_args:
121123
strip = int(patch_args[-1][2:])
122124
else:
@@ -133,20 +135,20 @@ def patch(ctx, patches = None, patch_cmds = None, patch_cmds_win = None, patch_t
133135
for arg in patch_args
134136
]),
135137
)
136-
st = ctx.execute([bash_exe, "-c", command])
138+
st = ctx.execute([bash_exe, "-c", command], working_directory = patch_directory)
137139
if st.return_code:
138140
fail("Error applying patch %s:\n%s%s" %
139141
(str(patchfile), st.stderr, st.stdout))
140142

141-
if _is_windows(ctx) and patch_cmds_win:
143+
if repo_utils.is_windows_os(ctx) and patch_cmds_win:
142144
for cmd in patch_cmds_win:
143-
st = ctx.execute([powershell_exe, "/c", cmd])
145+
st = ctx.execute([powershell_exe, "/c", cmd], working_directory = patch_directory)
144146
if st.return_code:
145147
fail("Error applying patch command %s:\n%s%s" %
146148
(cmd, st.stdout, st.stderr))
147149
else:
148150
for cmd in patch_cmds:
149-
st = ctx.execute([bash_exe, "-c", cmd])
151+
st = ctx.execute([bash_exe, "-c", cmd], working_directory = patch_directory)
150152
if st.return_code:
151153
fail("Error applying patch command %s:\n%s%s" %
152154
(cmd, st.stdout, st.stderr))

lib/private/repo_utils.bzl

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Utility functions for repository rules"""
2+
3+
def _is_windows_os(rctx):
4+
"""Returns true if the host operating system is Windows"""
5+
return rctx.os.name.lower().find("windows") != -1
6+
7+
def _is_darwin_os(rctx):
8+
"""Returns true if the host operating system is Darwin"""
9+
return rctx.os.name.lower().os_name.startswith("mac os")
10+
11+
def _is_linux_os(rctx):
12+
"""Returns true if the host operating system is Linux"""
13+
return rctx.os.name.lower().startswith("linux")
14+
15+
repo_utils = struct(
16+
is_windows_os = _is_windows_os,
17+
is_darwin_os = _is_darwin_os,
18+
is_linux_os = _is_linux_os,
19+
)

lib/repo_utils.bzl

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"Public API"
2+
3+
load("//lib/private:repo_utils.bzl", "repo_utils")
4+
load("//lib/private:patch.bzl", _patch = "patch")
5+
6+
is_windows_os = repo_utils.is_windows_os
7+
is_darwin_os = repo_utils.is_darwin_os
8+
is_linux_os = repo_utils.is_linux_os
9+
patch = _patch

0 commit comments

Comments
 (0)