-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsalmonella-log-parser.scm
326 lines (271 loc) · 9.9 KB
/
salmonella-log-parser.scm
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
(module salmonella-log-parser
(;; Exported API
read-log-file log-eggs log-skipped-eggs status-zero?
;; fetch
fetch-status fetch-message fetch-duration
;; install
install-status install-message install-duration
;; check-version
check-version-status check-version-message egg-version check-version-ok?
;; test
test-status test-message test-duration has-test?
;; meta-data
meta-data egg-dependencies egg-license
;; doc
doc-exists?
;; start & end
start-time salmonella-info end-time total-time
;; statistics
count-install-ok count-install-fail count-test-ok count-test-fail
count-no-test count-total-eggs count-documented count-undocumented
;; misc
prettify-time sort-eggs log-version anything-failed?
;; low level stuff
log-get
)
(import scheme)
(cond-expand
(chicken-4
(import chicken)
(use srfi-1 data-structures extras)
(use salmonella)
(define read-list read-file))
((or chicken-5 chicken-6)
(import (chicken base)
(chicken io)
(chicken file)
(chicken fixnum)
(chicken format)
(chicken process-context)
(chicken random)
(chicken sort)
(chicken string))
(import salmonella)
(include "libs/srfi-1.scm"))
(else
(error "Unsupported CHICKEN version.")))
(include "salmonella-common.scm")
(define (status-zero? status)
(and status (zero? status)))
(define (get-by-egg/action egg action log)
(find (lambda (entry)
(and (eq? (report-egg entry) egg)
(eq? (report-action entry) action)))
log))
(define (log-version-0? log)
;; Log files emitted by salmonella 1.x had salmonella-info as a
;; string as the first entry
(string? (car log)))
(define (read-log-file log-file)
(let ((entries (with-input-from-file log-file read-list)))
;; Ugly hack to avoid breaking on old log files. We don't actually
;; support parsing old logs at the moment -- just avoid crashing.
(if (log-version-0? entries)
entries
(map (lambda (entry)
(apply make-report entry))
entries))))
(define (log-get egg action getter log)
(and-let* ((log-line (get-by-egg/action egg action log)))
(getter log-line)))
(define (log-eggs log)
;; Return a list of eggs from `log' that actually had the
;; installation tested (i.e., the ones given as inputs to
;; salmonella).
(let loop ((log log)
(eggs '()))
(if (null? log)
eggs
(let* ((report (car log))
(egg (report-egg report))
(action (report-action report)))
(loop (cdr log)
(if (or (not (symbol? egg))
(memq egg eggs)
(not (eq? action 'install)))
eggs
(cons egg eggs)))))))
(define (log-skipped-eggs log)
;; Return a list of skipped eggs from `log'
(let loop ((log log)
(eggs '()))
(if (null? log)
eggs
(let* ((report (car log))
(egg (report-egg report))
(action (report-action report)))
(loop (cdr log)
(if (and (symbol? egg)
(not (memq egg eggs))
(eq? action 'skip))
(cons egg eggs)
eggs))))))
;; fetch
(define (fetch-status egg log) (log-get egg 'fetch report-status log))
(define (fetch-message egg log) (log-get egg 'fetch report-message log))
(define (fetch-duration egg log) (log-get egg 'fetch report-duration log))
;; install
(define (install-status egg log) (log-get egg 'install report-status log))
(define (install-message egg log) (log-get egg 'install report-message log))
(define (install-duration egg log) (log-get egg 'install report-duration log))
;; check-version
(define (check-version-status egg log) (log-get egg 'check-version report-status log))
(define (check-version-message egg log) (log-get egg 'check-version report-message log))
(define (egg-version egg log) (log-get egg 'check-version report-duration log))
(define (check-version-ok? egg log)
(let ((status (check-version-status egg log)))
(or (status-zero? status) (= status -1))))
;; test
(define (test-status egg log) (log-get egg 'test report-status log))
(define (test-message egg log) (log-get egg 'test report-message log))
(define (test-duration egg log) (log-get egg 'test report-duration log))
(define (has-test? egg log)
(let ((status (test-status egg log)))
(and status (not (= status -1)))))
;; meta-data
(define (meta-data egg log) (log-get egg 'meta-data report-message log))
(define (egg-dependencies egg log #!key with-test-dependencies? with-versions?)
;; Make sure to call this procedure giving proper eggs as arguments.
;; Core libraries, for example, don't have metadata (.meta) and will
;; make egg-dependencies raise an error.
(let ((data (meta-data egg log)))
(if data
(get-egg-dependencies data
with-test-dependencies?: with-test-dependencies?
with-versions?: with-versions?)
(error 'egg-dependencies
(sprintf "No metadata for ~a" egg)))))
(define (egg-license egg log)
(let ((data (meta-data egg log)))
(and-let* ((data)
(license (alist-ref 'license data)))
(car license))))
;; doc
(define (doc-exists? egg log)
(status-zero? (log-get egg 'check-doc report-status log)))
;; log version
;; Version 0 (emitted by salmonella 1.x)
;;
;; Version 1 (emitted by salmonellas 2.0 - 2.7)
;;
;; Version 2 (emitted by salmonellas 2.8 - <current version>):
;; * same format as log version 1's, but with version information
;; -- `log-version' action.
;;
;; Version 3 (emitted by salmonellas 2.8 - <current version>):
;; * test-egg produces multiple reports, as it fetches and installs
;; test dependencies, besides testing eggs. Actions for fetch and
;; install of test dependencies are lists whose first element is
;; either fetch-test-dep or install-test-dep and the second
;; element is the egg being tested (not the dependency!).
(define (log-version log)
(if (log-version-0? log)
0
(let loop ((log log))
(if (null? log)
1
(let ((report (car log)))
(if (eq? 'log-version (report-action report))
(report-message report)
(loop (cdr log))))))))
;; start & end
(define (start-report log)
(let loop ((log log))
(if (null? log)
(error 'start-report "Could not determine start report entry.")
(let ((current-report (car log)))
(if (eq? 'start (report-action current-report))
current-report
(loop (cdr log)))))))
(define (start-time log)
(report-duration (start-report log)))
(define (salmonella-info log)
(report-message (start-report log)))
(define (end-time log)
(let ((last-record (last log)))
(unless (eq? (report-action last-record) 'end)
(error 'end-time
"Corrupted log file: action of last record is not `end'"))
(report-duration last-record)))
(define (total-time log)
(- (end-time log) (start-time log)))
;; statistics
(define (count-install-ok log)
(count (lambda (egg)
(status-zero? (install-status egg log)))
(log-eggs log)))
(define (count-install-fail log)
(- (count-total-eggs log) (count-install-ok log)))
(define (count-test-ok log)
(count (lambda (entry)
(and (eq? 'test (report-action entry))
(status-zero? (report-status entry))))
log))
(define (count-test-fail log)
(count (lambda (entry)
(and (eq? 'test (report-action entry))
(> (report-status entry) 0)))
log))
(define (count-no-test log)
(count (lambda (entry)
(and (eq? 'test (report-action entry))
(< (report-status entry) 0)))
log))
(define (count-total-eggs log #!key with-skipped?)
(+ (length (log-eggs log))
(if with-skipped?
(length (log-skipped-eggs log))
0)))
(define (count-documented log)
(count (lambda (entry)
(and (eq? 'check-doc (report-action entry))
(status-zero? (report-status entry))))
log))
(define (count-undocumented log)
(count (lambda (entry)
(and (eq? 'check-doc (report-action entry))
(not (status-zero? (report-status entry)))))
log))
;; Misc
(define (prettify-time seconds)
(define (pretty-time seconds)
(cond ((zero? seconds)
"")
((< seconds 60)
(conc seconds "s"))
((< seconds 3600)
(let ((mins (quotient seconds 60)))
(conc mins "m" (pretty-time (- seconds (* 60 mins))))))
(else
(let ((hours (quotient seconds 3600)))
(conc hours "h" (pretty-time (- seconds (* 3600 hours))))))))
(if (zero? seconds)
"0s"
(let ((pretty (pretty-time (abs (inexact->exact seconds)))))
(if (negative? seconds)
(string-append "-" pretty)
pretty))))
(define (sort-eggs eggs)
(sort eggs (lambda (e1 e2)
(string<? (symbol->string e1)
(symbol->string e2)))))
(define (anything-failed? log-file)
(let ((log-data (read-log-file log-file)))
(let loop ((log-entries log-data))
(if (null? log-entries)
#f
(let* ((log-entry (car log-entries))
(action (report-action log-entry))
(status (report-status log-entry)))
(if (memq action '(fetch install test check-doc))
(if (or (fx= status 0) (fx= status -1))
(loop (cdr log-entries))
#t)
(if (and (memq action '(check-author
check-license
check-dependencies
check-category))
(not status))
#t
(loop (cdr log-entries)))))))))
) ;; end module