let rec my_int_of_string s =
let len = String.length s in
if len <= 0 then invalid_arg "my_int_of_string";
match s.[0] with
'+' -> my_int_of_string (String.sub s 1 (len - 1))
| _ -> int_of_string s
let parse_svn_log wc_dir =
let re_line = "r\\([0-9]+\\) | \\([^ ]+\\) | \\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\) \\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\) \\([+-][0-9][0-9]\\)[^|]*| \\([0-9]+\\) " in
let re_line = Str.regexp re_line in
let read_entry ic =
let line = input_line ic in
if Str.string_match re_line line 0 then
begin
let g n = Str.matched_group n line in
let revid = my_int_of_string (g 1) in
let login = g 2 in
let year = my_int_of_string (g 3) in
let month = my_int_of_string (g 4) in
let day = my_int_of_string (g 5) in
let hour = my_int_of_string (g 6) in
let min = my_int_of_string (g 7) in
let sec = my_int_of_string (g 8) in
let tz = my_int_of_string (g 9) in
let lines = my_int_of_string (g 10) in
let b = Buffer.create 256 in
ignore(input_line ic);
for i = 1 to lines do
Printf.bprintf b "%s\n" (input_line ic)
done;
Some (revid, login, (year, month, day, hour, min, sec, tz), Buffer.contents b)
end
else
None
in
let command = Printf.sprintf "(cd %s && svn log)" (Filename.quote wc_dir) in
try
let ic = Unix.open_process_in command in
let l = ref [] in
begin
try
while true do
match read_entry ic with
Some e -> l := e :: !l
| None -> ()
done
with
End_of_file -> ignore(Unix.close_process_in ic)
end;
!l
with
Unix.Unix_error (e,s1,s2) ->
let msg = Printf.sprintf "%s %s: %s"
(Unix.error_message e) s2 s1
in
failwith msg
;;
let chop_n_char n s =
let len = String.length s in
if len <= n +1 or n < 0 then
s
else
Printf.sprintf "%s..." (String.sub s 0 (n+1))
let tdl_item_of_entry (revid, login, d, comment) =
let (y,m,d,h,mi,s,tz) = d in
let date = {
Tdl.year = y;
month = m ;
day = d ;
hour = h;
minute = m;
second = s;
zone = tz * 60;
week_day = - 1;
}
in
let title = Printf.sprintf "[r%d] %s"
revid
(chop_n_char 40 (Str.global_replace (Str.regexp "\n\008*") "; " comment))
in
Tdl.item ~title ~enddate: date ~date ~desc: comment ~state: Tdl.Done ()
;;
let tdl_of_svn_log ~login ~title ~dir =
let re_login = Str.regexp login in
let entries = parse_svn_log dir in
prerr_endline (Printf.sprintf "%d entries" (List.length entries));
let entries = List.filter
(fun (_,login,_,_) -> Str.string_match re_login login 0)
entries
in
prerr_endline (Printf.sprintf "%d entries after filtering" (List.length entries));
let items = List.map tdl_item_of_entry entries in
let g = Tdl.group ~title ~items () in
Tdl.group ~title: dir ~groups: [g] ()
;;
let login = ref ".*";;
let group_title = ref "Commits";;
let options = [
"-l", Arg.Set_string login,
"<regexp>\tconsider only log entries with a login matching the given "^
"regular expression" ;
"-g", Arg.Set_string group_title,
"<title>\tuse the given title for the group in the created TODO list";
];;
let dir = ref None;;
let main () =
Arg.parse options
(fun s -> match !dir with
None -> dir := Some s
| _ -> failwith "Please give only working copy directory"
)
(Printf.sprintf
"Usage: %s [options] [<directory of a subversion working copy>]\nwhere options are:"
Sys.argv.(0)
);
let dir = match !dir with None -> Filename.current_dir_name | Some d -> d in
let tdl = tdl_of_svn_log ~login: !login ~title: !group_title ~dir in
Tdl.print_group Format.std_formatter tdl;
Format.print_flush ()
;;
let safe_main main =
try main ()
with
Failure s
| Sys_error s ->
prerr_endline s;
exit 1
let () = safe_main main