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