xref: /inferno-os/appl/cmd/itreplay.b (revision 3f1f06c5d12b24c4061e5123acabf72348ff45a2)
1implement Itreplay;
2
3include "sys.m";
4	sys: Sys;
5include "string.m";
6	str: String;
7include "draw.m";
8include "daytime.m";
9	daytime: Daytime;
10include "bufio.m";
11	bufio: Bufio;
12	Iobuf: import bufio;
13include "readdir.m";
14	readdir: Readdir;
15include "arg.m";
16include "itslib.m";
17	S_INFO, S_WARN, S_ERROR, S_FATAL, S_STIME, S_ETIME: import Itslib;
18
19SUMFILE: con "summary";
20MSGFILE: con "msgs";
21
22verbosity := 3;
23display_stderr := 0;
24display_stdout := 0;
25
26stderr: ref Sys->FD;
27
28
29Itreplay: module
30{
31	init: fn(ctxt: ref Draw->Context, argv: list of string);
32};
33
34
35
36init(nil: ref Draw->Context, args: list of string)
37{
38	sys = load Sys Sys->PATH;
39	stderr = sys->fildes(2);
40	arg := load Arg Arg->PATH;
41	if(arg == nil)
42		nomod(Arg->PATH);
43	daytime = load Daytime Daytime->PATH;
44	if(daytime == nil)
45		nomod(Daytime->PATH);
46	str = load String String->PATH;
47	bufio = load Bufio Bufio->PATH;
48	if(bufio == nil)
49		nomod(Bufio->PATH);
50	if(str == nil)
51		nomod(String->PATH);
52	readdir = load Readdir Readdir->PATH;
53	if(readdir == nil)
54		nomod(Readdir->PATH);
55	arg->init(args);
56	while((o := arg->opt()) != 0)
57		case o {
58		'e' =>	display_stderr++;
59		'o' =>	display_stdout++;
60		'v' =>	verbosity = toint("v", arg->arg(), 0, 9);
61		* =>		usage();
62		}
63	recdirl := arg->argv();
64	arg = nil;
65	if (recdirl == nil)
66		usage();
67	while (recdirl != nil) {
68		dir := hd recdirl;
69		recdirl = tl recdirl;
70		replay(dir);
71	}
72}
73
74usage()
75{
76	sys->fprint(stderr, "Usage: itreplay [-eo] [-v verbosity] recorddir ...\n");
77	raise "fail: usage";
78	exit;
79}
80
81fatal(s: string)
82{
83	sys->fprint(stderr, "%s\n", s);
84	raise "fail: error";
85	exit;
86}
87
88nomod(mod: string)
89{
90	sys->fprint(stderr, "Failed to load %s\n", mod);
91	raise "fail: module";
92	exit;
93}
94
95toint(opt, s: string, min, max: int): int
96{
97	if (len s == 0 || str->take(s, "[0-9]+-") != s)
98		fatal(sys->sprint("no value specified for option %s", opt));
99	v := int s;
100	if (v < min)
101		fatal(sys->sprint("option %s value is less than minimum of %d: %d", opt, v, min));
102	if (max != -1 && v > max)
103		fatal(sys->sprint("option %s value is greater than maximum of %d: %d", opt, v, max));
104	return v;
105}
106
107replay(dir: string)
108{
109	sl := linelist(dir+"/"+SUMFILE);
110	if (sl == nil) {
111		sys->fprint(stderr, "No summary file in %s\n", dir);
112		return;
113	}
114	sline := hd sl;
115	(n, toks) := sys->tokenize(sline, " ");
116	if (n < 4) {
117		sys->fprint(stderr, "Bad summary file in %s\n", dir);
118		return;
119	}
120	when := int hd toks;
121	toks = tl toks;
122	elapsed := int hd toks;
123	toks = tl toks;
124	cflag := int hd toks;
125	toks = tl toks;
126	testspec := hd toks;
127	mreport(1, when, 0, 2, sys->sprint("Processing %s: test %s ran in %dms with cflag=%d\n", dir, testspec, elapsed, cflag));
128	replay_msgs(dir+"/"+MSGFILE, testspec, cflag);
129	if (display_stdout) {
130		mreport(2, 0, 0, 0, "Stdout from test:");
131		display_file(dir+"/stdout");
132	}
133	if (display_stderr) {
134		mreport(2, 0, 0, 0, "Stderr from test:");
135		display_file(dir+"/stderr");
136	}
137}
138
139
140replay_msgs(mfile: string, tspec: string, cflag: int)
141{
142	mf := bufio->open(mfile, Bufio->OREAD);
143	if (mf == nil)
144		return;
145	(nwarns, nerrors, nfatals) := (0, 0, 0);
146	stime := 0;
147
148	while ((line := mf.gets('\n')) != nil) {
149		(whens, rest) := str->splitl(line, ":");
150		when := int whens;
151		msg := rest[1:];
152		sev := int msg[0:1];
153		verb := int msg[1:2];
154		body := msg[2:];
155		if (sev == S_STIME) {
156			stime = int body;
157			mreport(2, when, 0, 3, sys->sprint("Starting test %s cflag=%d", tspec, cflag));
158		}
159		else if (sev == S_ETIME) {
160			uetime := int body;
161			elapsed := uetime-stime;
162			errsum := sys->sprint("WRN:%d ERR:%d FTL:%d", nwarns, nerrors, nfatals);
163			mreport(2, when+(int body-stime)/1000, 0, 3, sys->sprint("Finished test %s after %dms - %s", tspec, elapsed, errsum));
164		}
165		else {
166			if (sev == S_WARN) {
167				nwarns++;
168			}
169			else if (sev == S_ERROR) {
170				nerrors++;
171			}
172			else if (sev == S_FATAL) {
173				nfatals++;
174			}
175			mreport(3, when, sev, verb, sys->sprint("%s: %s", severs(sev), body));
176		}
177	}
178}
179
180linelist(file: string): list of string
181{
182	bf := bufio->open(file, Bufio->OREAD);
183	if (bf == nil)
184		return nil;
185	cl : list of string;
186	while ((line := bf.gets('\n')) != nil) {
187		if (line[len line -1] == '\n')
188			line = line[:len line - 1];
189		cl = line :: cl;
190	}
191	bf = nil;
192	return cl;
193}
194
195display_file(file: string)
196{
197	bf := bufio->open(file, Bufio->OREAD);
198	if (bf == nil)
199		return;
200	while ((line := bf.gets('\n')) != nil) {
201		sys->print("                    %s", line);
202	}
203}
204
205
206severs(sevs: int): string
207{
208	SEVMAP :=  array[] of {"INF", "WRN", "ERR", "FTL"};
209	if (sevs >= len SEVMAP)
210		sstr := "UNK";
211	else
212		sstr = SEVMAP[sevs];
213	return sstr;
214}
215
216
217mreport(indent: int, when: int, sev: int, verb: int, msg: string)
218{
219	time := "";
220	if (when) {
221		tm := daytime->local(when);
222		time = sys->sprint("%4d%02d%02d %02d:%02d:%02d", tm.year+1900, tm.mon-1, tm.mday, tm.hour, tm.min, tm.sec);
223	}
224	pad := "---"[:indent];
225	term := "";
226	if (len msg && msg[len msg-1] != '\n')
227		term = "\n";
228	if (sev || verb <= verbosity)
229		sys->print("%-17s %s%s%s", time, pad, msg, term);
230}
231