-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathospecl_client
executable file
·127 lines (108 loc) · 3.67 KB
/
ospecl_client
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
#!/usr/bin/env ocaml
#use "topfind"
#require "str"
#require "unix"
#require "ospecl"
#thread
(* thread-safe mutable sequence *)
module SafeSeq : sig
type 'a t
val create : 'a list -> 'a t
val next : 'a t -> 'a option
end = struct
type 'a t = {
mutable seq : 'a list;
lock : Mutex.t
}
let create items = {
seq = items;
lock = Mutex.create ()
}
let next safe_seq =
Mutex.lock safe_seq.lock;
let top =
match safe_seq.seq with
| [] -> None
| first::rest -> begin
safe_seq.seq <- rest;
Some first
end
in
Mutex.unlock safe_seq.lock;
top
end
let fire handlers event =
List.iter (fun handle -> handle event) handlers
let execute_file_remotely (in_chan, out_chan) handlers filename =
let rec handle_next_event handlers =
let open Ospecl.Spec.Exec in
match input_value in_chan with
| Execution_finished -> () (* last event, so stop *)
| Execution_started -> (* don't forward these *)
handle_next_event handlers
| event -> begin
fire handlers event;
handle_next_event handlers
end
in
output_string out_chan (filename ^ "\n");
flush out_chan;
handle_next_event handlers
let execute_at_address files handlers address =
let (in_chan, out_chan) as channels = Unix.open_connection address in
let execute_file = execute_file_remotely channels handlers in
let rec execute_next files =
match SafeSeq.next files with
| None -> Unix.shutdown_connection in_chan
| Some file -> begin
execute_file file;
execute_next files
end
in
execute_next files
let execute_in_parallel spec_files handlers addresses =
let spec_file_seq = SafeSeq.create !spec_files in
fire handlers Ospecl.Spec.Exec.Execution_started;
let threads = List.map (Thread.create (execute_at_address spec_file_seq handlers)) addresses in
List.iter Thread.join threads;
fire handlers Ospecl.Spec.Exec.Execution_finished
let _ =
let usage_message =
let this_file = (Filename.basename Sys.argv.(0)) in
Printf.sprintf "usage: %s [options] [spec files... ]
Connects to a running ospecl_server at the given address, and sends each spec file name to be executed there, handling the execution events as they are sent back. The supplied spec files should be source files which define a single top level value - (specs : Ospecl.Spec.t list).
" this_file
in
let color = ref false in
let address_strings = ref [] in
let spec_files = ref [] in
let append_to list_ref value =
list_ref := !list_ref @ [value]
in
let formatter = ref Ospecl.Handlers.Terminal.progress in
let formatters = [
("p", Ospecl.Handlers.Terminal.progress);
("progress", Ospecl.Handlers.Terminal.progress);
("d", Ospecl.Handlers.Terminal.documentation);
("documentation", Ospecl.Handlers.Terminal.documentation);
]
in
let choose_format f =
formatter := List.assoc f formatters
in
Arg.parse (Arg.align [
("-address", Arg.String (append_to address_strings), "IP:PORT of a server to run the specs on");
("-color", Arg.Set color, " enable color in the output");
("-format", Arg.Symbol (fst (List.split formatters), choose_format), " choose a formatter");
]) (append_to spec_files) usage_message;
let addresses = List.map (fun address_string ->
match Str.split (Str.regexp ":") address_string with
| [ip; port] ->
let inet_addr = Unix.inet_addr_of_string ip in
let port_num = int_of_string port in
Unix.ADDR_INET (inet_addr, port_num)
| _ -> failwith "Addresses must be of the form <ip>:<port>"
) !address_strings
in
let handlers = !formatter ~color:!color in
execute_in_parallel spec_files handlers addresses