1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
|
(**************************************************************************)
(* Copyright © 2009 Stéphane Glondu <steph@glondu.net> *)
(* *)
(* This program is free software: you can redistribute it and/or modify *)
(* it under the terms of the GNU Affero General Public License as *)
(* published by the Free Software Foundation, either version 3 of the *)
(* License, or (at your option) any later version, with the additional *)
(* exemption that compiling, linking, and/or using OpenSSL is allowed. *)
(* *)
(* This program is distributed in the hope that it will be useful, but *)
(* WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *)
(* Affero General Public License for more details. *)
(* *)
(* You should have received a copy of the GNU Affero General Public *)
(* License along with this program. If not, see *)
(* <http://www.gnu.org/licenses/>. *)
(**************************************************************************)
open Printf
open Tyxml.Html
open Ben
open Types
open Core
open Common
let use_colors = ref false
let output_file = ref None
let input_source = ref Ben.Types.NoSource
let baseurl = ref "file:///.."
type output_format = Text | Xhtml | Levels | Json
let output_format = ref Levels
let output_format_from_string = function
| "text" -> Text
| "xhtml" | "html" -> Xhtml
| "json" -> Json
| "color" ->
use_colors := true;
Text
| _ -> Levels
let format_of_string = function
| "html" -> Xhtml
| "json" -> Json
| "txt" -> Text
| "levels" -> Levels
| s -> Printf.ksprintf invalid_arg "invalid format: %s" s
let string_of_format = function
| Text -> "txt"
| Json -> "json"
| Xhtml -> "html"
| Levels -> "levels"
let map_fun f l =
let fr = Frontend.get_selected_frontend () in
if fr.Frontend.name = "monitor" then
Parallel.map ~level:(Parallel.get_level ()) f l
else List.map f l
let get_config config key =
try StringMap.find key config
with Not_found -> Error.raise (Error.Missing_configuration_item key)
let is_affected config = lazy (Query.of_expr (get_config config "is_affected"))
let is_good config = lazy (Query.of_expr (get_config config "is_good"))
let is_bad config = lazy (Query.of_expr (get_config config "is_bad"))
open Modules
open Marshallable
open Data
let format_arch x =
let f =
match x with
| Unknown -> fun x -> "." ^ x ^ "."
| Up_to_date -> fun x -> "(" ^ x ^ ")"
| Outdated -> fun x -> "[" ^ x ^ "]"
| Partial -> fun x -> "¿" ^ x ^ "?"
in
let f =
if !use_colors then
match x with
| Unknown -> f
| Up_to_date -> fun x -> "\027[32m" ^ f x ^ "\027[0m"
| Outdated -> fun x -> "\027[1m\027[31m" ^ f x ^ "\027[0m"
| Partial -> fun x -> "\027[33m" ^ f x ^ "\027[0m"
else f
in
f
let ben_webpage = "https://debian.pages.debian.net/ben/"
let print_dep_line fmt src deps =
Format.fprintf fmt "%s:" !!!src;
S.iter (fun dep -> Format.fprintf fmt " %s" !!!dep) deps;
Format.fprintf fmt "\n%!"
let spec =
Arg.align
[
( "--run-debcheck",
Arg.Set Data.run_debcheck,
" Run debcheck to register installability information" );
( "--use-projectb",
Arg.Set Data.use_projectb,
" Get package lists from Projectb database" );
( "--output",
Arg.String (fun filename -> output_file := Some filename),
" Path to output file" );
( "-o",
Arg.String (fun filename -> output_file := Some filename),
" Path to output file" );
( "--output-format",
Arg.String
(fun format -> output_format := output_format_from_string format),
" Format of output" );
( "-f",
Arg.String
(fun format -> output_format := output_format_from_string format),
" Format of output" );
( "-stdin",
Arg.Unit (fun () -> input_source := Types.Stdin),
" Use stdin to read the input file" );
( "--template",
Arg.String (fun template -> Templates.load_template template),
" Select an HTML template" );
]
let check_media_dir base =
let mediad = base // "media" in
if not (Sys.file_exists mediad) then Unix.symlink !Clflags.media_dir mediad
else
match (Unix.stat mediad).Unix.st_kind with
| Unix.S_LNK ->
let target = Unix.readlink mediad in
if target != !Clflags.media_dir then (
Unix.unlink mediad;
Unix.symlink !Clflags.media_dir mediad)
| _ -> ()
let compute_state config pkg =
if Query.eval_binary pkg !!(is_bad config) then
if Query.eval_binary pkg !!(is_good config) then Partial else Outdated
else if Query.eval_binary pkg !!(is_good config) then Up_to_date
else Unknown
let combine_states state1 state2 =
match (state1, state2) with
| Partial, _ | _, Partial -> Partial
| Outdated, Up_to_date | Up_to_date, Outdated -> Partial
| Outdated, _ | _, Outdated -> Outdated
| Up_to_date, _ | _, Up_to_date -> Up_to_date
| Unknown, Unknown -> state2
let archs_list config =
let expr_l = function Types.EList l -> l | _ -> assert false in
let release_archs_list = expr_l (Clflags.get_config config "architectures") in
let ignored_archs_list =
try expr_l (Clflags.get_config config "ignored") with _ -> []
in
let archs_list = Core.uniq (release_archs_list @ ignored_archs_list) in
List.sort Stdlib.compare archs_list
let compute_monitor_data config sources binaries rounds =
map_fun
(fun xs ->
let packages = List.sort (fun x y -> compare !!!x !!!y) xs in
map_fun
(fun sname ->
let src = M.find sname sources in
let src_name = Package.get "package" src in
let states =
List.map
(function
| Types.EString arch ->
(* FIXME: indexing by name+arch is not a good idea after all *)
( arch,
PAMap.fold
(fun (_, arch') pkg (reasons, accu) ->
if arch' = arch && Package.get "source" pkg = src_name
then
let reason =
try
Printf.sprintf " %s\n"
(Package.get "debcheck-reason" pkg)
with _ -> ""
in
let reasons =
Printf.sprintf "%s%s" reasons reason
in
let state = compute_state config pkg in
(reasons, combine_states accu state)
else (reasons, accu))
binaries ("", Unknown) )
| _ -> assert false)
(archs_list config)
in
(src, states))
packages)
rounds
type transition_data = {
config : Types.expr Core.StringMap.t;
monitor_data :
(Package.source Package.t * (string * (string * status)) list) list list;
sources : (Package.source, Package.source Package.t) Package.Map.t;
binaries : Package.binary Package.t Modules.PAMap.t;
rounds : Package.source Package.Name.t list list;
dep_graph : (Package.source, Package.source Package.Set.t) Package.Map.t;
all : int;
bad : int;
packages : Package.source Data.S.t;
}
let print_text_monitor fmt { config; monitor_data; sources; rounds; _ } =
let nmax =
M.fold
(fun src _ accu ->
let n = String.length !!!src in
if n > accu then n else accu)
sources 0
in
let architectures =
List.map (Frontend.to_string "architectures") (archs_list config)
in
let width = String.length (String.concat " " architectures) + 6 + nmax in
let nrounds = String.length (string_of_int (List.length rounds)) in
let hwidth = String.length "> Dependency level <" + nrounds in
let header_fmt =
let width = width - hwidth + 2 in
let left = width / 2 in
let right = width - left in
let buf = Buffer.create 64 in
for _ = 1 to left do
Buffer.add_char buf '='
done;
bprintf buf "> Dependency level %%%dd <" nrounds;
for _ = 1 to right do
Buffer.add_char buf '='
done;
Buffer.add_char buf '\n';
Scanf.format_from_string (Buffer.contents buf) "%d"
in
List.iteri
(fun i xs ->
Format.fprintf fmt header_fmt i;
List.iter
(fun (src, states) ->
let in_testing =
try not (Package.get "is-in-testing" src = "no")
with Not_found -> true
in
let sname = Package.get "package" src in
let sname = if in_testing then sname else "_" ^ sname in
Format.fprintf fmt "%*s:" (nmax + 3) sname;
List.iter
(fun (arch, (_, state)) ->
Format.fprintf fmt " %s" (format_arch state arch))
states;
Format.fprintf fmt "\n")
xs;
Format.fprintf fmt "\n")
monitor_data
let print_json_monitor fmt { monitor_data; _ } =
let levels =
List.mapi
(fun i xs ->
let srcs =
List.map
(fun (src, states) ->
let in_testing =
try not (Package.get "is-in-testing" src = "no")
with Not_found -> true
in
let sname = Package.get "package" src in
let sname = if in_testing then sname else "_" ^ sname in
let archs =
List.map
(fun (arch, (_, state)) ->
Printf.sprintf " \"%s\":\"%s\"" arch
(class_of_status state))
states
in
Printf.sprintf " \"%s\" : {\n%s\n }" sname
(String.concat ",\n" archs))
xs
in
Printf.sprintf " \"%d\" : {\n%s\n }" i (String.concat ",\n" srcs))
monitor_data
in
Format.fprintf fmt "{\n%s\n}" (String.concat ",\n" levels)
let a_link url text = a ~a:[ a_href (uri_of_string url) ] [ txt text ]
let escape x = Uri.pct_encode ~component:`Fragment x
let pts t src = a_link (t.Template.pts ~src:(escape src)) src
let buildd t src ver = a_link (t.Template.buildd ~src ~ver) "build logs"
let buildds t srcs =
match t.Template.buildds ~srcs with
| None -> raise Exit
| Some s -> a_link s "build logs"
let rc_bugs t src =
match t.Template.critical_bugs ~srcs:src with
| None -> raise Exit
| Some s -> a_link s "RC bugs"
let changelog t ver dir src =
small [ a_link (t.Template.changelog ~letter:dir ~src ~ver) ver ]
let generated_on_text () =
[
txt "Page generated by ";
a_link ben_webpage "Ben";
txt " ";
txt Version.version;
txt (Printf.sprintf " on %s" (Core.get_rfc2822_date ()));
]
let overrall_state l =
let _ (* ignored_archs *), release_archs =
List.partition
(fun (arch, _) -> List.mem arch !Clflags.ignored_architectures)
l
in
if List.for_all (fun (_, (_, status)) -> status = Unknown) release_archs then
Unknown
else if
List.for_all (fun (_, (_, status)) -> status <> Outdated) release_archs
then
if List.for_all (fun (_, (_, status)) -> status <> Partial) release_archs
then Up_to_date
else Partial
else Outdated
let generate_stats monitor_data =
List.fold_left
(fun (all, bad, packages) level ->
List.fold_left
(fun (all, bad, packages) (package, statuses) ->
let is_in_testing =
try Package.get "is-in-testing" package = "yes" with _ -> false
in
let package =
Package.Name.of_string (Package.get "package" package)
in
let overrall_state = overrall_state statuses in
let packages = S.add package packages in
let return all bad = (all, bad, packages) in
match overrall_state with
| Outdated when (not !Data.use_projectb) || is_in_testing ->
return (all + 1) (bad + 1)
| Partial when (not !Data.use_projectb) || is_in_testing ->
return (all + 1) (bad + 1)
| Up_to_date -> return (all + 1) bad
| _ -> return all bad)
(all, bad, packages) level)
(0, 0, S.empty) monitor_data
let starts_with text head =
let s = try String.sub text 0 (String.length head) with _ -> text in
s = head
let cut_head text head =
try
let len = String.length head in
String.sub text len (String.length text - len)
with _ -> text
let beautify_text =
let r_link =
Re.Pcre.regexp
"#[0-9]{4,}|[a-z]{3,}://[^\\s><]+|<[^\\s><]+@[^\\s><]+>|[Pp][Tt][Ss]:[a-z0-9+\\-\\.]+|[Bb][Uu][Ii][Ll][Dd][Dd]:[a-z0-9+\\-\\.]+"
in
fun tpl text ->
let t = Re.Pcre.full_split ~rex:r_link text in
List.map
(function
| Re.Pcre.Text s -> txt s
| Re.Pcre.Delim s ->
let l = String.lowercase_ascii s in
if s.[0] = '#' then
let ss = String.sub s 1 (String.length s - 1) in
let link = tpl.Template.bugs ~src:ss in
a_link link s
else if s.[0] = '<' then
let ss = String.sub s 1 (String.length s - 2) in
let link = tpl.Template.msg_id ~mid:ss in
a_link link s
else if starts_with l "pts" then
let text = cut_head s "pts:" in
let link = tpl.Template.pts ~src:text in
a_link link s
else if starts_with l "buildd" then
let text = cut_head s "buildd:" in
let link = tpl.Template.buildd ~src:text ~ver:"" in
a_link link s
else a_link s s
| Re.Pcre.Group _ | Re.Pcre.NoGroup -> (* Ignore this case *) txt "")
t
let compute_graph data config =
let { src_map = sources; bin_map = binaries } =
filter_affected data is_affected config
in
let src_of_bin : (Package.binary, Package.source Package.Name.t) M.t =
PAMap.fold
(fun (name, _) pkg accu ->
let source = Package.get "source" pkg in
M.add name (Package.Name.of_string source) accu)
binaries M.empty
in
let dep_graph = Dependencies.get_dep_graph sources src_of_bin in
let rounds = Dependencies.topo_split dep_graph in
(rounds, sources, binaries, dep_graph)
let compute_transition_data data config =
let rounds, sources, binaries, dep_graph = compute_graph data config in
let monitor_data = compute_monitor_data config sources binaries rounds in
let all, bad, packages = generate_stats monitor_data in
{
config;
monitor_data;
sources;
binaries;
rounds;
dep_graph;
all;
bad;
packages;
}
let has_testing_data monitor_data =
match monitor_data with
| ((src, _) :: _) :: _ -> (
(* if is-in-testing has been injected, it has been injected into
all packages, so just pick any *)
try
let _ = Package.get "is-in-testing" src in
true
with Not_found -> false)
| _ -> false
let print_html_monitor template
{ config; monitor_data; binaries; dep_graph; packages; _ } extra =
let has_testing_data = has_testing_data monitor_data in
let affected = packages in
let mytitle =
try
Query.to_string ~escape:false (Query.of_expr (get_config config "title"))
with _ -> "(no title)"
in
let notes =
try
Query.to_string ~escape:false (Query.of_expr (get_config config "notes"))
with _ -> ""
in
let is_affected = Query.to_string (Lazy.force (is_affected config)) in
let is_good = Query.to_string (Lazy.force (is_good config)) in
let is_bad = Query.to_string (Lazy.force (is_bad config)) in
let archs_count = List.length (archs_list config) in
let page_title = sprintf "Transition: %s" mytitle in
let extra_headers =
[
script
(cdata_script
(sprintf "var nb_columns = %d; var nb_rounds = %d;" (2 + archs_count)
(List.length monitor_data)));
script ~a:[ a_src (uri_of_string "media/jquery.min.js") ] (txt "");
script ~a:[ a_src (uri_of_string "media/script.js") ] (txt "");
]
in
let hbody table =
[
b [ txt "Parameters:" ];
ul
~a:[ a_class [ "parameters" ] ]
[
li [ small [ b [ txt "Affected: " ]; txt is_affected ] ];
li [ small [ b [ txt "Good: " ]; txt is_good ] ];
li [ small [ b [ txt "Bad: " ]; txt is_bad ] ];
];
(if String.length notes = 0 then div []
else
div
~a:[ a_class [ "parameters" ] ]
[ small [ b [ txt "Notes: " ] ]; pre (beautify_text template notes) ]);
div
[
txt "Filter by status: ";
input ~a:[ a_input_type `Checkbox; a_id "good" ] ();
label ~a:[ a_label_for "good" ] [ txt "good" ];
txt " ";
input ~a:[ a_input_type `Checkbox; a_checked (); a_id "partial" ] ();
label ~a:[ a_label_for "partial" ] [ txt "partial" ];
txt " ";
input ~a:[ a_input_type `Checkbox; a_checked (); a_id "bad" ] ();
label ~a:[ a_label_for "bad" ] [ txt "bad" ];
txt " ";
input ~a:[ a_input_type `Checkbox; a_checked (); a_id "unknown" ] ();
label ~a:[ a_label_for "unknown" ] [ txt "unknown" ];
txt " ";
span ~a:[ a_id "count" ] [];
];
div
(if has_testing_data then
[
input ~a:[ a_input_type `Checkbox; a_id "notintesting" ] ();
label
~a:[ a_label_for "notintesting" ]
[ txt "ignore packages that are not in testing" ];
]
else []);
table;
]
in
let footer = [ small (generated_on_text ()) ] in
let abrege = function
| "hurd-i386" -> "hurd"
| "kfreebsd-amd64" -> "kbsd64"
| "kfreebsd-i386" -> "kbsd32"
| "powerpc" -> "ppc"
| x -> x
in
let archs_columns =
List.map
(function
| Types.EString arch when List.mem arch !Clflags.ignored_architectures
->
th [ small [ i [ txt (abrege arch) ] ] ]
| Types.EString arch -> th [ small [ txt (abrege arch) ] ]
| _ -> assert false)
(archs_list config)
in
let archs_columns round header =
tr ~a:[ a_id (sprintf "header%d" round) ] (header :: archs_columns)
in
let rows, _ =
List.fold_left
(fun (rows, i) xs ->
let names, rows =
List.fold_left
(fun (sources, acc) (source, states) ->
let src = Package.get "package" source in
let is_arch_all = Package.get "architecture" source = "all" in
let has_ma_same =
List.exists
(fun bin ->
List.exists
(fun arch ->
try
let pkg = PAMap.find (bin, arch) binaries in
Package.get "multi-arch" pkg = "same"
with Not_found -> false)
(List.map
(Frontend.to_string "architectures")
(archs_list config)))
(Package.binaries source)
in
let has_additional_text, additional_texts =
List.fold_left
(fun (has, acc) (property, text) ->
if property then (property || has, text :: acc)
else (has, acc))
(false, [])
[ (is_arch_all, "arch:all"); (has_ma_same, "ma:same") ]
in
let additional_text = String.concat ", " additional_texts in
let additional_text_html =
if has_additional_text then
[ txt " ["; small [ txt additional_text ]; txt "]" ]
else []
in
let in_testing =
try not (Package.get "is-in-testing" source = "no")
with Not_found -> true
in
let classes =
[ "src"; sprintf "round%d" i ]
@ if in_testing then [] else [ "notintesting" ]
in
let deps = M.find (Package.Name.of_string src) dep_graph in
let deps = S.filter (fun p -> S.mem p affected) deps in
let deps =
if S.is_empty deps then ""
else
let names = List.map ( !!! ) (S.elements deps) in
"Dependencies: " ^ String.concat ", " names
in
let version = Package.get "version" source in
let directory = Package.get "directory" source in
let sources = src :: sources in
let overrall_state =
[ class_of_status (overrall_state states) ]
in
let src_text =
pts template src
:: (if in_testing then [] else [ txt " (sid only)" ])
in
let acc =
tr
([
td
~a:
[
a_class ("srcname" :: (overrall_state @ classes));
a_id src;
a_title deps;
]
src_text;
td
~a:[ a_class [ "src" ] ]
([
txt "[";
buildd template (escape src) version;
txt "] (";
changelog template (sprintf "%s" version) directory
(escape src);
txt ")";
]
@ additional_text_html);
]
@ List.map
(fun (_, (reasons, state)) ->
td
~a:
[
a_class [ class_of_status state ]; a_title reasons;
]
[ small [ txt (string_of_status state) ] ])
states)
:: acc
in
(sources, acc))
([], rows) (List.rev xs)
in
let escaped_names = List.map (fun x -> escape x) names in
let column_arg =
try
let buildd_link = buildds template escaped_names in
let rc_bugs_link = rc_bugs template escaped_names in
[ txt " ("; buildd_link; txt " "; rc_bugs_link; txt ")" ]
with Exit -> []
in
let title = txt (sprintf "Dependency level %d" (i + 1)) in
let tr_cols =
archs_columns i
(th ~a:[ a_colspan 2; a_class [ "level" ] ] (title :: column_arg))
in
let rows = tr_cols :: rows in
(rows, i - 1))
([], List.length monitor_data - 1)
(List.rev monitor_data)
in
let table = table rows in
let content =
match extra with
| None -> table
| Some extra -> div ~a:[ a_class [ "content" ] ] [ table; extra ]
in
let subtitle =
[
a_link (Filename.concat !baseurl "index.html") "Transitions";
txt (Printf.sprintf " → %s" mytitle);
]
in
let html =
template.Template.page ~title:page_title ~subtitle ~headers:extra_headers
~body:(hbody content) ~footer
in
html
let print_dependency_levels fmt { dep_graph; rounds; _ } =
List.iteri
(fun i xs ->
Format.fprintf fmt "===[ Dependency level %d ]=====\n" i;
let packages = List.sort (fun x y -> compare !!!x !!!y) xs in
List.iter
(fun src ->
let deps = M.find src dep_graph in
print_dep_line fmt src deps)
packages)
rounds
let print_monitor format fmt transition_data =
match format with
| Levels -> print_dependency_levels fmt transition_data
| Text -> print_text_monitor fmt transition_data
| Json -> print_json_monitor fmt transition_data
| Xhtml ->
let template = Templates.get_registered_template () in
let output = print_html_monitor template transition_data None in
Format.fprintf fmt "%a\n%!" (Tyxml.Html.pp ()) output
let main _ =
let config =
match !input_source with
| Types.NoSource -> Error.raise Error.Missing_configuration_file
| _ as source -> Frontend.read_config ~multi:true source
in
let archs_list =
Frontend.to_string_l "architectures"
(Clflags.get_config config "architectures")
in
let data = Data.load_cache archs_list in
let transition_data = compute_transition_data data config in
let fmt, close =
match !output_file with
| None -> (Format.std_formatter, fun () -> ())
| Some file ->
let oc = open_out file in
(Format.formatter_of_out_channel oc, fun () -> close_out oc)
in
let () =
match (!output_format, !output_file) with
| Xhtml, Some file -> check_media_dir (Filename.basename file)
| _, _ -> ()
in
print_monitor !output_format fmt transition_data;
close ()
let anon_fun file =
if String.ends_with file ~suffix:".ben" then input_source := Types.File file
let frontend =
{
Frontend.name = "monitor";
Frontend.main;
Frontend.anon_fun;
Frontend.help = spec;
}
|