Skip to content

Commit 466a2ec

Browse files
committed
fix: correct patch commands for recursive diffs
1 parent 6e24749 commit 466a2ec

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

diff/defs.bzl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,22 @@ def diff(name, srcs, args = ["--unified"], patch = None, **kwargs):
7070
partial.call(srcs[i], name = target, out = target + ".in")
7171
srcs[i] = target
7272

73+
# Determine whether the first input of a diff is a source directory.
74+
# Bazel rules cannot detect source directories. This information is
75+
# needed to produce the correct patch command.
76+
source_directories = False
77+
if len(srcs) == 2: # TODO: support multiple directory inputs with --to-file
78+
all_sources = set(native.glob(srcs, exclude_directories = 0, allow_empty = True))
79+
file_sources = native.glob(srcs, exclude_directories = 1, allow_empty = True)
80+
directory_sources = all_sources.difference(file_sources)
81+
if len(directory_sources) > 0:
82+
source_directories = True
83+
7384
diff_rule(
7485
name = name,
7586
args = args,
7687
srcs = srcs,
7788
patch = patch or name + ".patch",
89+
source_directories = source_directories,
7890
**kwargs
7991
)

diff/private/diff.bzl

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,21 @@ def _determine_patch_type(args):
3535

3636
return "normal"
3737

38-
def _patch_cmd(type, source_file, patch_file):
38+
def _is_recursive(args):
39+
for arg in args:
40+
arg = arg.lstrip(" ")
41+
if arg.startswith("-r") or arg.startswith("--recursive"):
42+
return True
43+
return False
44+
45+
def _patch_cmd(type, source_file, patch_file, recursive, source_directories):
3946
if type == "normal":
4047
return "(cd \\$(bazel info workspace); patch -p0 {} < {})".format(source_file, patch_file)
4148
elif type == "context" or type == "unified":
42-
return "(cd \\$(bazel info workspace); patch -p0 < {})".format(patch_file)
49+
if recursive and source_directories:
50+
return "(cd \\$(bazel info workspace); patch --directory {} -p{} < {})".format(source_file, source_file.count("/") + 1, patch_file)
51+
else:
52+
return "(cd \\$(bazel info workspace); patch -p0 < {})".format(patch_file)
4353
return None
4454

4555
def _detect_multifile(args):
@@ -137,6 +147,7 @@ def _diff_rule_impl(ctx):
137147
fail("error: srcs attr of diff rule must contain exactly two targets unless --from-file or --to-file are specified")
138148

139149
type = _determine_patch_type(ctx.attr.args)
150+
recursive = _is_recursive(ctx.attr.args)
140151

141152
command = _build_command(
142153
ctx.bin_dir.path,
@@ -182,7 +193,7 @@ def _diff_rule_impl(ctx):
182193
if patchable:
183194
# Show a command to patch the source file if it's a (bazel) source file.
184195
# NB: the error message we print here allows the user to be in any working directory.
185-
patch_cmd = _patch_cmd(type, ctx.files.srcs[0].path, ctx.outputs.patch.path)
196+
patch_cmd = _patch_cmd(type, ctx.files.srcs[0].path, ctx.outputs.patch.path, recursive, ctx.attr.source_directories)
186197
if patch_cmd != None:
187198
patch_msg = """
188199
To accept the diff, run:
@@ -211,6 +222,14 @@ diff_rule = rule(
211222
""",
212223
default = [],
213224
),
225+
"source_directories": attr.bool(
226+
doc = """\
227+
Whether any of the patchable source inputs in `srcs` are directories. This is expected
228+
to be passed in by a wrapper macro as File.is_directory does not detect source directory
229+
inputs.
230+
""",
231+
default = False,
232+
),
214233
"srcs": attr.label_list(allow_files = True),
215234
"patch": attr.output(
216235
doc = """\

0 commit comments

Comments
 (0)