Commit | Line | Data |
---|---|---|
9f8e26f4 | 1 | (* |
ae4735db | 2 | * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen |
9f8e26f4 C |
3 | * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix |
4 | * This file is part of Coccinelle. | |
5 | * | |
6 | * Coccinelle is free software: you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation, according to version 2 of the License. | |
9 | * | |
10 | * Coccinelle is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>. | |
17 | * | |
18 | * The authors reserve the right to distribute this or future versions of | |
19 | * Coccinelle under other licenses. | |
20 | *) | |
21 | ||
22 | ||
485bce71 | 23 | open Common |
34e49164 | 24 | |
ae4735db | 25 | module CP = Classic_patch |
34e49164 | 26 | |
ae4735db | 27 | (* ./split_patch ../demos/janitorings/patch-kzalloc-vnew3.patch /tmp/xx "0 -> NULL" ../bodymail.doc |
34e49164 C |
28 | ./split_patch /tmp/badzero.patch /tmp/xx ../mailbody.doc ../kernel_dirs.meta |
29 | ||
30 | update: see http://lwn.net/Articles/284469/ | |
31 | for a script using git annotate to find automatically to who send | |
32 | a patch (by looking at authors of lines close concerning the patch I guess | |
33 | *) | |
34 | ||
35 | (*****************************************************************************) | |
36 | (* Flags *) | |
37 | (*****************************************************************************) | |
38 | ||
39 | let just_patch = ref false | |
40 | let verbose = ref true | |
41 | ||
ae4735db | 42 | let pr2 s = |
34e49164 C |
43 | if !verbose then pr2 s |
44 | ||
45 | (*****************************************************************************) | |
46 | (* Helpers *) | |
47 | (*****************************************************************************) | |
48 | ||
ae4735db | 49 | let print_header_patch patch = |
34e49164 C |
50 | patch +> List.iter (function CP.File (s, header, body) -> pr s) |
51 | ||
52 | ||
53 | (*****************************************************************************) | |
54 | (* Grouping strategies *) | |
55 | (*****************************************************************************) | |
56 | ||
ae4735db | 57 | let group_patch_depth_2 patch = |
34e49164 | 58 | let patch_with_dir = patch +> List.map (function (CP.File (s,header,body)) -> |
ae4735db | 59 | Common.split "/" (Common.dirname s), |
34e49164 C |
60 | (CP.File (s, header, body)) |
61 | ) | |
62 | in | |
ae4735db | 63 | let rec aux_patch xs = |
34e49164 C |
64 | match xs with |
65 | | [] -> [] | |
ae4735db C |
66 | | (dir_elems,x)::xs -> |
67 | let cond, base = | |
34e49164 C |
68 | if List.length dir_elems >= 2 then |
69 | let base = Common.take 2 dir_elems in | |
ae4735db | 70 | (fun dir_elems' -> |
34e49164 C |
71 | List.length dir_elems' >= 2 && Common.take 2 dir_elems' = base), |
72 | base | |
ae4735db C |
73 | else |
74 | (fun dir_elems' -> dir_elems' = dir_elems), | |
34e49164 C |
75 | dir_elems |
76 | in | |
ae4735db | 77 | |
34e49164 C |
78 | let (yes, no) = xs +> Common.partition_either (fun (dir_elems', x) -> |
79 | if cond dir_elems' | |
80 | then Left x | |
81 | else Right (dir_elems', x) | |
82 | ) in | |
83 | (Common.join "/" base, ["NOEMAIL"], (x::yes))::aux_patch no | |
84 | in | |
85 | aux_patch patch_with_dir | |
86 | ||
87 | ||
88 | ||
ae4735db | 89 | let group_patch_subsystem_info patch subinfo = |
34e49164 C |
90 | let patch_with_dir = patch +> List.map (function (CP.File (s,header,body)) -> |
91 | (Common.dirname s), (CP.File (s, header, body)) | |
92 | ) | |
93 | in | |
94 | let index = Maintainers.mk_inverted_index_subsystem subinfo in | |
95 | let hash = Maintainers.subsystem_to_hash subinfo in | |
96 | ||
ae4735db | 97 | let rec aux_patch xs = |
34e49164 C |
98 | match xs with |
99 | | [] -> [] | |
ae4735db C |
100 | | ((dir,patchitem)::xs) as xs' -> |
101 | let leader = | |
102 | try Hashtbl.find index dir | |
103 | with Not_found -> failwith ("cant find leader for : " ^ dir) | |
34e49164 | 104 | in |
ae4735db | 105 | let (emailsleader, subdirs) = |
34e49164 | 106 | try Hashtbl.find hash leader |
ae4735db | 107 | with Not_found -> failwith ("cant find subdirs of : " ^ leader) |
34e49164 C |
108 | in |
109 | ||
110 | (match emailsleader with | |
111 | | ["NOEMAIL"] | [] | [""] -> pr2 ("no leader maintainer for: "^leader); | |
112 | | _ -> () | |
113 | ); | |
114 | ||
115 | let emails = ref emailsleader in | |
116 | let allsubdirs = (leader, emailsleader)::subdirs in | |
117 | ||
118 | let (yes, no) = xs' +> Common.partition_either (fun (dir',patchitem')-> | |
119 | try ( | |
120 | let emailsdir' = List.assoc dir' allsubdirs in | |
121 | emails := !emails $+$ emailsdir'; | |
122 | Left patchitem' | |
123 | ) with Not_found -> Right (dir', patchitem') | |
124 | (* | |
125 | if List.mem dir' (leader::subdirs) | |
126 | then Left x | |
127 | else Right (dir', x) | |
128 | *) | |
129 | ) in | |
130 | (leader, !emails, yes)::aux_patch no | |
131 | in | |
132 | aux_patch patch_with_dir | |
133 | ||
134 | ||
135 | (*****************************************************************************) | |
136 | (* Split patch *) | |
137 | (*****************************************************************************) | |
ae4735db | 138 | let i_to_s_padded i total = |
34e49164 C |
139 | match i with |
140 | | i when i < 10 && total >= 10 -> "0" ^ i_to_s i | |
141 | | i when i < 100 -> i_to_s i | |
142 | | i -> i_to_s i | |
143 | ||
ae4735db | 144 | let split_patch file prefix bodymail subinfofile = |
34e49164 C |
145 | let patch = CP.parse_patch file in |
146 | ||
147 | let subsystem_info = Maintainers.parse_subsystem_info subinfofile in | |
148 | let minipatches = group_patch_subsystem_info patch subsystem_info in | |
149 | (* let minipatches = group_patch_depth_2 patch in *) | |
150 | ||
151 | let total = List.length minipatches in | |
152 | let minipatches_indexed = Common.index_list_1 minipatches in | |
153 | ||
ae4735db | 154 | let (subject, bodymail_rest) = |
34e49164 | 155 | match Common.cat bodymail with |
ae4735db C |
156 | | x::y::xs -> |
157 | if x =~ "Subject: \\(.*\\)" | |
34e49164 C |
158 | then |
159 | let subject = matched1 x in | |
ae4735db | 160 | if y =~ "[-]+$" |
34e49164 C |
161 | then |
162 | subject, xs | |
163 | else failwith ("wrong format for mailbody in:" ^ bodymail) | |
164 | else failwith ("wrong format for mailbody in:" ^ bodymail) | |
165 | | _ -> failwith ("wrong format for mailbody in:" ^ bodymail) | |
166 | in | |
167 | ||
168 | Common.command2_y_or_no ("rm -f " ^ prefix ^ "*"); | |
34e49164 | 169 | |
ae4735db C |
170 | |
171 | minipatches_indexed +> List.iter (fun ((dir,emails, minipatch), i) -> | |
34e49164 C |
172 | let numpatch = i_to_s_padded i total in |
173 | let tmpfile = prefix ^ numpatch ^ ".mail" in | |
174 | let patchfile = "/tmp/x.patch" in | |
175 | pr2 ("generating :" ^ tmpfile ^ " for " ^ dir); | |
176 | ||
177 | CP.unparse_patch minipatch patchfile; | |
178 | ||
ae4735db | 179 | let emails = |
34e49164 | 180 | (match emails with |
ae4735db | 181 | | ["NOEMAIL"] | [] | [""] -> |
34e49164 C |
182 | pr2 "no maintainer"; [] |
183 | | xs -> xs | |
184 | ) @ ["akpm@linux-foundation.org"] | |
185 | in | |
186 | ||
187 | ||
188 | if !just_patch | |
189 | then command2(sprintf "cat %s > %s" patchfile tmpfile) | |
190 | else begin | |
ae4735db | 191 | Common.with_open_outfile tmpfile (fun (pr_no_nl, chan) -> |
34e49164 C |
192 | let pr s = pr_no_nl (s ^ "\n") in |
193 | pr "To: kernel-janitors@vger.kernel.org"; | |
ae4735db | 194 | pr (sprintf "Subject: [PATCH %s/%d] %s, for %s" |
34e49164 C |
195 | numpatch total subject dir); |
196 | pr ("Cc: " ^ (Common.join ", " (emails @ ["linux-kernel@vger.kernel.org"]))); | |
197 | pr "BCC: padator@wanadoo.fr"; | |
198 | pr "From: Yoann Padioleau <padator@wanadoo.fr>"; | |
199 | pr "--text follows this line--"; | |
ae4735db | 200 | |
34e49164 C |
201 | pr ""; |
202 | bodymail_rest +> List.iter pr; | |
203 | pr ""; | |
204 | pr "Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>"; | |
ae4735db | 205 | emails +> List.iter (fun s -> |
34e49164 C |
206 | pr ("Cc: " ^ s) |
207 | ); | |
208 | pr "---"; | |
209 | ||
210 | pr ""; | |
211 | ); | |
212 | ||
213 | command2(sprintf "diffstat -p1 %s >> %s" patchfile tmpfile); | |
214 | command2(sprintf "echo >> %s" tmpfile); | |
215 | command2(sprintf "cat %s >> %s" patchfile tmpfile); | |
216 | end | |
217 | ) | |
218 | ||
ae4735db | 219 | |
34e49164 C |
220 | |
221 | (*****************************************************************************) | |
222 | (* Test *) | |
223 | (*****************************************************************************) | |
224 | ||
ae4735db | 225 | let test_patch file = |
34e49164 C |
226 | let patch = CP.parse_patch file in |
227 | let groups = group_patch_depth_2 patch in | |
ae4735db | 228 | groups +> List.iter (fun (dir, email, minipatch) -> |
34e49164 C |
229 | print_header_patch minipatch; |
230 | pr "" | |
231 | ) | |
232 | ||
233 | ||
234 | (*****************************************************************************) | |
235 | (* Main entry point *) | |
236 | (*****************************************************************************) | |
237 | ||
ae4735db | 238 | let main () = |
34e49164 C |
239 | begin |
240 | let args = ref [] in | |
241 | let options = [ | |
242 | "-just_patch", Arg.Set just_patch, ""; | |
243 | "-no_verbose", Arg.Clear verbose, ""; | |
244 | ] in | |
ae4735db C |
245 | let usage_msg = |
246 | "Usage: " ^ basename Sys.argv.(0) ^ | |
247 | " <patch> <prefix> <bodymailfile> <maintainerfile> [options]" ^ "\n" | |
34e49164 C |
248 | ^ "Options are:" |
249 | in | |
250 | ||
251 | Arg.parse (Arg.align options) (fun x -> args := x::!args) usage_msg; | |
252 | args := List.rev !args; | |
253 | ||
254 | (match (!args) with | |
255 | | [patch] -> test_patch patch | |
ae4735db | 256 | | [patch;prefix;bodymail;subinfofile] -> |
34e49164 C |
257 | split_patch patch prefix bodymail subinfofile; |
258 | ||
259 | command2("rm -f /tmp/split_check*"); | |
ae4735db | 260 | let checkfile = "/tmp/split_check.all" in |
34e49164 | 261 | let checkprefix = "/tmp/split_check-xx" in |
ae4735db C |
262 | save_excursion verbose (fun () -> |
263 | save_excursion just_patch (fun () -> | |
34e49164 C |
264 | just_patch := true; |
265 | verbose := false; | |
266 | split_patch patch checkprefix bodymail subinfofile; | |
267 | )); | |
268 | command2("cat /tmp/split_check*.mail > " ^ checkfile); | |
269 | ||
ae4735db | 270 | let diff = Common.cmd_to_list (sprintf "diff %s %s " patch checkfile) |
34e49164 C |
271 | in |
272 | let samesize = Common.filesize patch = Common.filesize checkfile in | |
273 | if (List.length diff <> 0) | |
274 | then | |
ae4735db | 275 | if samesize |
34e49164 C |
276 | then pr2 "diff but at least same size" |
277 | else pr2 "PB: diff and not same size" | |
ae4735db C |
278 | |
279 | | _ -> Arg.usage (Arg.align options) usage_msg; | |
34e49164 C |
280 | ) |
281 | end | |
282 | ||
283 | (*****************************************************************************) | |
284 | let _ = | |
285 | main () | |
286 |