| 1 | (* sort a list of git codes such that the most recent comes first *) |
| 2 | |
| 3 | let git_home = ref "/home/julia/linux-2.6" |
| 4 | |
| 5 | let unwind_protect f cleanup = |
| 6 | try f () |
| 7 | with e -> begin cleanup e; raise e end |
| 8 | |
| 9 | let (with_open_infile: string -> ((in_channel) -> 'a) -> 'a) = fun file f -> |
| 10 | let chan = open_in file in |
| 11 | unwind_protect (fun () -> |
| 12 | let res = f chan in |
| 13 | close_in chan; |
| 14 | res) |
| 15 | (fun e -> close_in chan) |
| 16 | |
| 17 | (* ----------------------------------------------------------------------- *) |
| 18 | |
| 19 | let months = |
| 20 | [("Jan",1);("Feb",2);("Mar",3);("Apr",4);("May",5);("Jun",6);("Jul",7); |
| 21 | ("Aug",8);("Sep",9);("Oct",10);("Nov",11);("Dec",12)] |
| 22 | |
| 23 | let antimonths = |
| 24 | [(1,31);(2,28);(3,31);(4,30);(5,31); (6,30);(7,31);(8,31);(9,30);(10,31); |
| 25 | (11,30);(12,31);(0,31)] |
| 26 | |
| 27 | let normalize (year,month,day,hour,minute,second) = |
| 28 | if hour < 0 |
| 29 | then |
| 30 | let (day,hour) = (day - 1,hour + 24) in |
| 31 | if day = 0 |
| 32 | then |
| 33 | let month = month - 1 in |
| 34 | let day = List.assoc month antimonths in |
| 35 | let day = |
| 36 | if month = 2 && year / 4 * 4 = year && not (year / 100 * 100 = year) |
| 37 | then 29 |
| 38 | else day in |
| 39 | if month = 0 |
| 40 | then (year-1,12,day,hour,minute,second) |
| 41 | else (year,month,day,hour,minute,second) |
| 42 | else (year,month,day,hour,minute,second) |
| 43 | else (year,month,day,hour,minute,second) |
| 44 | |
| 45 | exception Fail of string |
| 46 | |
| 47 | let read_info code = |
| 48 | let _ = |
| 49 | Sys.command |
| 50 | (Printf.sprintf |
| 51 | "pushd %s >& /dev/null ; git log %s^..%s | grep Date: > /tmp/gitsort_info ; popd >& /dev/null" |
| 52 | !git_home code code) in |
| 53 | with_open_infile "/tmp/gitsort_info" (fun i -> |
| 54 | let l = |
| 55 | try input_line i |
| 56 | with End_of_file -> raise (Fail "bad git file") in |
| 57 | match Str.split (Str.regexp " ") l with |
| 58 | [date;_;_;weekday;month;day;time;year;offset] -> |
| 59 | let day = int_of_string day in |
| 60 | let month = List.assoc month months in |
| 61 | let year = int_of_string year in |
| 62 | (match Str.split (Str.regexp ":") time with |
| 63 | [hour;minute;second] -> |
| 64 | let hour = int_of_string hour in |
| 65 | let minute = int_of_string minute in |
| 66 | let second = int_of_string second in |
| 67 | let modifier = |
| 68 | match String.get offset 0 with |
| 69 | '-' -> -1 |
| 70 | | '+' -> 1 |
| 71 | | _ -> raise (Fail "bad offset") in |
| 72 | (if not (String.sub offset 3 2 = "00") |
| 73 | then raise (Fail "require 0 minutes difference")); |
| 74 | let hour = |
| 75 | hour + (modifier * (int_of_string (String.sub offset 1 2))) in |
| 76 | normalize (year,month,day,hour,minute,second) |
| 77 | | _ -> raise (Fail "bad date2")) |
| 78 | | l -> raise (Fail ("bad date1: "^(String.concat "|" l)))) |
| 79 | |
| 80 | let rec get_dates = function |
| 81 | [] -> [] |
| 82 | | code::rest -> |
| 83 | let date = |
| 84 | try Some (read_info code) |
| 85 | with |
| 86 | Fail s -> Printf.printf "problem in %s: %s\n" code s; None |
| 87 | | _ -> Printf.printf "problem in %s\n" code; None in |
| 88 | match date with |
| 89 | Some date -> (date,code)::(get_dates rest) |
| 90 | | None -> get_dates rest |
| 91 | |
| 92 | let get_codes file = |
| 93 | let gits = ref ([] : string list) in |
| 94 | with_open_infile file (fun i -> |
| 95 | let rec loop _ = |
| 96 | let git = try Some (input_line i) with End_of_file -> None in |
| 97 | match git with |
| 98 | Some x -> gits := x :: !gits; loop() |
| 99 | | None -> () in |
| 100 | loop ()); |
| 101 | List.concat |
| 102 | (List.map |
| 103 | (function l -> |
| 104 | List.filter |
| 105 | (* all because I don't know how to make a backslash regexp...*) |
| 106 | (function x -> String.length x > 10) |
| 107 | (Str.split (Str.regexp "[ \t]+") l)) |
| 108 | !gits) |
| 109 | |
| 110 | let _ = |
| 111 | let args = Array.to_list Sys.argv in |
| 112 | let file = |
| 113 | match args with |
| 114 | [_;git_home_info;gits] -> git_home := git_home_info; gits |
| 115 | | [_;gits] -> gits |
| 116 | | _ -> failwith "args: [git home] git_codes_file" in |
| 117 | let codes = get_codes file in |
| 118 | let dates = get_dates codes in |
| 119 | match List.sort compare dates with |
| 120 | (_,last)::prev -> |
| 121 | List.iter (function (_,x) -> Printf.printf "%s \\\n" x) (List.rev prev); |
| 122 | Printf.printf "%s\n" last |
| 123 | | _ -> () |
| 124 | |
| 125 | |
| 126 | |