Author: glondu-guest Date: Wed Feb 25 00:05:41 2009 New Revision: 6257 URL: http://svn.debian.org/wsvn/?sc=1&rev=6257 Log: Add a script to monitor transitions
Added: trunk/tools/ocaml_transition_monitor/ trunk/tools/ocaml_transition_monitor/Makefile trunk/tools/ocaml_transition_monitor/ocaml-status.css trunk/tools/ocaml_transition_monitor/ocaml_transition_monitor.mll Added: trunk/tools/ocaml_transition_monitor/Makefile URL: http://svn.debian.org/wsvn/trunk/tools/ocaml_transition_monitor/Makefile?rev=6257&op=file ============================================================================== --- trunk/tools/ocaml_transition_monitor/Makefile (added) +++ trunk/tools/ocaml_transition_monitor/Makefile Wed Feb 25 00:05:41 2009 @@ -1,0 +1,10 @@ +all: ocaml_transition_monitor.byte + +%.byte: %.ml + ocamlfind ocamlc -package ocsigen.xhtml,str -linkpkg -o $@ $< + +%.ml: %.mll + ocamllex $< + +clean: + rm -f Packages.* *.html *.cm* *.byte *~ Added: trunk/tools/ocaml_transition_monitor/ocaml-status.css URL: http://svn.debian.org/wsvn/trunk/tools/ocaml_transition_monitor/ocaml-status.css?rev=6257&op=file ============================================================================== --- trunk/tools/ocaml_transition_monitor/ocaml-status.css (added) +++ trunk/tools/ocaml_transition_monitor/ocaml-status.css Wed Feb 25 00:05:41 2009 @@ -1,0 +1,41 @@ +body { + font-family: sans-serif; +} +h1 { + margin: 0; + padding: 5px 0px 5px 150px; + height: 50px; + background: #df0451; + color: white; + margin-bottom: 1em; + border-bottom: 2px solid #af0031; + background-image: url(http://caml.inria.fr//pub/logos/caml-inria-fr.128x58.gif); + background-repeat: no-repeat; +} +div.status { + text-align: center; +} +div.status table a { + text-decoration: none; +} +div#footer { + margin-top: 2em; + font-size: 60%; +} + +.good { + background: LightGreen; +} + +.bad { + background: Salmon; +} + +.unknown { + background: Cornsilk; +} + +td { + border-style: solid; + border-width: 1px; +} Added: trunk/tools/ocaml_transition_monitor/ocaml_transition_monitor.mll URL: http://svn.debian.org/wsvn/trunk/tools/ocaml_transition_monitor/ocaml_transition_monitor.mll?rev=6257&op=file ============================================================================== --- trunk/tools/ocaml_transition_monitor/ocaml_transition_monitor.mll (added) +++ trunk/tools/ocaml_transition_monitor/ocaml_transition_monitor.mll Wed Feb 25 00:05:41 2009 @@ -1,0 +1,242 @@ +(* + Copyright © 2009 Stéphane Glondu <st...@glondu.net> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Dependencies: wget, bzip2, ocsigen-dev. +*) + +{ + let ocaml_version = "3.11.0" + + let mirror = "http://ftp.fr.debian.org/debian" + let suite = "unstable" + let section = "main" + + let architectures = + [ "alpha"; "amd64"; "armel"; "hppa"; "i386"; "ia64"; "mips"; "mipsel"; "powerpc"; "s390"; "sparc" ] + + module S = Set.Make(String) + module M = Map.Make(String) + + open Printf + open XHTML.M + + type source_package = { + sname: string; + sdeps: string list; + sbins : string list; + sversion: string; + } + type binary_package = { + bname: string; + bdeps: string list; + bsrc: string; + bversion: string; + bnmu: int; + } + + let headers_to_keep = + [ "Package"; "Binary"; "Version"; "Build-Depends"; "Depends"; "Architecture"; "Source"; "Provides" ] + + type status = Unknown | Up_to_date | Outdated + let string_of_status = function + | Unknown -> "unknown" + | Up_to_date -> "good" + | Outdated -> "bad" + + let skip_download = ref false + let quiet_mode = ref false + + let progress x = + if !quiet_mode then ifprintf stderr x else fprintf stderr x +} + +let name = ['A'-'Z' 'a'-'z' '0'-'9' '-' '.' ':' '~' '+']+ + +rule entry accu = parse + | ([^':' '\n']+ as header) ":" + { + if List.mem header headers_to_keep then + (entry ((header, values [] lexbuf)::accu) lexbuf) + else + (skip lexbuf; entry accu lexbuf) + } + | eof | '\n' { if accu = [] then raise End_of_file else accu } +and values accu = parse + | name as name { values (name::accu) lexbuf } + | [' ' ',' '|']+ { values accu lexbuf } + | '(' [^')']* ')' | "\n " | '[' [^']']* ']' + { values accu lexbuf } + | "\n " { values accu lexbuf } + | "\n" { accu } +and skip = parse + | ([^'\n']* "\n ")* [^'\n']* "\n" { () } + +{ + let get_one = function + | [a] -> a + | x -> invalid_arg (sprintf "[%s] should have exactly one element" (String.concat ", " x)) + + let assoc ?default x xs = + try List.assoc x xs + with Not_found -> match default with + | None -> invalid_arg ("Not_found: "^x) + | Some y -> y + + let parse_source channel = + let lexbuf = Lexing.from_channel channel in + let result = ref M.empty in + let rec aux () = + let entry = entry [] lexbuf in + let name = get_one (assoc "Package" entry) in + let entry = { + sname = name; + sdeps = assoc ~default:[] "Build-Depends" entry; + sbins = assoc "Binary" entry; + sversion = get_one (assoc "Version" entry); + } in + result := M.add name entry !result; + aux () + in try aux () with End_of_file -> !result + + let parse_binary channel = + let lexbuf = Lexing.from_channel channel in + let result = ref M.empty in + let rec aux () = + let entry = entry [] lexbuf in + let name = get_one (assoc "Package" entry) in + let entry = { + bname = name; + bdeps = (assoc ~default:[] "Depends" entry) @ (assoc ~default:[] "Provides" entry); + bsrc = get_one (assoc ~default:[name] "Source" entry); + bversion = get_one (assoc "Version" entry); + bnmu = 0; + } in + result := M.add name entry !result; + aux () + in try aux () with End_of_file -> !result + + let runtime_ocaml_regexp = Str.regexp "^ocaml\\(-base\\)?\\(-nox\\)?-\\([0-9.]+\\)$" + let build_ocaml_regexp = Str.regexp "^ocaml\\(-nox\\)?$" + + let depends_on_ocaml x = + let rec aux = function + | [] -> None + | x::xs -> + if Str.string_match runtime_ocaml_regexp x 0 then + Some (Str.matched_group 3 x) + else aux xs + in aux x.bdeps + + let build_depends_on_ocaml x = + let rec aux = function + | [] -> false + | x::xs -> + if Str.string_match build_ocaml_regexp x 0 then + true + else aux xs + in aux x.sdeps + + let with_in_file file f = + let chan = open_in_bin file in + try + let res = f chan in + close_in chan; res + with e -> close_in chan; raise e + + let with_out_file file f = + let chan = open_out_bin file in + try + let res = f chan in + close_out chan; res + with e -> close_out chan; raise e + + let get_arch_status arch = + let binaries = with_in_file ("Packages."^arch) parse_binary in + let runtime_versions = M.fold + (fun k pkg accu -> match depends_on_ocaml pkg with + | None -> accu + | Some version -> M.add k (pkg, version) accu) + binaries M.empty in + let compiled_sources = M.fold + (fun k (pkg, version) accu -> + M.add pkg.bsrc (version = ocaml_version) accu) + runtime_versions M.empty in + compiled_sources + + let get_sources () = + let sources = with_in_file "Packages.source" parse_source in + let sources = M.fold + (fun k pkg accu -> + if build_depends_on_ocaml pkg + || pkg.sname = "ocaml" + || pkg.sname = "dh-ocaml" then M.add k pkg accu else accu) + sources M.empty in + sources + + let get_package_lists () = + List.for_all + (fun arch -> + let url = sprintf "%s/dists/%s/%s/binary-%s/Packages.bz2" mirror suite section arch in + let cmd = sprintf "wget -q -O- '%s' | bzcat > Packages.%s" url arch in + progress "Downloading Packages.%s...%!" arch; + let r = Sys.command cmd in + progress "\n%!"; + r = 0) + architectures + && (let url = sprintf "%s/dists/%s/%s/source/Sources.bz2" mirror suite section in + let cmd = sprintf "wget -q -O- '%s' | bzcat > Packages.source" url in + progress "Downloading Packages.source...%!"; + let r = Sys.command cmd in + progress "\n%!"; + r = 0) + + let main () = + let all_binaries = List.map get_arch_status architectures in + let all_sources = List.sort compare + (M.fold (fun k _ accu -> k::accu) (get_sources ()) []) + in + let status pkg = List.map + (fun x -> + try if M.find pkg x then Up_to_date else Outdated + with Not_found -> Unknown) all_binaries + in + let status = List.map (fun pkg -> (pkg, status pkg)) all_sources in + let all_sources = List.map + (fun (pkg, status) -> tr + (td [a ~a:[a_href (uri_of_string ("http://packages.qa.debian.org/"^pkg))] [pcdata pkg]; + br (); + small [pcdata "["; + a ~a:[a_href (uri_of_string ("http://buildd.debian.org/~luk/status/package.php?p="^pkg))] [pcdata "buildd"]; + pcdata "]"; + ]]) + (List.map (fun x -> let x = string_of_status x in td ~a:[a_class [x]] [pcdata x]) status)) + status + in + let summary = tablex + ~thead:(thead (tr (th [pcdata "Source package"]) (List.map (fun arch -> th [pcdata arch]) architectures)) []) + (match all_sources with x::xs -> tbody x xs | _ -> invalid_arg "there must be at least one package") + [] + in + let page_title = "Monitoring OCaml transition to "^ocaml_version in + let html = html + (head (title (pcdata page_title)) [link ~a:[a_rel [`Stylesheet]; a_href (uri_of_string "ocaml-status.css")] ()]) + (body [h1 [pcdata page_title]; + div ~a:[a_class ["status"]] [summary]]) + in + with_out_file "ocaml_transition_monitor.html" + (fun chan -> output (fun s -> fprintf chan "%s%!" s) html) + + let _ = + let speclist = [ + "--skip-download", Arg.Set skip_download, "Skip downloading package list files"; + "--quiet", Arg.Set quiet_mode, "Quiet mode"; + ] in + Arg.parse speclist (fun s -> raise (Arg.Bad s)) "Generates ocaml_transition_monitor.html"; + if not !skip_download && not (get_package_lists ()) then failwith "Error while downloading lists!"; + main () +} _______________________________________________ Pkg-ocaml-maint-commits mailing list Pkg-ocaml-maint-commits@lists.alioth.debian.org http://lists.alioth.debian.org/mailman/listinfo/pkg-ocaml-maint-commits