@@ -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
4555def _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