3 module CP
= Classic_patch
5 (* ./split_patch ../demos/janitorings/patch-kzalloc-vnew3.patch /tmp/xx "0 -> NULL" ../bodymail.doc
6 ./split_patch /tmp/badzero.patch /tmp/xx ../mailbody.doc ../kernel_dirs.meta
8 update: see http://lwn.net/Articles/284469/
9 for a script using git annotate to find automatically to who send
10 a patch (by looking at authors of lines close concerning the patch I guess
13 (*****************************************************************************)
15 (*****************************************************************************)
17 let just_patch = ref false
18 let verbose = ref true
21 if !verbose then pr2 s
23 (*****************************************************************************)
25 (*****************************************************************************)
27 let print_header_patch patch
=
28 patch
+> List.iter
(function CP.File
(s
, header
, body
) -> pr s
)
31 (*****************************************************************************)
32 (* Grouping strategies *)
33 (*****************************************************************************)
35 let group_patch_depth_2 patch
=
36 let patch_with_dir = patch
+> List.map
(function (CP.File
(s
,header
,body
)) ->
37 Common.split
"/" (Common.dirname s
),
38 (CP.File
(s
, header
, body
))
41 let rec aux_patch xs
=
44 | (dir_elems
,x
)::xs
->
46 if List.length dir_elems
>= 2 then
47 let base = Common.take
2 dir_elems
in
49 List.length dir_elems'
>= 2 && Common.take
2 dir_elems'
= base),
52 (fun dir_elems'
-> dir_elems'
= dir_elems
),
56 let (yes
, no
) = xs
+> Common.partition_either
(fun (dir_elems'
, x
) ->
59 else Right
(dir_elems'
, x
)
61 (Common.join
"/" base, ["NOEMAIL"], (x
::yes
))::aux_patch no
63 aux_patch patch_with_dir
67 let group_patch_subsystem_info patch subinfo
=
68 let patch_with_dir = patch
+> List.map
(function (CP.File
(s
,header
,body
)) ->
69 (Common.dirname s
), (CP.File
(s
, header
, body
))
72 let index = Maintainers.mk_inverted_index_subsystem subinfo
in
73 let hash = Maintainers.subsystem_to_hash subinfo
in
75 let rec aux_patch xs
=
78 | ((dir
,patchitem
)::xs
) as xs'
->
80 try Hashtbl.find
index dir
81 with Not_found
-> failwith
("cant find leader for : " ^ dir
)
83 let (emailsleader
, subdirs
) =
84 try Hashtbl.find
hash leader
85 with Not_found
-> failwith
("cant find subdirs of : " ^
leader)
88 (match emailsleader
with
89 | ["NOEMAIL"] | [] | [""] -> pr2 ("no leader maintainer for: "^
leader);
93 let emails = ref emailsleader
in
94 let allsubdirs = (leader, emailsleader
)::subdirs
in
96 let (yes
, no
) = xs'
+> Common.partition_either
(fun (dir'
,patchitem'
)->
98 let emailsdir'
= List.assoc dir'
allsubdirs in
99 emails := !emails $
+$
emailsdir'
;
101 ) with Not_found
-> Right
(dir'
, patchitem'
)
103 if List.mem dir' (leader::subdirs)
108 (leader, !emails, yes
)::aux_patch no
110 aux_patch patch_with_dir
113 (*****************************************************************************)
115 (*****************************************************************************)
116 let i_to_s_padded i total
=
118 | i
when i
< 10 && total
>= 10 -> "0" ^ i_to_s i
119 | i
when i
< 100 -> i_to_s i
122 let split_patch file prefix bodymail subinfofile
=
123 let patch = CP.parse_patch file
in
125 let subsystem_info = Maintainers.parse_subsystem_info subinfofile
in
126 let minipatches = group_patch_subsystem_info patch subsystem_info in
127 (* let minipatches = group_patch_depth_2 patch in *)
129 let total = List.length
minipatches in
130 let minipatches_indexed = Common.index_list_1
minipatches in
132 let (subject
, bodymail_rest
) =
133 match Common.cat bodymail
with
135 if x
=~
"Subject: \\(.*\\)"
137 let subject = matched1 x
in
141 else failwith
("wrong format for mailbody in:" ^ bodymail
)
142 else failwith
("wrong format for mailbody in:" ^ bodymail
)
143 | _
-> failwith
("wrong format for mailbody in:" ^ bodymail
)
146 Common.command2_y_or_no
("rm -f " ^ prefix ^
"*");
149 minipatches_indexed +> List.iter
(fun ((dir
,emails, minipatch
), i
) ->
150 let numpatch = i_to_s_padded i
total in
151 let tmpfile = prefix ^
numpatch ^
".mail" in
152 let patchfile = "/tmp/x.patch" in
153 pr2 ("generating :" ^
tmpfile ^
" for " ^ dir
);
155 CP.unparse_patch minipatch
patchfile;
159 | ["NOEMAIL"] | [] | [""] ->
160 pr2 "no maintainer"; []
162 ) @ ["akpm@linux-foundation.org"]
167 then command2
(sprintf
"cat %s > %s" patchfile tmpfile)
169 Common.with_open_outfile
tmpfile (fun (pr_no_nl
, chan
) ->
170 let pr s
= pr_no_nl
(s ^
"\n") in
171 pr "To: kernel-janitors@vger.kernel.org";
172 pr (sprintf
"Subject: [PATCH %s/%d] %s, for %s"
173 numpatch total subject dir
);
174 pr ("Cc: " ^
(Common.join
", " (emails @ ["linux-kernel@vger.kernel.org"])));
175 pr "BCC: padator@wanadoo.fr";
176 pr "From: Yoann Padioleau <padator@wanadoo.fr>";
177 pr "--text follows this line--";
180 bodymail_rest
+> List.iter
pr;
182 pr "Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>";
183 emails +> List.iter
(fun s
->
191 command2
(sprintf
"diffstat -p1 %s >> %s" patchfile tmpfile);
192 command2
(sprintf
"echo >> %s" tmpfile);
193 command2
(sprintf
"cat %s >> %s" patchfile tmpfile);
199 (*****************************************************************************)
201 (*****************************************************************************)
203 let test_patch file
=
204 let patch = CP.parse_patch file
in
205 let groups = group_patch_depth_2 patch in
206 groups +> List.iter
(fun (dir
, email
, minipatch
) ->
207 print_header_patch minipatch
;
212 (*****************************************************************************)
213 (* Main entry point *)
214 (*****************************************************************************)
220 "-just_patch", Arg.Set
just_patch, "";
221 "-no_verbose", Arg.Clear
verbose, "";
224 "Usage: " ^ basename
Sys.argv
.(0) ^
225 " <patch> <prefix> <bodymailfile> <maintainerfile> [options]" ^
"\n"
229 Arg.parse
(Arg.align
options) (fun x
-> args := x
::!args) usage_msg;
230 args := List.rev
!args;
233 | [patch] -> test_patch patch
234 | [patch;prefix
;bodymail
;subinfofile
] ->
235 split_patch patch prefix bodymail subinfofile
;
237 command2
("rm -f /tmp/split_check*");
238 let checkfile = "/tmp/split_check.all" in
239 let checkprefix = "/tmp/split_check-xx" in
240 save_excursion
verbose (fun () ->
241 save_excursion
just_patch (fun () ->
244 split_patch patch checkprefix bodymail subinfofile
;
246 command2
("cat /tmp/split_check*.mail > " ^
checkfile);
248 let diff = Common.cmd_to_list
(sprintf
"diff %s %s " patch checkfile)
250 let samesize = Common.filesize
patch = Common.filesize
checkfile in
251 if (List.length
diff <> 0)
254 then pr2 "diff but at least same size"
255 else pr2 "PB: diff and not same size"
257 | _
-> Arg.usage
(Arg.align
options) usage_msg;
261 (*****************************************************************************)